ღ Miranda

开启IE的上帝模式

前言

事先要说明,这篇文章里的方法是在能够修改对象一字节的情况下获得任意地址读写后的,修改一字节可以使用uaf等漏洞,这里调试时可以手动修改。

执行系统程序

可以通过下面的脚本让网页运行计算器:

加载后会有弹窗确认,确认后就会弹出计算器,而开启上帝模式就是在不弹窗提示的情况下直接执行calc.exe程序。

调试分析

首先需要找到弹窗对应的函数,这个弹窗实际上是调用了user32.dll中的CreateWindowEx,用windbg在这个函数的asciiunicode版本上分别下断点:

查看栈回溯,发现了三个可能与ActiveXObject运行有关的函数:

似乎jscript9!ScriptEngine::CanObjectRun+0x78决定了控件是否能够运行,由jscript9!ScriptSite::CreateActiveXObject创建控件。

jscript9!ScriptSite::CreateActiveXObjectjscript9!ScriptEngine::CanObjectRun下断点,然后刷新页面,断在了第一个断点,再运行,就断在了CanObjectRun函数内,单步执行到这里,调用了一个虚表里的函数:

这个函数中就调用了CreateWindowExW,看来就是触发弹窗的位置,如果点击是,那么CanObjectRun会返回1:

点击否就会返回0,现在可以确认弹窗的函数是s_apfnPlainTearoff对象虚表偏移0x14处的函数,虚表在mshtml模块基地址偏移0x00c67870处,看调用弹窗函数后CanObjectRun是怎么返回的:

确定返回值的是sete al这条指令,sete指令根据zf寄存器的值确定设置al的值为0或1,应该是点击是或否设置了zf寄存器,对比一下两种选择:

通过调试发现在调用s_apfnPlainTearoff虚表函数时eax的值不为0,那么我们可以通过修改虚表使CanObjectRun直接返回,修改虚表偏移0x14631abb5cleave的地址就可以直接返回,偏移jscript9基地址为0x000dbb5c。通过任意地址读写可以实现修改虚表,可以这样实现:

看到虚表已经被改写:

不会有任何弹窗提示直接弹出计算器。

执行任意代码

上面的方法只可以执行系统里的可执行文件,那么如何执行任意代码呢,可以通过ADODB.Stream写文件,那么我们可以把要执行的可执行文件经过base64编码后用下面的脚本写到文件中然后执行文件:

直接执行会报错:

这是因为微软默认禁用了ADODB.Stream对象,无法创建,在jscript9!ScriptSite::CreateObjectFromProgID函数上下断点,单步跟踪:

可以知道jscript9!ScriptEngine::CanCreateObject返回值决定了是否还会调用后面的CanObjectRun函数,当返回0时ScriptSite::CreateObjectFromProgID直接就返回了,不会创建对象,那么只要想办法在返回后修改eax的值不为0即可,经过试验,直接用上面的脚本在CanCreateObject返回后修改eax并不能成功,还是要结合任意地址读写开启上帝模式,脚本如下:

alert("1");弹窗后断下修改两次CanCreateObject的返回值最后能成功弹出计算器。

修改虚表

单步跟踪CanCreateObject,看看到底是怎么样确定返回值的,通过比较WScript.shellADODB.Stream的创建过程:

可以知道通过MSHTML!TearoffThunk4这个虚函数的返回值确定CanCreateObject的返回值,这个虚函数同样是之前s_apfnPlainTearoff对象虚表中的函数,偏移为0x10,改写为CanCreateObjectleave ret,偏移为0xdb82c,调试可以看到成功改写虚表:

但是改写后会失败并且引发异常,并不能到CanObjectRun这个函数处:

原因是64bab72c处的edi不为0,导致了跳转,所以在返回后还需要保证edi为0才行。

这时候需要用到rop,再看CanCreateObject函数,可以看到64bab803处把虚表指针赋值给了ecx,然后调用了偏移0x10处的虚函数,eax就是对象的地址。:

如果可以改写eax的值,指向我们构造的对象,然后伪造一个虚表,然后就可以利用rop改写edi为0,伪造的虚表:

伪造的对象:

可以在windbg中用mona插件寻找这些指令:

实现上述思路的代码如下:

pp_obj是指向对象的指针,只要改写了这里,也就是控制了上面的eax,那么就可以使用伪造的对象进行rop了。接下来需要寻找eax的来源:

经过调试发现在ScriptEngine::GetSiteHostSecurityManagerNoRef中修改了[ebp-4],然后在后面赋值给了eax

跟踪这个对象的获取过程:

总结如下:

通过调试可以知道arg_0就是JavascriptActiveX对象的地址:

验证我们的猜测,下两个端点,分别在给obj赋值时和JavascriptActiveXObject::NewInstance返回后:

new ActiveXObject("WScript.shell");创建对象调试:

所以我们可以得到结论,可以用我们创建的对象地址找到最后赋值给obj的地址,当然也可以改写这个地址,改写我们之前的GodOnGodOff函数。

修改后脚本:

成功弹出计算器,但最后还需要解决一个问题,就是不同域的问题。

跨域问题

之前的测试都是在本地访问html文件,而当试图访问另一台服务器上的这个文件时,当所有步骤执行成功后会报错:

通过下alert断点,定位到产生这个异常的代码:

ADODB.Stream有关的两个库是msado15.dllmsader15.dll,看看与SaveToFile有关的函数:

在第一个函数上下断点,断下后esi指向了对象:

断下后单步到msado15!SecurityCheck处:

这个函数有两个参数,msado15!SecurityCheck检查这两个路径是否在同域下,尝试修改eax的值为C:\:

这次没有报错直接弹出计算器。

追踪eax的来源:

eax来自于CStream::SaveToFile的第一个参数,调试可以看到就是ATL::CComObject<CStream>对象:

可以推测,esi就是bStream对象,使用get_addr得到bStream地址:

然后到CStream::SaveToFile函数处

这里esi0e43b328,可以看到在bStream偏移0x50的地方有这个地址,可以验证:

只要修改这个字符串即可,实现如下:

最终脚本:

Modify array length弹窗后修改数组长度然后就可以弹出计算器。

发表评论

电子邮件地址不会被公开。