In January, Barak Gabai of the X-Force Application Security Research Team discovered an interesting information leak vulnerability in iOS IOKit IOMobileFramebuffer (CVE-2015-1097), which can be used to defeat the kernel address obfuscation mechanism available since iOS 6. The vulnerability was disclosed to Apple and has been fixed in iOS 8.3.

In this blog post, I will provide a brief overview of the kernel address obfuscation technique employed by iOS and show how Gabai’s vulnerability renders it ineffective, as is the case with similar memory disclosures. I will also briefly touch on what I believe makes this particular vulnerability uniquely interesting.

The iOS kernel address obfuscation is excellently described in full in the “mach_port_kobject() and the kernel address obfuscation” blog post by Stefan Esser. Readers unfamiliar with this security mitigation mechanism and techniques for defeating it are encouraged to first read Esser’s post.

Background

On iOS, the kernel address space is randomized. C++ objects on the kernel heap are juicy targets for exploiters, and they can often be used for arbitrary code execution.

In some circumstances, the kernel — such as via mach_port_kobject() prior to iOS 8.1.3 — can provide an address of a kernel object to a user-space caller. Should the address of these objects be provided directly to user-space, exploitation would be assisted because an attacker — such as a malware author or jailbreak developer — could know where exploitable heap objects were situated in the kernel heap. Therefore, in recent versions of the kernel, these addresses are not passed to user-space in the clear and are instead obfuscated.

In order to perform this obfuscation of kernel-space addresses prior to being exposed to user-space, the addresses are passed through the VM_KERNEL_ADDRPERM(addr) macro, which is defined as follows:

#define VM_KERNEL_ADDRPERM(_v) \
 (((vm_offset_t)(_v) == 0) ? \
  (vm_offset_t)(0) : \
  (vm_offset_t)(_v) + vm_kernel_addrperm)

As we can see, the code takes the kernel-space address and adds a vm_kernel_addrperm value to it. This permutation constant is a random value that is generated on boot. Prior work has been published on the strength of this permutation constant, and I’m not going to go into how the vm_kernel_addrperm value is generated in this blog post. However, for the purposes of this discussion, let’s assume Apple has managed to generate a permutation constant of sufficient entropy.

If all the above worked as it should, it would be difficult to attack the interesting objects situated on the kernel heap. However, in order to defeat this mechanism, we can make use of the invertible nature of the obfuscation function in order to deobfuscate the kernel address. The kernel is able to do so because it already knows vm_kernel_addrperm. So if we would like to do the same, we would ideally like to discover vm_kernel_addrperm.

For the function itself, we can see the following:

vm_kernel_addrperm = addr_obfuscated - addr_clear

So if we manage to find a leak of addr_clear (or any address from which we can reliably calculate the offset), we can then render the entire obfuscation mechanism useless. Such leaks have been demonstrated in the past.

The Vulnerability

Gabai discovered that the (unobfuscated) address of the IOMobileFramebuffer object on the kernel heap is inadvertently being leaked to user-space by a member function. In my opinion, what makes this particular leak interesting is the mechanism of the leak itself.

The vulnerability can basically be summarized as follows: The ‘get_framebuffer_id’ method (selector 7) of IOMobileFramebufferUserClient calls a member method of IOMobileFramebuffer and passes the return value of the call to user-space.

In the standard ARM calling convention, the R0 register is used both to pass the first argument to the function and to hold the return value on the function return.

In our case, the first argument (placed in R0) is the pointer of the IOMobileFramebuffer object itself. In this instance, the called method is, in fact, ’empty’ — a nullsub. Therefore, as the caller expects the return value to be in R0 — and the nullsub simply doesn’t touch R0 — the return value is the persisted value of R0, the object pointer. This is then further persisted to user-space, and hence, we have our information leak.

How Can These Nullsubs Occur?

The most likely reason in the case of C++ is that an empty virtual function of a base class has been called instead of the derived class function. In such a case, the return register, as defined by the calling convention, will persist in its value. In C++, the first argument is the pointer of the object itself (the ‘this’ pointer). Depending on the calling convention, such as in the case of the standard ARM calling convention, it’s even possible that this object pointer is what will be present in the return register, then the function returns.

Another reason could be that code may have been #if{,def}’d out. This pattern is sometimes seen with debug code, which is to be removed in release builds. In such a case, it is possible that compiler optimizations could remove the function altogether. Based on some minor experimentation I performed with both GCC and Clang at varying optimization levels, it’s entirely possible nullsubs could be left in the code. Also, by default, GCC doesn’t warn about control reaching the end of a non-void function, whereas Clang does.

Any instance where control from a non-void function can return without a return value is potentially dangerous, and developers should take care to eliminate such instances from their code.

While developers need to be aware of how the code looks in a high-level language, they should think about what’s happening under the hood, as well.

More from Software Vulnerabilities

Patch Tuesday -> Exploit Wednesday: Pwning Windows Ancillary Function Driver for WinSock (afd.sys) in 24 Hours

‘Patch Tuesday, Exploit Wednesday’ is an old hacker adage that refers to the weaponization of vulnerabilities the day after monthly security patches become publicly available. As security improves and exploit mitigations become more sophisticated, the amount of research and development required to craft a weaponized exploit has increased. This is especially relevant for memory corruption vulnerabilities.Figure 1 — Exploitation timelineHowever, with the addition of new features (and memory-unsafe C code) in the Windows 11 kernel, ripe new attack surfaces can…

Direct Kernel Object Manipulation (DKOM) Attacks on ETW Providers

Overview In this post, IBM Security X-Force Red offensive hackers analyze how attackers, with elevated privileges, can use their access to stage Windows Kernel post-exploitation capabilities. Over the last few years, public accounts have increasingly shown that less sophisticated attackers are using this technique to achieve their objectives. It is therefore important that we put a spotlight on this capability and learn more about its potential impact. Specifically, in this post, we will evaluate how Kernel post-exploitation can be used…

Dissecting and Exploiting TCP/IP RCE Vulnerability “EvilESP”

September’s Patch Tuesday unveiled a critical remote vulnerability in tcpip.sys, CVE-2022-34718. The advisory from Microsoft reads: “An unauthenticated attacker could send a specially crafted IPv6 packet to a Windows node where IPsec is enabled, which could enable a remote code execution exploitation on that machine.” Pure remote vulnerabilities usually yield a lot of interest, but even over a month after the patch, no additional information outside of Microsoft’s advisory had been publicly published. From my side, it had been a…

Self-Checkout This Discord C2

This post was made possible through the contributions of James Kainth, Joseph Lozowski, and Philip Pedersen. In November 2022, during an incident investigation involving a self-checkout point-of-sale (POS) system in Europe, IBM Security X-Force identified a novel technique employed by an attacker to introduce a command and control (C2) channel built upon Discord channel messages. Discord is a chat, voice, and video service enabling users to join and create communities associated with their interests. While Discord and its related software…