It's been a few months since our analysis of the new ASLR support in Android ICS 4.0. Given that ICS 4.0 is old news now with the recent release of Jelly Bean 4.1, I thought it was about time to give an update on the ASLR capabilities as well as cover some of the other improvements in exploit mitigations present in Jelly Bean.
As a quick recap of the current state of ASLR in Android ICS:
For the uninitiated, ASLR randomizes where various areas of memory (eg. stack, heap, libs, etc) are mapped in the address space of a process. Combined with complementary mitigation techniques such as non-executable memory protection (NX, XN, DEP, W^X, whatever you want to call it), ASLR makes the exploitation of traditional memory corruption vulnerabilities probabilistically difficult. ... Unfortunately, the ASLR support in Android 4.0 did not live up to expectations and is largely ineffective for mitigating real-world attacks, due to the lack of randomization of the executable and linker memory regions. It also would be beneficial to randomize the heap/brk by setting kernel.randomize_va_space=2.
So, things weren't in great shape. Despite those deficiencies, Android has stepped its game up mitigation-wise in the new Jelly Bean release. Read on for the full details!
A Brief History of Mitigations in Android
I was going to give an overview of how exploit mitigations have evolved over the years in the various versions of Android, but it looks like Nick K from Google has beat me to it with a great timeline in their official security documentation:
- ProPolice to prevent stack buffer overruns (-fstack-protector)
- safe_iop to reduce integer overflows
- Extensions to OpenBSD dlmalloc to prevent double free() vulnerabilities and to prevent chunk consolidation attacks. Chunk consolidation attacks are a common way to exploit heap corruption.
- OpenBSD calloc to prevent integer overflows during memory allocation
- Format string vulnerability protections (-Wformat-security -Werror=format-security)
- Hardware-based No eXecute (NX) to prevent code execution on the stack and heap
- Linux mmap_min_addr to mitigate null pointer dereference privilege escalation (further enhanced in Android 4.1)
- Address Space Layout Randomization (ASLR) to randomize key locations in memory
- PIE (Position Independent Executable) support
- Read-only relocations / immediate binding (-Wl,-z,relro -Wl,-z,now)
- dmesg_restrict enabled (avoid leaking kernel addresses)
- kptr_restrict enabled (avoid leaking kernel addresses)
What's New in Jelly Bean
There's a few exploit mitigations that have been added/improved for Jelly Bean 4.1. Let's go into a bit of detail on each.
ASLR - Position Independent Executables (PIE)
As we mentioned in our previous post on Android ASLR, the executable mapping in the process address space was not randomized in Ice Cream Sandwich, making ROP-style attacks possible using the whole executable as a source of gadgets. In Jelly Bean, most binaries are now compiled/linked with the PIE flag (commits for the linker, ARM and x86), which means the executable mapping will be properly randomized when executed.
To check whether a binary is a PIE, you can use the readelf(1) and check the type field in the ELF header. For example, the vold binary on Ice Cream Sandwich is not PIE-enabled as indicated by the EXEC ELF type:
$ arm-linux-androideabi-readelf -h vold-4.0.2-gnexus | grep Type Type: EXEC (Executable file)
While the vold binary on the new Jelly Bean version is PIE-enabled as indicated by the DYN ELF type:
$ arm-linux-androideabi-readelf -h vold-4.1.1-gnexus | grep Type Type: DYN (Shared object file)
ASLR - Heap / Brk Randomization
As mentioned in our previous blog post, kernel.randomize_va_space sysctl has now been set to 2 in Jelly Bean, enabling randomization of the heap/brk space, which was lacking in Ice Cream Sandwich.
You can verify the correct randomize_va_space parameter easily on your device using adb:
shell@android:/ $ cat /proc/version Linux version 3.0.31-g6fb96c9 ... shell@android:/ $ cat /proc/sys/kernel/randomize_va_space 2
ASLR - Linker Randomization
The custom Android linker was the last piece of the ASLR puzzle that was not randomized in Ice Cream Sandwich. In Jelly Bean, the linker is now randomized in the process address space.
This means that the deficiencies in ICS pointed out in our previous blog post have all been addressed in Jelly Bean, giving it full stack, heap/brk, lib/mmap, linker, and executable ASLR:
Props to Nick K and the Android team for getting this implemented and landed between 4.0 and 4.1.
ELF Hardening - RELRO / BIND_NOW
Also new in Jelly Bean, most of the system binaries are compiled with the RELRO and BIND_NOW flags passed to the linker (commits for the linker, ARM, and x86). This hardens those binaries against attacks that may attempt to overwrite the GOT and other sensitive ELF structures by making them read-only at startup.
Stealth's popular Gingerbreak exploit used a GOT overwrite to obtain code execution in the vold daemon. Check out slide #42 and #43 in my "Don't Root Robots" presentation to see how Gingerbreak overwrites a GOT entry to point to system(3) and executes an arbitrary privileged command.
If you're interested in more non-Android-specific details on how the RELRO and BIND_NOW linker flags prevent GOT overwrites and other ELF trickery, Julien has a good blog post on the topic.
Infoleak Prevention - dmesg_restrict / kptr_restrict
Jelly Bean also pulled in a couple easy enhancements inherited from the upstream Linux kernel that can prevent information leakage. The dmesg_restrict and kptr_restrict sysctls, originally implemented by Dan Rosenberg, are now available and enabled in 4.1. The former will prevent an unprivileged user from reading the dmesg/klogctl buffer which may contain sensitive information. The latter will prevent the system from exposing sensitive kernel address (eg. through various interfaces in /proc) to unprivileged userspace processes.
The end result is denying attackers information sources on the system that may aid in increasing the feasibility or reliability of a kernel exploit. For example, my Levitator exploit used the /proc/kallsyms interface, which is now restricted by kptr_restrict. It's not a huge gain, but still a good proactive step.
What's Next for Android
Now that ASLR is implemented "fully", it will certainly drive more interest towards the inherent weaknesses of 32-bit ASLR and other more platform/architecture-specific ASLR bypasses. Expect to see analysis showing just how weak "full ASLR" is entropy-wise when dealing with the constraints of a 32-bit address space. When you start digging into the implementation-specific details of exploit mitigations, hilarity often results (case in point: the 1 bit of entropy in Windows stack cookies). Hey, maybe I'll do it if I can find some free time.
Since Google decided to implement their own libc (bionic), they lose some of the exploit mitigation benefits that have been in glibc for a while (did I really just use "exploit mitigation benefits" and "glibc" in the same sentence?). One such example is FORTIFY_SOURCE, a group of mitigations that can prevent certain styles of buffer overflows and string formatting attacks. Google will have to implement similar functionality into their bionic library.
The PaX and grsecurity patchsets offer a wide range of hardening techniques that go above and beyond what the traditional Linux userspace and kernel offers. While some techniques may be inappropriate for mobile use due to performance impact and other architectural considerations, Google can definitely cherry-pick from these patchsets if they decide to be proactive about exploit mitigations.
MAC / RBAC
Once a system has been hardened with the latest and greatest exploit mitigations available, one usually looks towards other methods of containing a successful exploit to prevent it from adversely affecting the rest of the system. Commonly, in the Linux world, folks will deploy MAC or RBAC based systems (such as SELinux, grsecurity, SMACK, Yama, seccomp, etc) to attempt to sandbox and bound the impact of a successful exploit. Given Google's involvement in the new seccomp filter for ChromeOS and Chromium, I would not be at all surprised to see it employed in Android in the near future.
Mandatory Code Signing
Lastly, code signing would go a long way towards preventing traditional memory corruption attacks (and also making Bouncer's challenges a bit more tractable).
While Android is still playing a bit of catch-up, other mobile platforms are moving ahead with more innovative exploit mitigation techniques, such as the in-kernel ASLR present in Apple's iOS 6. One could claim that iOS is being proactive with such techniques, but in reality, they're simply being reactive to the type of exploits that typically target the iOS platform. However, Apple does deserve credit for raising the barrier up to the point of kernel exploitation by employing effective userspace mitigations such NX, ASLR, and mandatory code signing. Thankfully, Android is getting there, and Jelly Bean is a major step towards that goal.
[caption id="attachment_1260" align="aligncenter" width="500"] Dug and Jon spend some time testing Android security in-person.[/caption]