Exploits & Vulnerabilities
LLDBFuzzer: Debugging and Fuzzing the Apple Kernel
Our fuzzing methodology LLDBFuzzer found dozens of vulnerabilities, including double free and out-of-bounds (OOB) read/write bugs. These vulnerabilities could allow an attacker access to restricted memory or be used in a privilege escalation attack.
The bug hunting space has grown significantly smaller now that most mobile operating systems feature built-in threat mitigation tools and techniques. Android 9’s control flow integrity (CFI) or pointer authentication codes (PAC) based on iOS 12 hardware are some examples of such features. Industry-standard fuzzers like Americal fuzzy lop (AFL) and syzkaller are widely used as well.
To help security researchers, we have developed LLDBFuzzer, which is based on the LLVM Project's next-generation debugger called Low Level Debugger (LLDB). We tested LLDBFuzzer on a MacPro's AMD graphic drivers. These drivers are used to accelerate and optimize 2D, 3D and video rendering, and they contain many interfaces that the user space can access; these features make them a good target for LLDBFuzzer.
LLDB is not suitable for debugging low-level kernel components, but it can debug almost all the kernel extensions and XNU codes after the required hardware is operational. Based on these features, this is the novel fuzzing architecture of LLDBFuzzer:
Figure 1. The LLDBFuzzer Architecture
This solution is based on the remote kernel debugger system, so there are two machines: the remote machine, which runs our main fuzzing logic; and the target machine, which is loaded with a custom kernel and deploys our fuzz point. The target machine can be a MacOS VM or a real device.
The following explains each module:
- Probe Setup: It will query the fuzz strategy, which contains all the attack surfaces we revised from XNU and KEXTs, and parse them for an executor to deploy probes on the target machine.
- Mutation: The executor will break at probe point, then bit flip their input buffer. However, not all the inputs need mutation because the inputs are not always buffers; the executor will use the debug function to check them.
- Crash Monitor: This module will monitor the status of target machines via the fuzzing log, and then return the signal. It can use the manager toolset to restart, or send the core dump and panic logs to fuzzing servers for further reproduction.
- Executor: This is a fuzz controller for all fuzzing steps.
- Sanitizers: The target machine loads our custom XNU, which is compiled with a kernel address sanitizer (KSAN) and a kernel memory sanitizer (KMSAN). These two sanitizers were introduced in our BlackHat Europe 2018 presentation.
- Remote Debugger Components: This module is an essential part of our whole fuzzing solution. It is implemented in the Ethernet driver; however, not all drivers implement the kernel debugger functions (an example would be the Intel Mausi Network Driver).
- XNU and KEXTs: Unusually, due to the features of the LLDB debugger, LLDBFuzzer will not only pay attention to the normal attack surface, such as "is_io_connect_method" and "unix_syscall64," but also to the deeper attack surface, such as the "IOAccelCommandStreamInfo" process functions in the AMDRadeonX4000_AMDSIGLContext service.
Results of LLDBFuzzer Experimentation
Our fuzzing methodology found several vulnerabilities, including double free and out-of-bounds (OOB) read/write bugs. These vulnerabilities could allow an attacker access to restricted memory or be used in a privilege escalation attack.
LLDBFuzzer has proven to be an effective way to find and expand new attack interfaces; but it is also flexible, scalable, and scriptable for vulnerability research utilities. In our full report below, we demonstrate how to implement an LLDB debugger client within network extensions, which can help security researchers fuzz within virtual machines to significantly improve efficiency. We also discuss six of the vulnerabilities we found, and analyze what caused them.
To learn more about LLDBFuzzer, download our full technical brief.