ღ Miranda

IE:从一字节改写到全地址读写

前言

在浏览器的漏洞利用中,通过uaf漏洞能够改写一字节,这时可以利用这篇文章的方法实现任意地址读写,测试环境是win7 32bit sp1IE10

对象堆喷射

这种方法中通过两次对象的喷射实现地址预测。

首先是第一个对象喷射:

目的是把一个ArrayBuffer的缓冲空间放在LargeHeapBlock之间:

为了追踪内存布局,我们要找到ArrayBuffer对象的地址,在jscript9!Js::JavascriptArrayBuffer::Create下断点,断下后返回:

eax的值02426dc0就是ArrayBuffer对象的地址:

+0x10处是缓冲区地址,也就是0203c8c0,这段地址确实在堆上,并且大小为0x58:

定位到这段内存,发现前后都是LargeHeapBlock对象:

接下来是第二次,脚本如下:

这次需要三个断点,在第一个弹窗时下断点:

这里获得了第一次喷射中ArrayBuffer对象信息,布置的缓冲区地址为087cc3c0

然后继续,当第二个弹窗出现时,下另外两个断点:

当第一次断在断点1时,esi存放了Array对象的地址:

这里得到Array对象地址092b3ce0,数组地址093b1010,看到现在数组里还没有元素,但长度是我们设置的00003bf8,然后断在断点2时:

得到Int32Array对象的地址092b70f0,断下三次后:

每个对象偏移0x18是数组大小,也就是ArrayBuffer的缓冲区0x58/4=0x16,偏移0x1c是我们第一次喷射得到的0x58 bytes的缓冲区地址,现在Array对象指向的数组:

填入了三个Int32Array的地址。至于Array[0]处的092b70c0,是在创建Array对象之前构造的,不知道是什么原因。

第二次喷射中每块的大小可以这么计算:

Array在内存中是对齐的,所以每次实际喷射了0x10000 bytes

喷射完后查看预测地址0c0a0000:

可以在偏移0x3bf8*4处找到Int32Array对象:

喷射布局:

改写一字节

假设我们通过某个漏洞能够修改指定地址的一字节值,那么如果修改了0c0af01b的一字节,假设改为了20,那么数组长度就会变成20000016,那么就可以读写02038678往后的20000016*4字节的空间,调试的时候选择在Second Done弹窗后手动修改0c0af018处的值为20000016

修改完后可以使用下面的代码找到我们修改的对象:

由于我们喷射的ArrayBuffer的空间是处于LargeHeapBlock之间的,所以首先可以获取LargeHeapBlock对象的虚表地址,这样就可以确定模块基地址,我们还知道LargeHeapBlock对象是链表的形式在内存中,所以可以通过链表指针来验证ArrayBuffer的位置是否正确,每个LargeHeapBlock对象偏移0x24处指针指向下一个对象:

这样也可以验证我们的喷射是否成功,代码如下:

经过几次页面的刷新,最终得到了buf_addr的地址01eb44b0,在调试器里验证与之一致:

任意地址读写

下一步需要改写0c0af01c处的ArrayBuffer地址为0,这样就可以实现全地址空间读写,目前脚本如下:

改写后可以读写全地址空间,但读写地址时需要是4的倍数,需要实现读写函数解决地址不是4倍数的情况:

泄露对象地址

为了确定模块的基地址,还需要能够得到任意对象的地址,这里利用到了Array数组,把一个对象赋给数组的最后一个元素,然后通过读地址读出对象的地址。具体实现如下:

首先把每个Array的最后一个元素置0,然后把0x0c0a0000处的数组最后一个元素置为3,然后找到这个数组,把对象的引用赋值给数组最后一个元素,再用read函数读出来。比如可以这样确定jscript9mshtml的基地址:

jscript9的地址可以通过Int32Array的虚表计算:

先通过数组,先看看div对象:

得到的div对象:

偏移0x10处是CBaseTypeOperations::CBaseFinalizer对象,可以用这个来计算mshtml的基地址:

综合如下:

得到结果:

与实际结果一致:

总结

脚本总结如下:

这是通用的方法,稍加修改就可以放在exp中实现任意地址的读写。

发表评论

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