AI-powered features have added 0-click attack surfaces to mobile phones, such as SMS, RCS, and more. Because audio decoders are now phone zero-click targets, the P0 decided to investigate. One such format they decided to look into was Dolby Digital, including AC-3 and EAC-3.
While reviewing the audio format specification, they noticed an apparent problem: no limit was specified for the emdf_payload_size parameter. Ivan Fratric found that copying the data from this content into the heap contained a simple integer overflow. By using this, along with a stop point for the emdf_container_length of the buffer, a buffer can be underallocated without turning into a wild copy.
There's a useful pointer that can be overwritten called skip. By carefully filling the heap with multiple payloads, it's possible to overwrite the pointer and have arbitrary attacker-controlled data written to it.
Making this exploit work without an ASLR leak was super complicated and beyond my experience. It required a deep understanding of the data structures in play and the code that was interacting with them. After a lot of work, they introduced a repeatable out-of-bounds write. Using relative writes allowed us to avoid issues with ASLR. They were now able to use their write to overwrite a function pointer within a table. Neat!
Android has several mechanisms to make running shellcode within mediacoded difficult, primarily SELinux. Some co-workers, Jann Horn and Seth Jenkins came up with a plan to work around these limitations. Use ROP to write to /proc/self/mem repeatedly to make it a descriptor that's easy to guess. Then, use pwrite on the shellcode in memory to overwrite a function's code. This works because /proc/self/mem allows for any memory in a process to be overwritten for debug purposes.
Due to ASLR guessing, the exploit worked 1 in 255 times; this would take about 6 minutes to run with process restarts. They believe that the two sources of 1/16 could be removed with several months of effort. Android has a lot of platform mitigations and they reflect on this. ASLR on the lower bits of pointers made this much harder than they expected. Additionally, all parts of the process were sufficiently randomized. mediacodec contains several seccomp rules that prevent a process from executing syscalls that aren't necessary but were left out of the Pixel 9; this would have prevented the pwrite strategy that was used in this post. This would have required several weeks of development effort to implement the entire exploit in ROP.
scudo, the heap allocator, didn't feel sufficiently hardened. Part of the exploit tricked it into moving allocations. Most of the time, this wouldn't be possible because of the guard pages, but it's still worth considering. On macOS and iOS devices that use the -fbounds-safety flag, the exploit isn't possible.
The blog's perspective isn't just let's find a bug. It's can we create a reliable exploit chain like a threat actor? This is a very unique perspective that I love see, as it makes the security work feel more real.