106 - MediaTek, Yet Another Chrome Bug, and BigSig
A surprisingly simple bug in a well-fuzzed cryptographic library from Mozilla leading to an easy stack overflow in RSA-PSS code (vulnerability exists elsewhere also).
Problem Code: https://searchfox.org/mozilla-central/rev/f8576fec48d866c5f988baaf1fa8d2f8cce2a82f/security/nss/lib/cryptohi/secvfy.c#489
The VFYContext
object contains a fixed size buffer to hold a the bytes of a signature to be validated. These bytes come from the certificate from validated and the size of the signature in the certificate are not validated before attempting to copy them into the buffer, leading to, in the case of RSA-PSS at least (the vulnerability exists in multiple algorithms) a stack-based overflow with attacker controlled data. Though stack-based is not too important in this case because within the same VFYContext
object is a pointer to a SECHashObject
which contains functions pointers. Overwritting that can immediately provide a control flow hijack.
Must of this post is actually dedicated to a discussion about why this vulnerability was missed for so long with the original code being checked-in to the repository in 2003, being exposed and exploitable since 2012. Its neither a subtle to detect bug, not a hard to hit bug. Additionally, its not as though Mozilla has an immature security process and simply is not looking but still the bug was missed.
Ormandy puts forward a few issues that might have led to this that are worth considering for your own security process or fuzzing campaigns:
- Missing end-to-end testing, in the development world there is unit testing, and there is integration testing. Both are useful, and neither replaces the other. As NSS was a modular library it was easy to fuzz various components in isolation. The fuzzer would test the certificate decoder, but those decoded certificates would not be passed into other areas of the application so integration issues couldn’t easily be detected.
- Arbitrary size limits, there is a 10,000 byte limit on fuzzed input which does not reflect the limits of the code itself.
- Misleading metrics, the combined code-coverage information was exposed rather than the coverage of any individual fuzzer leading to code that was well covered by fuzzers that couldn’t possibly generate the relevant input for this bug.
Three vulnerabilities found in MediaTek’s audio Digital Signal Processor (DSP) firmware. They first go into some background on the DSP (which runs on a custom architecture and is interfaced with via the /dev/audio_ipi
driver). They dumped and reversed the firmware for it’s IPI (Inter Processor Interrupt) message handlers. Trivial overflows were found in some of these handlers.
Bug 1 - AUDIO_DSP_TASK_MSGA2DSHARDMEM
message handler heap overflow
The param1
parameter was used for a memcpy()
call to the atod_share
buffer. There’s no checks on this parameter, it can overflow the size of the destination buffer.
Bug 2 - init_share_mem_core()
heap overflow
Called when an IPI message with ID 7 is received. Similar to the first bug, param1
is used as a size for a memcpy()
. This time they attempted to check the size against 0xE0, but the destination buffer audio_dsp_dram
is only 0x20 bytes in size, so an overflow of 0xC0 bytes is still possible.
Bug 3 - AUDIO_DSP_TASK_PCM_PREPARE
message handler OOB write
Data from a user-provided audio buffer at offset 0x54 is used as an index into a static array. There’s no checking on this index, therefore you can pass an arbitrary index that’ll go out of bounds of the target array for a controlled write, since it writes using user-controlled data.
Exploitation of the TIPC heap overflow bug based on a keylength being used in a memcpy()
call before it was validated. Two objects are used in combination with the overflow to achieve code execution. First, the elastic object msg_msg
is used to derive an infoleak. Since this object is elastic (ie. it’s size can be influenced by the user), it’s a great object for heap shaping. It also contains a message size field, which the TIPC overflow can smash, yielding an out-of-bounds read when that message is received, and thus an infoleak.
This infoleak not only provides a kASLR defeat, but it also can be used to leak the pointer to the message buffer you control the contents of, allowing you to fake data without worrying about Supervisor Mode Access Prevention (SMAP).
The second object was the tty
object for pseudo-terminals. This object contains useful pointers for hijacking control flow, such as a tty_ops
pointer, which contains callbacks for various file operations like read()
, write()
, and ioctl()
. By using the TIPC overflow to smash the tty
object, it was possible to corrupt the ops pointer.
Chaining these two primitives, achieving code execution was trivial. They used it to establish an arbitrary write, then smashed the modprobe_path
to get a controlled module loaded and ran as root.