Google’s Project Zero Discovered how to Bypass Samsung’s Knox Hypervisor (Fixed in January Patch)
GoogleProjectZeroBlog has verified a number of exploits that enable Samsung’s phones running the supposedly-secure Samsung Knox security suite to be attacked. The author notes that all vulnerabilities have been passed to Samsung who has actually released fixes for them in a January software update.
As part of the Samsung Knox security software suite introduced by Samsung, there is a piece of software that sits between Android applications and the kernel — this type of software is called a Hypervisor, and can be used as an additional layer of software to further secure Android devices. The Samsung Knox Hypervisor is called “Real-time Kernel Protection” or RKP for short, as I will reference it in the rest of this article. The Kernel sits below RKP in the Android software stack, and the applications that run on the device sit at the top. The idea behind RKP is to provide an extra layer of security for the device, all requests (memory and other resources) made by applications to the Kernel have to go through Knox first, which tries to detect if an application is doing something it shouldn’t. RKP also provides security through obscurity with an extra layer to hide sensitive information an application could use to compromise the device. The article at GoogleProjectZeroBlog goes quite deep into just how Android memory, the RKP and Operating Systems in general work, I have condensed the article and simplified it to give a quick overview of what was discovered. I encourage you to read the full article if you have time, though, as it is very enlightening.
KASLR or Kernel Address Space Layout Randomisation is the process of changing the location of the kernel code in memory by a random amount at boot. Every time the device is booted the kernel is loaded into a different address space (area in memory). The idea is to make it harder to find where the kernel code is located in order to attack it because after each boot the kernel code “shifts” by a random amount in memory. This sounds like a great step to prevent would-be attackers but recent research has shown that you can actually defeat this without requiring a software bug or vulnerability, as KASLR is actually very hard to implement in a robust way against local attackers.
In the case of the RKP software, the ability to bypass KASLR is actually simpler than the research referenced above. All android devices’ memory is referenced by pointers and in order to protect the devices from attack, whenever android devices print or output (whether to screen or to file for logs or debugging), the pointers references are anonymized, and this makes it impossible to find out where the pointer actually points to when reading the output. Think of memory pointers like a street sign that points to a location and think of anonymizing as blurring that. Much like TV anonymizing is done after the filming, Android also applies this anonymizing at output time and only if anonymizing is configured correctly, and the author states that every device [he] encountered has had pointer anonymizing correctly configured. This might sound like it’s very hard to break but actually all you need to do is to find a single pointer (think street sign) that was not anonymized (blurred out) by the kernel developer (beware this is not your average Android app developer) when the pointer is written to the logs or other location e.g. screen or a file. So if you can find a pointer that wasn’t anonymized then you can calculate the kernel’s random address shift as the difference between the two. Interestingly the author couldn’t find an exploitable pointer in the kernel but did find it inside the RPK where developers forgot to anonymize a pointer in the debug (logging) output, which came about by the way of a typo. To anonymize the pointers in Android you have to use a special code and it turns out the RPK developers mistakenly used a lower case ‘k’ instead of an uppercase ‘K’. Therefore it was relatively simple to figure out the random shift amount of the kernel code and attack it.
The next exploit is a little more complex: Samsung Knox protects your device by applying a set of rules to the devices memory to stop malicious code. The rules are as follows:
- All pages (code in memory), with the exception of the kernel’s code, are marked as “Privileged Execute Never” (meaning code here can never run)
- Kernel data pages (data used by the program in memory) are never marked executable (so code here can never run)
- Kernel code pages (code in memory) are never marked writable (so no malicious code can change it)
- All kernel pages are marked as read-only in stage 2 translation table (the table that sits between the application and the kernel to further prevent applications knowing about real memory locations)
- All memory translation entries are marked as read-only for applications.
We will focus on rule 3 as this is where the author found a problem with the implementation of the rules above. RPK does in fact mark the memory for the kernel as read-only, however as an oversight to the KASL a hole was discovered, which led to writing code into the supposedly “read-only” section. In order to obfuscate the location of the kernel at boot time memory is allocated to the kernel, this amount of memory is much larger than the kernel’s text segment. By allocating a larger amount of memory it makes it much harder to find the actual kernel code which could be anywhere, and as we saw above it is moved randomly on each boot of the device.
_text and _etext mark the protected range
The author was able to confirm that the memory used by the kernel was indeed marked as “read-only”, however the rest of that large amount of memory used to hide the kernel was not marked as “read-only”. This is because RKP only protects a only the region containing the kernel’s text after applying the KASLR slide.
In the third exploit the author was able access another area of memory that should be restricted to read-only as well. The RKP protects memory and uses a Hypervisor Configuration Register (HCR) to control key kernel operations. The point of the HCR is to allow valid and real kernel operations to access the registers and block malicious attacks. It does this by checking the calls made to the registers which govern the virtualization features. The HCR is configured to block specific operations which would be handled normally allowing RKP to choose whether to allow or disallow a request. In this exploit the HCR control was not covering two registers that turned out to be very important. The author dug deep into the ARM Reference manual and discovered that the first register allowed him to basically turn off RKP for applications. The System Control Register for EL1 (SCTLR_EL1) provides top-level control over the system, including the memory system. In a prefect world the application would use memory that was mapped via the RKP so that the RKP could control what the application could access. However turning off this register allowed the RKP to be disabled by effectively returning the device to how it ran before RKP was installed – meaning that the device mapped to physical memory without the extra security provided by RKP. That in turn meant that the author could read and write to memory that was orginaly and correctly blocked by the RKP software.
The second register that was missed had a more subtle affect, but ultimately just as devastating to security. The Translation Control Register for EL1 (TCR_EL1) register directly relates to the amount of memory that an application works with called a page. RKP is hardcoded to a page size of 4kb because AARCH64 Linux kernels (such as Android) use a translation size of 4KB. The register in question (TCR_EL1) sets the ARM chipsets to the size of memory that is to be returned. It turns out that this register is not protected by the HCR and therefore an attacker can change it, the author changed it to 64kb page size. What this means is that when the request is fulfilled by RKP the actual amount of memory accessible is now 64kb instead of 4kb. The reason is that the ARM chipset still controls the page size and it was set to 64kb by the exploit. Since the RKP protects memory from being written to as part of the rules listed in exploit #2 the memory is still actually protected — but here is the catch, since RKP is hardcoded to 4kb it doesn’t change to a 64kb page size when the register was updated, so only the first 4kb of memory are protected allowing the attacker to do whatever he wants with the remaining 60kb.
The last exploit the author shows is referencing memory where the RKP software is, so the attacker could attack the RKP software itself. One trick to stop this type of attack which linux kernels use as well is to un-map your program from the virtual memory address space so no applications can attack it because they cant reference it. Remember that memory is all about pointers and tables which map physical memory to virtual memory. So as per the normal defense in this type of attack RKP un-maps itself so that it cannot be attacked. However, where the kernel doesn’t provide such abilities, RKP does allow a piece of memory to be mapped and marked as Read/Write, the only check is that its not the underlying kernel itself, RKP makes no checks to see if the addresses that are being requested to be mapped is the area where RKP itself resides in memory. Basically, RKP allows itself to be re-mapped back into the address space that applications can access and as a side affect the memory is automatically marked as Read/Write so an attacker can now use the memory however it wants.
One of the biggest issues with the exploits listed above is that the author mentions how difficult these would be to do due to the lack of functions in the base Android kernel; ironically the secure RKP hypervisor provided all the tools that were required to carry out the attacks. It goes to show sometimes well-intentioned software causes more issues than it solves and its lucky that we have people like Gal Beniamini willing to get theirs hands dirty and test that the documentation matches what the software actually does.
While these exploits seem scary and make Knox sound very vulnerable I would like to reassure everyone again that these issues have all been fixed in the January update from Samsung. Also, these exploits require a very deep understanding of ARM processors and programming.
Source: Project Zero