Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/binary-exploitation/integer-overflow-and-underflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,33 @@ clang -O0 -Wall -Wextra -std=c11 -D_FORTIFY_SOURCE=0 \
-o int_underflow_heap int_underflow_heap.c
```

### Other Examples
### Allocator alignment rounding wrap → undersized chunk → heap overflow (Dolby UDC case)

Some custom allocators round allocations up to alignment without re-checking for overflow. In the Dolby Unified Decoder (Pixel 9, CVE-2025-54957), attacker-controlled `emdf_payload_size` (decoded with an unbounded `variable_bits(8)` loop) is fed into `ddp_udc_int_evo_malloc`:

```c
size_t total_size = alloc_size + extra;
if (alloc_size + extra < alloc_size) return 0; // initial wrap guard
if (total_size % 8)
total_size += (8 - total_size) % total_size; // vulnerable rounding
if (total_size > heap->remaining) return 0;
```

For 64-bit values near `0xFFFFFFFFFFFFFFF9`, `(8 - total_size) % total_size` wraps the addition and produces a **tiny `total_size`** even though the logical `alloc_size` remains huge. The caller later writes `payload_length` bytes into the returned chunk:

```c
buffer = ddp_udc_int_evo_malloc(evo_heap, payload_length, extra);
for (size_t i = 0; i < payload_length; i++) { // bounds use logical size
buffer[i] = next_byte_from_emdf(); // writes past tiny chunk
}
```

Why exploitation is reliable in this pattern:
- **Overflow length control:** Bytes are sourced from a reader capped by another attacker-chosen length (`emdf_container_length`), so the write stops after N bytes instead of spraying `payload_length`.
- **Overflow data control:** Bytes written past the chunk are fully attacker-supplied from the EMDF payload.
- **Heap determinism:** The allocator is a per-frame bump-pointer slab with no frees, so adjacency of corrupted objects is predictable.

## Other Examples

- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
- Only 1B is used to store the size of the password so it's possible to overflow it and make it think it's length of 4 while it actually is 260 to bypass the length check protection
Expand Down Expand Up @@ -416,5 +442,6 @@ This **doesn't change in ARM64** as you can see in [**this blog post**](https://

- [Detect Go’s silent arithmetic bugs with go-panikint](https://blog.trailofbits.com/2025/12/31/detect-gos-silent-arithmetic-bugs-with-go-panikint/)
- [go-panikint (compiler fork)](https://github.com/trailofbits/go-panikint)
- [Pixel 0-click – CVE-2025-54957 allocator wrap → heap overflow](https://projectzero.google/2026/01/pixel-0-click-part-1.html)

{{#include ../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,29 @@ Opcode List 1 : [opcode 23], [opcode 23], ...
- Delivery relies on system media re-parsing (not the chat client) and thus inherits that process' permissions (full read/write access to the gallery, ability to drop new media, etc.).
- Any image parser reachable through `MediaStore` (vision widgets, wallpapers, AI résumé features, etc.) becomes remotely reachable if the attacker can convince a target to save media.

## 0-click DD+/EAC-3 decoding path (Google Messages ➜ mediacodec sandbox)

Modern messaging stacks also auto-decode *audio* for transcription/search. On Pixel 9, **Google Messages** will hand incoming RCS/SMS audio to the **Dolby Unified Decoder (UDC)** inside `/vendor/lib64/libcodec2_soft_ddpdec.so` **before** the user opens the message, expanding the 0-click surface to media codecs.

**Key parse constraints**
- Each DD+ syncframe has up to 6 blocks; each block can copy up to `0x1FF` bytes of attacker-controlled *skip data* into a skip buffer (≈ `0x1FF * 6` bytes per frame).
- The skip buffer is scanned for **EMDF**: `syncword (0xX8)` + `emdf_container_length` (16b) + variable-length fields. `emdf_payload_size` is parsed with an unbounded `variable_bits(8)` loop.
- EMDF payload bytes are allocated inside a custom per-frame **“evo heap”** bump allocator and then copied byte-by-byte from a bit-reader bounded by `emdf_container_length`.

**Integer-overflow → heap-overflow primitive (CVE-2025-54957)**
- `ddp_udc_int_evo_malloc` aligns `alloc_size+extra` to 8 bytes via `total_size += (8 - total_size) % total_size` **without wrap detection**. Values near `0xFFFFFFFFFFFFFFF9..FF` shrink to tiny `total_size` on AArch64.
- The copy loop still uses the *logical* `payload_length` from `emdf_payload_size`, so attacker bytes overwrite evo-heap data past the undersized chunk.
- Overflow length is precisely capped by attacker-chosen `emdf_container_length`; overflow bytes are attacker-controlled EMDF payload data. The slab allocator is reset every syncframe, giving predictable adjacency.

**Secondary read primitive**
If `emdf_container_length > skipl`, EMDF parsing reads past initialized skip bytes (OOB read). Alone it leaks zeros/known media, but after corrupting adjacent heap metadata it can read back the corrupted region to validate the exploit.

**Exploitation recipe**
1. Craft EMDF with huge `emdf_payload_size` (via `variable_bits(8)`) so allocator padding wraps into a small chunk.
2. Set `emdf_container_length` to the desired overflow length (≤ total skip data budget); place overflow bytes in the EMDF payload.
3. Shape the per-frame evo heap so the small allocation sits before target structures inside the decoder’s static buffer (≈693 KB) or dynamic buffer (≈86 KB) allocated once per decoder instance.
4. Optionally choose `emdf_container_length > skipl` to read back overwritten data from the skip buffer after corruption.

## Quram's DNG Opcode Interpreter Bugs

DNG files embed three opcode lists applied at different decode stages. Quram copies Adobe's API, but its Stage-3 handler for `DeltaPerColumn` (opcode ID 11) trusts attacker-supplied plane bounds.
Expand Down Expand Up @@ -74,5 +97,6 @@ Two payload families exist: one tuned for jemalloc, another for scudo. They diff
## References

- [Project Zero – A look at an Android ITW DNG exploit](https://projectzero.google/2025/12/android-itw-dng.html)
- [Project Zero – Pixel 0-click: CVE-2025-54957 in Dolby UDC](https://projectzero.google/2026/01/pixel-0-click-part-1.html)

{{#include ../../banners/hacktricks-training.md}}