Wednesday, February 8, 2017

Lifting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 (Hyper) Visor: Bypassing Samsung’s Real-Time Kernel Protection

Posted by Gal Beniamini, Project Zero

Traditionally, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system’s kernel is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last security boundary standing between an attacker and full control over a target system. As such, additional care must be taken in order to ensure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 integrity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. First, when a system boots, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 integrity of its key components, including that of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system’s kernel, must be verified. This is achieved on Android by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 verified boot chain. However, simply booting an aucá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365nticated kernel is insufficient—what about maintaining cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 integrity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system is executing?

Imagine a scenario where an attacker is able to find and exploit a vulnerability in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system’s kernel. Using such a vulnerability, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker may attempt to subvert cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 integrity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel itself, eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r by modifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of its code, or by introducing new attacker-controlled code and running it within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system. Even more subtly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker may choose to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data structures used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system in order to alter its behaviour (for example, by granting excessive rights to select processes). As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel is in charge of managing all memory translations, including its own, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is no mechanism in place preventing an attacker within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same context from doing so.

However, in keeping with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 concept of “defence in depth”, additional layers may be added in order to safeguard cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel against such would-be attackers. If stacked correctly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se layers may be designed in such a way which eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r severely limits or simply prevents an attacker from subverting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s integrity.

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android ecosystem, Samsung provides a security hypervisor which aims to tackle cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem of ensuring cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 integrity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel during runtime. The hypervisor, dubbed “Real-Time Kernel Protection” (RKP), was introduced as part of Samsung KNOX. In this blog post we’ll take an in-depth look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 inner-working of RKP and present multiple vulnerabilities which allowed attackers to subvert each of RKP’s security mechanisms. We’ll also see how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 design of RKP could be fortified in order to prevent future attacks of this nature, making exploitation of RKP much harder.

As always, all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerabilities in this article have been disclosed to Samsung, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fixes have been made available in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 January SMR.

I would like to note that in addition to addressing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reported issues, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Samsung KNOX team has been extremely helpful and open to discussion. This dialogue helped ensure that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues were diagnosed correctly and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 root causes identified. Moreover, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KNOX team has reviewed this article in advance, and have provided key insights into future improvements planned for RKP based on this research.

I would especially like to thank Tomislav Suchan from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Samsung KNOX team for helping address every single query I had and for providing deep insightful responses. Tomislav’s hard work ensured that all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues were addressed correctly and fully, leaving no stone unturned.

HYP 101


Before we can start exploring cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 architecture of RKP, we first need a basic understanding of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtualisation extensions on ARMv8. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ARMv8 architecture, a new concept of exception levels was introduced. Generally, discrete components run under different exception levels - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 more privileged cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 component, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 higher its exception level.

Screenshot from 2017-01-27 12:45:40.png

In this blog post we’ll only focus on exception levels within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “Normal World”. Within this context, EL0 represents user-mode processes running on Android, EL1 represents Android’s Linux kernel, and EL2 (also known as “HYP” mode) represents cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RKP hypervisor.

Recall cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n when user-mode processes (EL0) wish to interact with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system’s kernel (EL1), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y must do so by issuing “Supervisor Calls” (SVCs), triggering exceptions which are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n handled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. Much in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same way, interactions with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor (EL2) are performed by issuing “Hypervisor Calls” (HVCs).

Additionally, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor may control key operations that are performed within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, by using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “Hypervisor Configuration Register” (HCR). This register governs over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtualisation features that enable EL2 to interact with code running in EL1. For example, setting certain bits in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 HCR will cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor to trap specific operations which would normally be handled by EL1, enabling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor to choose whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r to allow or disallow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requested operation.

Lastly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor is able to implement an additional layer of memory translation, called a “stage 2 translation”. Instead of using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 regular model where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system’s translation table maps between virtual addresses (VAs) and physical addresses (PAs), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation process is split in two.

First, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 translation tables are used in order to map a given VA to an intermediate physical address (IPA) - this is called a “stage 1 translation”. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 access controls present in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation are also applied, including access permission (AP) bits, execute never (XN) and privileged execute never (PXN).

Then, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting IPA is translated to a PA by performing a “stage 2 translation”. This mapping is performed by using a translation table which is accessible to EL2, and is inaccessible to code running in EL1. By using this 2-stage translation regime, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor is able to prevent access to certain key regions of physical memory, which may contain sensitive data that should be kept secret from EL1.

Screenshot from 2017-01-27 15:18:54.png

Creating a Research Platform


As we just saw in our “HYP 101” lesson, communicating with EL2 explicitly is done by issuing HVCs. Unlike SVCs which may be freely issued by code running in EL0, HVCs can only be triggered by code running in EL1. Since RKP runs in EL2 and exposes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vast majority of its functionality by means of commands which can be triggered from HVCs, we first need a platform from which we are able to send arbitrary HVCs.

Fortunately, in a recent blog post, we already covered an exploit that allowed us to elevate privileges into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of system_server. This means that all that’s left before we can start investigating RKP and interacting with EL2, is to find an additional vulnerability that allows escalation from an already privileged context (such as system_server), to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel.

Luckily, simply surveying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack surface exposed to such privileged contexts revealed a vast amount of relatively straightforward vulnerabilities, any of which could be used to gain some foothold in EL1. For cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 purpose of this research, I’ve decided to exploit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most convenient of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se: a simple stack overflow in a sysfs entry, which could be used to gain arbitrary control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack contents for a kernel thread. Once we have control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack’s contents, we can construct a ROP payload that prepares arguments for a function call in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, calls that function, and returns cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 results back to user-space.

Untitled Diagram.png

In order to ease exploitation, we can wrap cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire process of creating a ROP stack which calls a kernel function and returns cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 results to user-space, into a single function, which we’ll call “execute_in_kernel”. Combined with our shellcode wrapper, which converts normal-looking C code to shellcode that can be injected into system_server, we are now able to freely construct and run code which is able to invoke kernel functions on demand.

Screenshot from 2017-01-27 16:42:38.png


Putting it all togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, we can start investigating and interacting with RKP using this robust research platform. The rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 research detailed in this blog post was conducted on a fully updated Galaxy S7 Edge (SM-G935F, XXS1APG3, Exynos chipset), using this exact framework in order to inject code into system_server using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first exploit, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n run code in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second exploit.

Finally, now that we’ve laid down all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 needed foundations, let’s get cracking!

Mitigation #1 - KASLR


With cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 introduction of KNOX v2.6, Samsung devices implement Kernel Address Space Layout Randomisation (KASLR). This security feature introduces a random “offset”, generated each time cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device boots, by which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 base address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel is shifted. Normally, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel is loaded into a fixed physical address, which corresponds to a fixed virtual address in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 VAS of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. By introducing KASLR, all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s memory, including its code, is shifted by this randomised offset (also known as a “slide”).

While KASLR may be a valid mitigation against remote attackers aiming to exploit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, it is very hard to implement in a robust way against local attackers. In fact, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re has been some very interesting recent research on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 subject which manages to defeat KASLR without requiring any software bug (e.g., by observing timing differences).

While those attacks are quite interesting in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir own right, it should be noted that bypassing KASLR can often be achieved much more easily. Recall that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire kernel is shifted by a single “slide” value - this means that leaking any pointer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel which resides at a known offset from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s base address would allow us to easily calculate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 slide’s value.

The Linux kernel does include mechanisms intended to prevent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 leakage of such pointers to user-space. One such mitigation is enforced by ensuring that every time a pointer’s value is written by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, it is printed using a special format specifier: “%pK”. Then, depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of kptr_restrict, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel may anonymise cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 printed pointer. In all Android devices that I’ve encountered, kptr_restrict is configured correctly, indeed ensuring cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “%pK” pointers are anonymised.

Be that as it may, all we need is to find a single pointer which a kernel developer neglected to anonymise. In Samsung’s case, this turned out to be racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r amusing… The pm_qos debugfs entry, which is readable by system_server, included cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following code snippet responsible for outputting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entry’s contents:

static void pm_qos_debug_show_one(struct seq_file *s, struct pm_qos_object *qos)
{
   struct plist_node *p;
   unsigned long flags;

   spin_lock_irqsave(&pm_qos_lock, flags);

   seq_printf(s, "%s\n", qos->name);
   seq_printf(s, "   default value: %d\n", qos->constraints->default_value);
   seq_printf(s, "   target value: %d\n", qos->constraints->target_value);
   seq_printf(s, "   requests:\n");
   plist_for_each(p, &qos->constraints->list)
       seq_printf(s, "      %pk(%s:%d): %d\n",
                     container_of(p, struct pm_qos_request, node),
                     (container_of(p, struct pm_qos_request, node))->func,
                     (container_of(p, struct pm_qos_request, node))->line,
                     p->prio);

   spin_unlock_irqrestore(&pm_qos_lock, flags);
}

Unfortunately, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 anonymisation format specifier is case sensitive… Using a lowercase “k”, like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code above, causes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code above to output cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer without applying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 anonymisation offered by “%pK” (perhaps this serves as a good example of how fragile KASLR is). Regardless, this allows us to simply read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of pm_qos, and subtract cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer’s value from it’s known offset from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s base address, thus giving us cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KASLR slide.

Mitigation #2 - Loading Arbitrary Kernel Code


Preventing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation of new kernel code is one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 main mitigations enforced by RKP. In addition, RKP aims to protect all existing kernel code against modification. These mitigations are achieved by enforcing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following set of rules:

  1. All pages, with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exception of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code, are marked as “Privileged Execute Never” (PXN)
  2. Kernel data pages are never marked executable
  3. Kernel code pages are never marked writable
  4. All kernel code pages are marked as read-only in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table
  5. All memory translation entries (PGDs, PMDs and PTEs) are marked as read-only for EL1

While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se rules appear to be quite robust, how can we be sure that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are being enforced correctly? Admittedly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rules are laid out nicely in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RKP documentation, but that’s not a strong enough guarantee...

Instead of exercising trust, let’s start by challenging cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first assertion; namely, that with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exception of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code, all ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r pages are marked as PXN. We can check this assertion by looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation tables in EL1. ARMv8 supports cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use of two translation tables in EL1, TTBR0_EL1 and TTBR1_EL1. TTBR0_EL1 is used to hold cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mappings for user-space’s VAS, while TTBR1_EL1 holds cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s global mappings.

In order to analyse cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 stage 1 translation table used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, we’ll need to first locate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 physical address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation table itself. Once we find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation table, we can use our execute_in_kernel primitive in order to iteratively execute a “read gadget” in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel, allowing us to read out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation table.

There is one tiny snag, though - how will we be able to retrieve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation table? To do so, we’ll need to find a gadget which allows us to read TTBR1_EL1 without causing any adverse effects in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel.

Unfortunately, combing over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code reveals a depressing fact - it seems as though such gadgets are quite rare. While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are some functions that do read TTBR1_EL1, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y also perform additional operations, resulting in unwanted side effects. In contrast, RKP’s code segments seem to be rife with such gadgets - in fact, RKP contains small gadgets to read and write nearly every single control register belonging to EL1.

Perhaps we could somehow use this fact to our advantage? Digging deeper into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code (init/main.c) reveals that racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r perplexingly, on Exynos devices (as opposed to Qualcomm-based devices) RKP is bootstrapped by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 kernel. This means that instead of booting EL2 directly from EL3, it seems that EL1 is booted first, and only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n performs some operations in order to bootstrap EL2.

This bootstrapping is achieved by embedding cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire binary containing RKP’s code in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 kernel’s code segment. Then, once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel boots, it copies cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RKP binary to a predefined physical range and transitions to TrustZone in order to bootstrap and initialise RKP.

RKP bootstrap.png

By embedding cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RKP binary within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s text segment, it becomes a part of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory range executable from EL1. This allows us to leverage all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 gadgets in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 embedded RKP binary - making life that much easier.

Equipped with this new knowledge, we can now create a small program which reads cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation table using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 gadgets from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RKP binary directly in EL1, and subsequently dumps and parses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 table’s contents. Since we are interested in bypassing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code loading mitigations enforced by RKP, we’ll focus on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 physical memory ranges containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel. After writing and running this program, we are faced with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following output:

...
[256] L1 table [PXNTable: 0, APTable: 0]
 [  0] 0x080000000-0x080200000 [PXN: 0, UXN: 1, AP: 0]
 [  1] 0x080200000-0x080400000 [PXN: 0, UXN: 1, AP: 0]
 [  2] 0x080400000-0x080600000 [PXN: 0, UXN: 1, AP: 0]
 [  3] 0x080600000-0x080800000 [PXN: 0, UXN: 1, AP: 0]
 [  4] 0x080800000-0x080a00000 [PXN: 0, UXN: 1, AP: 0]
 [  5] 0x080a00000-0x080c00000 [PXN: 0, UXN: 1, AP: 0]
 [  6] 0x080c00000-0x080e00000 [PXN: 0, UXN: 1, AP: 0]
 [  7] 0x080e00000-0x081000000 [PXN: 0, UXN: 1, AP: 0]
 [  8] 0x081000000-0x081200000 [PXN: 0, UXN: 1, AP: 0]
 [  9] 0x081200000-0x081400000 [PXN: 0, UXN: 1, AP: 0]
 [ 10] 0x081400000-0x081600000 [PXN: 1, UXN: 1, AP: 0]
...

As we can see above, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire physical memory range [0x80000000, 0x81400000] is mapped in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation table using first level “Section” descriptors, each of which is responsible for translating a 1MB range of memory. We can also see that, as expected, this range is marked UXN and non-PXN - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore EL1 is allowed to execute memory in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se ranges, while EL0 is prohibited from doing so. However, much more surprisingly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire range is marked with access permission (AP) bit values of “00”. Let’s consult cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ARM VMSA to see what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se values indicate:

Screenshot from 2017-01-28 12:23:15.png


Aha - so in fact this means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se memory ranges are also readable and writable from EL1! Combining all this togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, we reach cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 conclusion that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire physical range of [0x80000000, 0x81400000] is mapped as RWX in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation table.

This still doesn’t mean we can modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code. Remember, RKP enforces cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 memory translation as well. These memory ranges could well be restricted in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation in order to prevent attackers from gaining write access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m.

After some reversing, we find that RKP’s initial stage 2 translation table is in fact embedded in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RKP binary itself. This allows us to extract its contents and to analyse it in detail, similar to our previous work on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation table.

Screenshot from 2017-01-28 12:34:45.png

I’ve written a python script which analyses a given binary blob according to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table’s format specified in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ARM VMSA. Next, we can use this script in order to discover cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory protections enforced by RKP on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s physical address range:

...
0x80000000-0x80200000: S2AP=11, XN=0
0x80200000-0x80400000: S2AP=11, XN=0
0x80400000-0x80600000: S2AP=11, XN=0
0x80600000-0x80800000: S2AP=11, XN=0
0x80800000-0x80a00000: S2AP=11, XN=0
0x80a00000-0x80c00000: S2AP=11, XN=0
0x80c00000-0x80e00000: S2AP=11, XN=0
0x80e00000-0x81000000: S2AP=11, XN=0
0x81000000-0x81200000: S2AP=11, XN=0
0x81200000-0x81400000: S2AP=11, XN=0
0x81400000-0x81600000: S2AP=11, XN=0
...

First of all, we can see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table used by RKP maps every IPA to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same PA. As such, we can safely ignore cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existence of IPAs for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 remainder of this blog post and focus of PAs instead.

More importantly, however, we can see that our memory range of interest is not marked as XN, as is expected. After all, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel should be executable by EL1. But bafflingly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire range is marked with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 access permission (S2AP) bits set to “11”. Once again, let’s consult cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ARM VMSA:

Screenshot from 2017-01-28 12:51:37.png
So this seems a little odd… Does this mean that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire kernel’s code range is marked as RWX in both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table? That doesn’t seem to add up. Indeed, trying to write to memory addresses containing EL1 kernel code results in a translation fault, so we’re definitely missing something here.

Ah, but wait! The stage 2 translation tables that we’ve analysed above are simply cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial translation tables which are used when RKP boots. Perhaps after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 kernel finishes its initialisation it will somehow request RKP to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se mappings in order to protect its own memory ranges.

Indeed, looking once again at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s initialisation routines, we can see that shortly after booting, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 kernel calls into RKP:

static void rkp_init(void)
{
rkp_init_t init;
init.magic = RKP_INIT_MAGIC;
init.vmalloc_start = VMALLOC_START;
init.vmalloc_end = (u64)high_memory;
init.init_mm_pgd = (u64)__pa(swapper_pg_dir);
init.id_map_pgd = (u64)__pa(idmap_pg_dir);
init.rkp_pgt_bitmap = (u64)__pa(rkp_pgt_bitmap);
init.rkp_map_bitmap = (u64)__pa(rkp_map_bitmap);
init.rkp_pgt_bitmap_size = RKP_PGT_BITMAP_LEN;
init.zero_pg_addr = page_to_phys(empty_zero_page);
init._text = (u64) _text;
init._etext = (u64) _etext;
if (!vmm_extra_mem) {
printk(KERN_ERR"Disable RKP: Failed to allocate extra mem\n");
return;
}
init.extra_memory_addr = __pa(vmm_extra_mem);
init.extra_memory_size = 0x600000;
init._srodata = (u64) __start_rodata;
init._erodata =(u64) __end_rodata;
init.large_memory = rkp_support_large_memory;

rkp_call(RKP_INIT, (u64)&init, 0, 0, 0, 0);
rkp_started = 1;
return;
}

On cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s side we can see that this command provides RKP with many of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory ranges belonging to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. In order to figure out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation of this command, let’s shift our focus back to RKP. By reverse engineering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation of this command within RKP, we arrive at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following approximate high-level logic:

void handle_rkp_init(...) {
   ...
   void* kern_text_phys_start = rkp_get_pa(text);
   void* kern_text_phys_end = rkp_get_pa(etext);
   rkp_debug_log("DEFERRED INIT START", 0, 0, 0);

   if (etext & 0x1FFFFF)
       rkp_debug_log("Kernel range is not aligned", 0, 0, 0);

   if (!rkp_s2_range_change_permission(kern_text_phys_start, kern_text_phys_end, 128, 1, 1))
       rkp_debug_log("Failed to make Kernel range RO", 0, 0, 0);

   ...
}

The highlighted function call above is used in order to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 access permissions for a given PA memory range. Calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se arguments will cause cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 given memory range to be marked as read-only in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation. This means that shortly after booting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 kernel, RKP does indeed lock down write access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code ranges.

...And yet, something’s still missing here. Remember that RKP should not only prevent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code from being modified, but it aims to also prevent attackers from creating new executable code in EL1. Well, while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code is indeed being marked as read-only in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table, does that necessarily prevent us from creating new executable code?

Recall that we’ve previously encountered cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 presence of KASLR, in which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s base address (both in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s VAS and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding physical address) is shifted by a randomised “slide” value. Moreover, since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel assumes that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual to physical offset for kernel addresses is constant, this means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same slide value is used for both virtual and physical addresses.

However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a tiny snag here -- cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address range we examined earlier on, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same one which is marked RWX is both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 and stage 2 translation table, is much larger than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s text segment. This is, partly, in order to allow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel to be placed somewhere within that region after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KASLR slide is determined. However, as we’ve just seen, after choosing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KASLR slide, RKP only protects cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 range spanning from “_text” to “_etext” - that is, only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 region containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s text after applying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 KASLR slide.

kaslr_rwx (1).png

This leaves us with two large regions: [0x80000000, “_text”], [“_etext”, 0x81400000], which are left marked as RWX in both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 and stage 2 translation tables! Thus, we can simply write new code to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se regions and execute it freely within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of EL1, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore bypassing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code loading mitigation. I’ve included a small PoC which demonstrates this issue, here.

Mitigation #3 - Bypassing EL1 Memory Controls


As we’ve just seen in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous section, some of RKP’s stated goals require memory controls that are enforced not only in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation, but also directly in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation used by EL1. For example, RKP aims to ensure that all pages, with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exception of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s code, are marked as PXN. These goals require RKP to have some form of control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation table.

So how exactly does RKP make sure that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se kinds of assurances are kept? This is done by using a combined approach; first, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation tables are placed in a region which is marked as read-only in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation tables. This, in effect, disallows EL1 code from directly modifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation tables cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365mselves. Secondly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel is instrumented (a form of paravirtualisation), in order to make it aware of RKP’s existence. This instrumentation is performed so that each write operation to a data structure used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation process (a PGD, PMD or PTE), will instead call an RKP command, informing it of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requested change.

Putting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two defences togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, we arrive at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 conclusion that all modifications to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation table must cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore pass through RKP which can, in turn, ensure that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y do not violate any of its security goals.

Or do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y?

While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se rules do prevent modification of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation table, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y don’t prevent an attacker from using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory management control registers to circumvent cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se protections. For example, an attacker could attempt to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of TTBR1_EL1 directly, pointing it at an arbitrary (and unprotected) memory address.

Obviously, such operations cannot be permitted by RKP. In order to allow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor to deal with such situations, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “Hypervisor Configuration Register” (HCR) can be leveraged. Recall that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 HCR allows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor to disallow certain operations from being performed under EL1. One such operation which can be trapped is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 modification of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 memory management control registers.


In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case of RKP on Exynos devices, while it does not set HCR_EL2.TRVM (i.e., it allows all read access to memory control registers), it does indeed set HCR_EL2.TVM, allowing it to trap write access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se registers.

So although we’ve established that RKP does correctly trap write access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 control registers, this still doesn’t guarantee cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y remain protected. This is actually quite a delicate situation - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel requires some access to many of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se registers in order to perform regular operations. This means that while some access can be denied by RKP, ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r operations need to be inspected carefully in order to make sure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y do not violate RKP’s safety guarantees, before allowing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to proceed. Once again, we’ll need to reverse engineer RKP’s code to assess cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 situation.

Screenshot from 2017-01-30 01:54:02.png

As we can see above, attempts to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 location of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation tables cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365mselves, result in RKP correctly verifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire translation table, making sure it follows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allowed stage 1 translation policy. In contrast, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are a couple of crucial memory control registers which, at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time, weren’t intercepted by RKP at all - TCR_EL1 and SCTLR_EL1!

Inspecting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se registers in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ARM reference manual reveals that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y both can have profound effects on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation process.

For starters, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 System Control Register for EL1 (SCTLR_EL1) provides top-level control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system, including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory system, in EL1. One bit of crucial importance in our scenario is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SCTLR_EL1.M bit.


This bit denotes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 state of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MMU for stage 1 translation in EL0 and EL1. Therefore, simply by unsetting this bit, an attacker can disable cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MMU for stage 1 translation. Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bit is unset, all memory translation in EL1 map directly to IPAs, but more importantly - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se memory translation do not have any access permissions checks enabled, effectively making all memory ranges considered as RWX in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation. This, in turn, bypasses several of RKP’s assurances, such as making sure that only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s text is not marked as PXN.

As for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Translation Control Register for EL1 (TCR_EL1), it’s effects are slightly more subtle. Instead of completely disabling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 translation’s MMU, this register governs cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way in which translation is performed.


Indeed, observing this register more closely, reveals certain key ways in which an attacker may leverage it in order to circumvent RKP’s stage 1 protections. For example, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AARCH64 memory translation table may assume different formats, depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation granule under which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system is operating. Normally, AARCH64 Linux kernels use a translation granule of 4KB.

This fact is implicitly acknowledged in RKP. For example, when code in EL1 changes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation table (e.g., TTBR1_EL1), RKP must protect this PGD in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation in order to make sure that EL1 cannot gain access to it. Indeed, reversing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corresponding code within RKP reveals that it does just that:

Screenshot from 2017-01-30 01:56:10.png

However, as we can see in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 picture above, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 protection is only performed on a 4KB region (a single page). This is because when using a 4KB translation granule, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation regime has a translation table size of 4KB. However, this is where we, as an attacker, come in. What if we were to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation granule to 64KB, by modifying TCR_EL1.TG0 and TCR_EL1.TG1?


In that case, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation regime’s translation table will now be 64KB as well, as opposed to 4KB under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous regime. Since RKP uses a hard-coded value of 4KB when protecting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 translation table, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bottom 60KB remain unprotected by RKP, allowing an attacker in EL1 to freely modify it in order to point to any IPA, any more crucially, with any access permissions, UXN/PXN values.


Lastly, it should once more be noted that while cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 gadgets needed to access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se registers aren’t abundant in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s image, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are present in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 embedded RKP binary on Exynos devices. Therefore we can simply execute cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se gadgets within EL1 in order to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registers above. I’ve written a small PoC that demonstrates this issue by disabling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 1 MMU in EL1.

Mitigation #4 - Accessing Stage 2 Unmapped Memory


Ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system’s memory, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re exist several ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r memory regions which may contain potentially sensitive information that should not be accessible by code running in EL0 and EL1. For example, peripherals on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SoC may have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir firmware stored in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “Normal World”, in physical memory ranges which should never be accessible to Android itself.

In order to enforce such protections, RKP explicitly unmaps a few memory ranges from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table. By doing so, any attempt to access cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se PA ranges in EL0 or EL1 will result in a translation fault, consequently crashing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel and rebooting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device.

Moreover, RKP’s own memory ranges should also be made inaccessible to lesser privileged code. This is crucial so as to protect RKP from modifications by EL0 and EL1, but also serves to protect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sensitive information that is processed within RKP (such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “cfprop” key). Indeed, after starting up, RKP explicitly unmaps it’s own memory ranges in order to prevent such access:

s2unmap.png

Admittedly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table itself is placed within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very region being unmapped from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore ensuring that code in EL1 cannot modify it. However, perhaps we could find anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r way to control stage 2 mappings, but leveraging RKP itself.

For example, as we’ve previously seen, certain operations such as setting TTBR1_EL1 result in changes to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table. Combing over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RKP binary, we come across one such operation, as follows:

__int64 rkp_set_init_page_ro(unsigned args* args_buffer)
{
 unsigned long page_pa = rkp_get_pa(args_buffer->arg0);
 if ( page_pa < rkp_get_pa(text) || page_pa >= rkp_get_pa(etext) )
 {
   if ( !rkp_s2_page_change_permission(page_pa, 128, 0, 0) )
     return rkp_debug_log("Cred: Unable to set permission for init cred", 0LL, 0LL, 0LL);
 }
 else
 {
   rkp_debug_log("Good init CRED is within RO range", 0LL, 0LL, 0LL);
 }
 rkp_debug_log("init cred page", 0LL, 0LL, 0LL);
 return rkp_set_pgt_bitmap(page_pa, 0);
}

As we can see, this command receives a pointer from EL1, verifies it is not within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s text segment, and if so proceeds to call rkp_s2_page_change_permission in order to modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 access permissions on this range in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation table. Digging deeper into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function reveals that this set of parameters is used to denote cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 region as read-only and XN.

But, what if we were to supply a page that resides somewhere that is not currently mapped in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stage 2 translation at all, such as RKP’s own memory ranges? Well, in this case, rkp_s2_page_change_permission will happily create a translation entry for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 given page, effectively mapping in a previously unmapped region!

This allows us to re-map any stage 2 unmapped region (albeit as read-only and XN) from EL1. I’ve written a small PoC which demonstrates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue by stage 2 re-mapping RKP’s physical address range and reading it from EL1.

Design Improvements to RKP


After seeing some specific issues in this blog post, highlighting how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 different defence mechanisms of RKP could be subverted by an attacker, let’s zoom out for a second and think about some design choices that could serve to strengcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n RKP’s security posture against future attacks.

First, RKP on Exynos devices is currently being bootstrapped by EL1 code. This is in contrast to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 model used on Qualcomm devices, whereby cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL2 code is both verified by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bootloader, and subsequently booted by EL3. Ideally, I believe cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same model used on Qualcomm devices should be adopted for Exynos as well.

Performing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bootstrapping in this order automatically fixes ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r related security issues “for free”, such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 presence of RKP’s binary within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel’s text segment. As we’ve seen, this seemingly harmless fact is in fact very useful for an attacker in several of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 scenarios we’ve highlighted in this post. Moreover, it removes ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r risks such as attackers exploiting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 kernel early in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 boot process and leveraging that access to subvert cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initialisation of EL2.

As in interim improvement, RKP decided to zero out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 RKP binary resident in EL1’s code during initialisation. This improvement will roll out in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next Nougat milestone release of Samsung devices, and addresses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue of attackers leveraging cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary for gadgets. However, it doesn’t address cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue regarding potential early exploitation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL1 kernel to subvert cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initialization of EL2, which requires a more extensive modification.

Second, RKP’s code segments are currently marked as both writable and executable in TTBR0_EL2. This, combined with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fact that SCTLR_EL2.WXN is not set, allows an attacker to use any memory corruption primitive in EL2 in order to directly overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EL2 code segments, allowing for much easier exploitation of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypervisor.

While I have not chosen to include cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se issues in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 blog post, I’ve found several memory corruptions, any of which could be used to modify memory within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of RKP. Combining cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two facts togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, we can conclude that any of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se memory corruptions could be used by an attacker to directly modify RKP’s code itself, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore gaining code execution within it.

Simply setting SCTLR_EL2.WXN and marking RKP’s code as read-only would not prevent an attacker from gaining access to RKP, but it could make exploitation of such memory corruptions harder to exploit and more time consuming.

Third, RKP should lock down all memory control registers, unless cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y absolutely must be used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Linux kernel. This would prevent abuse of several of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se registers which may subtly affect cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system’s behaviour, and in doing so, violate assumptions made by RKP about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel. Where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se registers have to be modified by EL1, RKP should verify that only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 appropriate bits are accessed.

RKP has since locked down access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two registers mentioned in this blog post. This is a good step in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right direction, and unfortunately as access to some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se registers must be retained, simply revoking access to all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m is not a feasible solution. As such, preventing access to ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r memory control registers remains a long term goal.

Lastly, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re should be some distinction between stage 2 unmapped regions that were simply never mapped in, and those which were explicitly mapped out. This can be achieved by storing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory ranges corresponding to explicitly unmapped regions, and disallowing any modification that would result in remapping cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m within RKP. While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue I highlighted is now fixed, implementing this extra step would prevent furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r similar issues from cropping up in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 future.