From 23290dc16e0a8806fdbf7ddfb0cee32a0d7fc030 Mon Sep 17 00:00:00 2001 From: HackTricks News Bot Date: Thu, 15 Jan 2026 18:40:19 +0000 Subject: [PATCH] =?UTF-8?q?Add=20content=20from:=20Pixel=200-click:=20Part?= =?UTF-8?q?=201=20=E2=80=94=20Exploiting=20CVE-2025-54957=20in=20the=20Dol?= =?UTF-8?q?...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../integer-overflow-and-underflow.md | 29 ++++++++++++++++++- ...g-android-media-pipelines-image-parsers.md | 24 +++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/binary-exploitation/integer-overflow-and-underflow.md b/src/binary-exploitation/integer-overflow-and-underflow.md index a0a8b95936f..e2ca6ce60a1 100644 --- a/src/binary-exploitation/integer-overflow-and-underflow.md +++ b/src/binary-exploitation/integer-overflow-and-underflow.md @@ -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 @@ -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}} diff --git a/src/mobile-pentesting/android-app-pentesting/abusing-android-media-pipelines-image-parsers.md b/src/mobile-pentesting/android-app-pentesting/abusing-android-media-pipelines-image-parsers.md index da957d08ff8..7c36eb6f026 100644 --- a/src/mobile-pentesting/android-app-pentesting/abusing-android-media-pipelines-image-parsers.md +++ b/src/mobile-pentesting/android-app-pentesting/abusing-android-media-pipelines-image-parsers.md @@ -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. @@ -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}}