关联漏洞
描述
Write Up & Exploitation For CVE-2021-38003
介绍
# CVE-2021-38003
This analysis documents my research into CVE-2021-38003, a vulnerability in V8’s `Map` object handling, using d8 9.5.172.21 on an ARM64 Ubuntu VM.
My approach involves testing a reproducer, analyzing crashes with GDB, examining V8 source code, and refining the proof-of-concept (PoC) to try to achieve RCE.
## Reproducing the Vulnerability
### Basic System Environment & Setup
- OS: Ubuntu 22.04 ARM 64
- V8: 9.5.172.21
<img width="919" alt="vulnerable_version" src="https://github.com/user-attachments/assets/51d62a83-601f-4540-a632-884db00671d8" />
I began by running the provided PoC (`poc.js`) in d8 to confirm the vulnerability in version 9.5.172.21, known to be affected by CVE-2021-38003.
<img width="1426" alt="initial_poc_running" src="https://github.com/user-attachments/assets/bc736142-a3ed-4cb1-98ac-d60116fe2ddb" />
The output verified the V8 version and revealed a crash in `ordered-hash-table.cc` at line 290, where a debug check failed: `table->NumberOfDeletedElements() == removed_holes_index (2 vs. 1)`. This crash, occurring in `Runtime_MapShrink`, confirmed the PoC’s effectiveness.
The PoC manipulates a JavaScript `Map` by inserting a “hole” value with `%TheHole()`, deleting it multiple times next to another key, and iterating `0x3000` times to stress the heap. A garbage collection call (`gc()`) risks freeing referenced memory, and a `map1.set(foo_arr, 0xffff)` operation triggers resizing, exposing the bug. The `%DebugPrint(foo_arr)` call checks `foo_arr`’s state for corruption. The mismatch in deleted elements suggests heap corruption, as V8 processes an invalid `OrderedHashMap`, a structure for storing `Map` key-value pairs. In a release build, absent debug checks, this could enable exploitable memory errors, supporting possible RCE efforts.
This step validated the PoC, laying the beginning for possible RCE exploration and codebase navigation.
## Debugging with GDB
To investigate the crash, I used GDB to examine the `OrderedHashMap` state at the point of failure:
<img width="1444" alt="initial_gdb_debug" src="https://github.com/user-attachments/assets/04e95713-086c-45c7-853a-9da117db0591" />
<img width="1000" alt="initial_gdb_debug" src="https://github.com/user-attachments/assets/40d8dee2-6a3c-4572-8f39-77d6e9842e75" />
Execution halted at the `DCHECK` failure, with `NumberOfDeletedElements()` at 2 and `removed_holes_index` at 1, confirming the inconsistency. The `OrderedHashMap` object, with a pointer value of 12678878763661, was valid but corrupted. The stack held valid addresses, indicating heap-based corruption, and `x0` was null, as `table` was stack-passed. The backtrace connected `Runtime_MapShrink` to `OrderedHashTable::Shrink` and `OrderedHashMap::Rehash`, showing the PoC’s `set` operations triggered a `Map` resize.
The `OrderedHashMap`’s corrupted state, driven by `delete %TheHole()` and garbage collection, pointed to potential type confusion or memory writes, key for RCE. The backtrace also mapped JavaScript to C++ functions in `runtime-collections.cc` and `ordered-hash-table.cc`, facilitating codebase navigation.
## Exploring V8’s Source Code
I analyzed `ordered-hash-table.cc` and `runtime-collections.cc` to identify the bug’s root cause:
- ordered-hash-table.cc
<img width="964" alt="Screenshot 2025-05-19 at 16 49 05" src="https://github.com/user-attachments/assets/6b69587f-e4a7-470d-8694-044a4416675b" />
- runtime-collections.css
<img width="917" alt="Screenshot 2025-05-19 at 16 52 31" src="https://github.com/user-attachments/assets/b7c5b9e6-b8af-4156-9684-c2130e2fb6a8" />
In `ordered-hash-table.cc`, `OrderedHashTable::Rehash` iterates `Map` entries, tracking deleted elements with `removed_holes_index`. The `DCHECK` at line 290 fails when `NumberOfDeletedElements()` (2) exceeds `removed_holes_index` (1). `Runtime_MapShrink` in `runtime-collections.cc` initiates rehashing during resizing.
The PoC’s sequence—`m.set(%TheHole(), 1); m.delete(%TheHole()); m.delete(%TheHole())`—creates a `Map` with two deleted entries but one hole counted, corrupting the `OrderedHashMap`. Garbage collection and heap stress amplify this, risking out-of-bounds writes or type confusion in a release build. This analysis confirmed the bug’s exploitability and demonstrated my ability to trace JavaScript operations to C++ functions.
## Refining the PoC for Possible RCE
### First PoC Refinement
I made `exploit_attempt1.js` to spray the heap with 5,000 `ArrayBuffer` objects, including a crafted `ArrayBuffer` whose `DataView` set a pointer to `0x4141414141414141`, aiming to plant a fake object exploitable via `OrderedHashMap` corruption. To induce type confusion, I treated `foo_arr`, a floating-point array, as an `ArrayBuffer` through a `DataView`, seeking invalid memory access. A `map1.set(foo_arr, 0xffff)` call stressed the `OrderedHashMap` to trigger resizing errors.
<img width="964" alt="Screenshot 2025-05-19 at 16 49 05" src="https://github.com/user-attachments/assets/414d0d66-0139-4b86-acec-63ba90405f2e" />
The PoC triggered a `DCHECK` failure at `ordered-hash-table.cc:290`, where `table->NumberOfDeletedElements()` (2) mismatched `removed_holes_index` (1). The d8 crash reported a fatal error in `Runtime_MapShrink`, with a stack trace through `OrderedHashTable::Shrink` and `OrderedHashMap::Rehash`. GDB revealed no stack or register corruption, as the debug check halted execution before `DataView` operations. This highlighted the debug build’s protective assertions but confirmed the PoC’s potential to disrupt V8’s heap, a step toward RCE in a release build.
### Second PoC Attempt: Experimental `DCHECK` Bypass
I made `exploit_attempt2.js`To reveal the corruption’s full impact, I commented out the `DCHECK` in `ordered-hash-table.cc:290`, **recognizing that source modification isn’t viable in real-world exploits**. This experiment mimicked a release build, where `DCHECK`s are absent, allowing the corruption to propagate.
I modified the source, rebuilt d8 after resolving a build directory issue, and ran the PoC:
<img width="964" alt="Screenshot 2025-05-19 at 16 49 05" src="https://github.com/user-attachments/assets/0ec8fccf-9baa-4df5-a096-c3096b8d88ec" />
The result was a new crash in `builtins-collections-gen.cc:790`, where a `CSA_ASSERT` failed during `m.delete(1)` in the `getmap` function’s loop (0x4000 iterations). The assertion, checking an entry’s index against the `Map`’s element counts, failed due to the corrupted `OrderedHashMap` from `delete %TheHole()` calls. The heap, sprayed with 20,001 objects including a fake pointer (`0x4141414141414141`), was stressed by `map1.set` operations, but the crash preceded the `DataView` type confusion attempt.
This crash marks significant progress toward RCE. The corruption’s impact on V8’s optimized `Map.delete` builtin suggests potential for out-of-bounds access or type confusion in a release build, where the `CSA_ASSERT` would be absent. The early crash limited the `DataView`’s role, but the heap spraying’s effectiveness positions the PoC for further escalation with minimal tweaks, such as adjusting loop iterations or testing in a release environment.
**Limitations**: The `DCHECK` bypass, while insightful, **deviates from real-world exploit constraints, a choice I made just for experimentation**.
## Conclusion
My analysis of CVE-2021-38003 demonstrated the vulnerability’s heap corruption potential and advanced toward RCE through systematic PoC refinements. I reproduced the bug, pinpointed its cause in `OrderedHashMap`’s handling of `delete %TheHole()`, and navigated V8’s codebase to trace JavaScript to C++ functions, addressing the second screening question. Three PoC iterations, culminating in a `CSA_ASSERT` crash after an experimental `DCHECK` bypass, showed progress toward RCE, meeting the first question’s challenge despite debug build limitations. The corruption’s impact on optimized builtins underscores its exploitability in production environments.
文件快照
[4.0K] /data/pocs/b9ef8d308df31ef9d9d9b692a5b516294fecee1f
├── [ 852] exploit_attempt1.js
├── [1.2K] exploit_attempt2.js
├── [ 377] poc.js
└── [7.9K] README.md
0 directories, 4 files
备注
1. 建议优先通过来源进行访问。
2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。