Monday, February 9, 2015

A Token’s Tale

Posted by James Forshaw currently impersonating NT AUTHORITY\SYSTEM.


Much as I enjoy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process of vulnerability research sometimes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a significant disparity between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 difficulty of finding a vulnerability and exploiting it. The Project Zero blog contains numerous examples of complex exploits for seemingly trivial vulnerabilities. You might wonder why we’d go to this level of effort to prove exploitability, surely we don’t need to do so? Hopefully by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of this blog post you’ll have a better understanding of why it’s often cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case we spend a significant effort to demonstrate a security issue by developing a working proof of concept.

Our primary target for a PoC is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r benefits for developing one. A customer of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor’s system can use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC to test whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re vulnerable to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue and ensure any patch has been correctly applied. And cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security industry can use it to develop mitigations and signatures for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability even if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor is not willing or able to patch. Without cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC being made available only people who reverse engineer cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch are likely to know about it, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y might not have your best interests in mind.

I don’t want this blog post to get bogged down in too much technical detail about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug (CVE-2015-0002 for reference). Instead I’m going to focus on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process of taking that relatively simple vulnerability, determining exploitability and developing a PoC. This PoC should be sufficient for a vendor to make a reasonable assessment of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 presented vulnerability to minimize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir triage efforts. I’ll also explain my rationale for taking various shortcuts in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC development and why it has to be so.

Reporting a Vulnerability

One of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 biggest issues with vulnerability research on closed or proprietary systems is dealing with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 actual reporting process to get a vulnerability fixed. This is especially cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case in complex or non-obvious vulnerabilities. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system is open source, I could develop a patch, submit it and it stands a chance of getting fixed. For a closed source system I will have to go through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process of reporting. To understand this better let’s think about what a typical large vendor might need to do when receiving external security vulnerability reports.

Vendor Vulnerability Response.png

This is a really simplified view on vulnerability response handling but it’s sufficient to explain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 principles. For a company which develops cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 majority of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir software internally I would have little influence over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patching cycle, but I can make a difference in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 triage cycle. The easier I can make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor’s life cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shorter cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 triage cycle can be and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 quicker we can get a patch released. Everyone wins, except hopefully cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 people who might be using this vulnerability already. Don’t forget just because I didn’t know about this vulnerability before doesn’t mean it isn’t already known about.

In an ideal vulnerability research world (i.e. one in which I have to do cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 least amount of non-research work) if I find a bug all I’d need to do is write up some quick notes about it, send it to a vendor, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’ll understand cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’ll immediately move heaven and earth to develop cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch, job done. Of course it doesn’t work that way, sometimes just getting a vendor to recognize cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s even a security issue is an important first step. There can be a significant barrier between moving from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 triage cycle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch cycle, especially as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’re usually separate entities inside a company. To provide for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best chance possible I’ll do two things:

  1. Put togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a report of sufficient detail so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor understands cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability
  2. Develop a PoC which unequivocally demonstrates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security impact

Writing up a Report

Writing up a report for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor is pretty crucial to getting an issue fixed, although it isn’t sufficient in many cases. You can imagine if I wrote something like, “Bug in ahcache.sys, fixit, *lol*” that doesn’t really help cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor much. At cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very least I’d want to provide some context such as what systems cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability affects (and doesn’t affect), what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impact of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability is (to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best of my knowledge) and what area of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue resides.

Why wouldn’t just cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 report be sufficient? Think about how a large modern software product is developed. It’s likely developed between a team of people who might work on individual parts. Depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 age of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable code cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original developer might have moved on to ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r projects, left cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 company entirely or been hit by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number 42 bus. Even if it’s relatively recent code written by a single person who’s still around to talk to it doesn’t mean cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y remember how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code works. Anyone who’s developed software of any size will have come across code cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y wrote, a month, week or even a day ago and wondered how it works. There’s a real possibility that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security researcher who’s spent time going through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executable instruction by instruction might know it better than anyone in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 world.

Also you can think about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 report in a scientific sense, it’s your vulnerability hypocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sis. Some vulnerabilities can be proven, for example a buffer overflow can typically be proven macá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365matically, placing 10 things into space for 5 doesn’t work. But in many cases cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s nothing better than empirical proof of exploitability. If done right it can be experimentally validated by both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reporter and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor, this is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of a proof-of-concept. Correctly developed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor can observe cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 effects of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 experiment, converting my hypocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sis to a cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ory which no-one can disprove.

Proving Exploitability through Experimentation

So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hypocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365sis posits that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability has a real-world security impact, we’ll prove it objectively using our PoC. In order to do this we need to provide cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor not just with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mechanism to prove that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability is real but also clear observations that can be made and why those observations constitute a security issue.

What observations need to be made depend on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type of vulnerability. For memory corruption vulnerabilities it might be sufficient to demonstrate an application crashing in response to certain input. This isn’t always cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case, some memory corruptions don’t provide cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker any useful control. Therefore demonstrating control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current execution flow, such as controlling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 EIP register is usually cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ideal.

For logical vulnerabilities it might be more nuanced, such as you can write a file to a location you shouldn’t be able to or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 calculator application ends up running with elevated privileges. There’s no one-size-fits-all approach, however at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 very least you want to demonstrate some security impact which can be observed objectively.

The thing to understand is I’m not developing a PoC for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 purposes of being a useful exploit (from an attacker perspective) but to prove it’s a security issue to a sufficient level of confidence that it will get fixed. Unfortunately it isn’t always easy to separate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two aspects and sometimes without demonstrating local privilege escalation or remote code execution it isn’t taken as seriously as it should be.

Developing a Proof of Concept

Now let’s go into some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 challenges I faced in developing a PoC for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ahcache vulnerability I identified. Let’s not forget cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a trade off between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time spent developing a PoC and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chance of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability being fixed. If I don’t spend enough time to develop a working PoC cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor could turn around and not fix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability, on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r hand cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 more time I spend cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 longer this vulnerability exists which is potentially as bad for users.

Vulnerability Technical Details

Having a bit of understanding of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability will help us frame cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 discussion later. You can view cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue here with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attached PoC that I sent to Microsoft. The vulnerability exists in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ahcache.sys driver which was introduced in Windows 8.1 but in essence this driver implements cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows native system call NtApphelpCacheControl. This system call handles a local cache for application compatibility information which is used to correct application behaviour on newer versions of Windows. You can read more about application compatibility here.

Some operations of this system call are privileged so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver does a check of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current calling application to ensure cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have administrator privileges. This is done in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function AhcVerifyAdminContext which looks something like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following code:

BOOLEAN AhcVerifyAdminContext()
{
   BOOLEAN CopyOnOpen;
   BOOLEAN EffectiveOnly;
   SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;

   PACCESS_TOKEN token = PsReferenceImpersonationToken(
           NtCurrentThread(),
           &CopyOnOpen,
           &EffectiveOnly,
           &ImpersonationLevel);
   if (token == NULL) {
       token = PsReferencePrimaryToken(NtCurrentProcess());
   }
   PSID user = GetTokenUser(token);

   if(RtlEqualSid(user, LocalSystemSid) || SeTokenIsAdmin(token)) {
       return TRUE;
   }

   return FALSE;
}

This code queries to see if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current thread is impersonating anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r user. Windows allows a thread to pretend to be someone else on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system so that security operations can be correctly evaluated. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 thread is impersonating a pointer to an access token is returned. If NULL is returned from PsReferenceImpersonationToken cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code queries for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current process’ access token. Finally cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code checks whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 access token’s user is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 local system user or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token is a member of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Administrators group. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 function returns TRUE cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 privileged operation is allowed to go ahead.

This all seems fine, so what’s cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue? While full impersonation is a privileged operation limited to users which have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impersonate privilege in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir token, a normal user without cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 privilege can impersonate ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r users for non-security related functions. The kernel differentiates between privileged and unprivileged impersonation by assigning a security level to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token when impersonation is enabled. To understand cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s only two levels of interest, SecurityImpersonation which means cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impersonation is privileged and SecurityIdentification which is unprivileged.

If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token is assigned SecurityIdentification only operations such as querying for token information, such as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token’s user is allowed. If you try and open a secured resource such as a file cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel will deny access. This is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 underlying vulnerability, if you look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PsReferenceImpersonationToken returns a copy of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security level assigned to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token, however cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code fails to verify it’s at SecurityImpersonation level. This means a normal user, who was able to get hold of a Local System access token could impersonate at SecurityIdentification and still pass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 check as querying for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user is permitted.

Proving Trivial Exploitation

Exploiting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug requires capturing a Local System access token, impersonating it and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system call with appropriate parameters. This must be achievable from normal user privilege ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rwise it isn’t a security vulnerability. The system call is undocumented so if we wanted to take a shortcut could we just demonstrate that we can capture cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token and leave it at that?

Well not really, what this PoC would demonstrate is that something which is documented as possible is indeed possible. Namely that it’s possible from a normal user to capture cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 token and impersonate it, as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impersonation system is designed this would not cause a security issue. I knew already that COM supports impersonation, that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a number of complex system privileged services (for example BITS) we can communicate with as a normal user that we could convince to communicate back to our application in order to perform cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 impersonation. This wouldn’t demonstrate that we can even reach cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable AhcVerifyAdminContext method in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel let alone successfully bypass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 check.

So starts cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 long process of reverse engineering to work out how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system call works and what parameters you need to pass to get it to do something useful. There’s some existing work from ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r researchers (such as this) but certainly nothing concrete to take forward. The system call supports a number of different operations, it turned out that not all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operations needed complex parameters. For example cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AppHelpNotifyStart and AppHelpNotifyStop operations could be easily called, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y relied on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 AhcVerifyAdminContext function. I could now produce a PoC which we can verify bypasses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 check by observing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system call’s return code.

BOOL IsSecurityVulnerability() {
ImpersonateLocalSystem();

NTSTATUS status = NtApphelpCacheControl(AppHelpNotifyStop, NULL);

return status != STATUS_ACCESS_DENIED;
}

Is this sufficient to prove exploitability? History has taught me no, for example this issue has almost cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exact same sort of operation, namely you can bypass an administrator check through impersonation. In this case I couldn’t produce sufficient evidence that it was exploitable for anything ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than information disclosure. So in turn it was not fixed, even though it was effectively a security issue. To give ourselves cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best chance of proving exploitability we need to spend more time on this PoC.

Improving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Proof-of-Concept

In order to improve upon cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first PoC I would need to get a better understanding of what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system call is doing. The application compatibility cache is used to store cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lookup data from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 application compatibility database. This database contains rules which tell cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 application compatibility system what executables to apply “shims” to in order implement custom behaviours, such as lying about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 operating system’s version number to circumvent an incorrect check. The lookup is made every time a process is created, if a suitable matching entry is found it’ll be applied to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new process. The new process will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n lookup cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shim data it needs to apply from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 database.

Application Compatibility no cache.png
As this occurs every time a new process is created cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a significant performance impact in going to database file every time. The cache is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re to reduce this impact, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 database lookup can be added to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cache. If that executable is created later cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cached lookup can quickly eliminate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 expensive database lookup and eicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r apply a set of shims or not.

Application Compatibility (1).png

Therefore we should be able to cache an existing lookup and apply it to an arbitrary executable. So I spent some time working out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 format of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parameters to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system call in order to add my own cached lookup. The resulting structure for Windows 8.1 32 bit looked like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following:

struct ApphelpCacheControlData {
       BYTE           unk0[0x98];
       DWORD          query_flags;
       DWORD          cache_flags;
       HANDLE         file_handle;
       HANDLE         process_handle;
       UNICODE_STRING file_name;
       UNICODE_STRING package_name;
       DWORD          buf_len;
       LPVOID         buffer;
       BYTE           unkC0[0x2C];
       UNICODE_STRING module_name;
       BYTE           unkF4[0x14];
};

You can see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s an awful lot of unknown parts in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure. This causes a problem if you were to apply this to Windows 7 (which has a slightly different structure) or 64 bit (which has a different sized structure) but for our purposes it doesn’t matter. We’re not supposed to be writing code to exploit all versions of Windows, all we need to do is prove cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 security issue to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor. As long as you inform cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vendor of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC limitations (and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y pay attention to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m) we can do this. The vendor’s still better placed to determine if this PoC proves exploitability across versions of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 OS, it’s cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir product after all.

So I could now add an arbitrary cached entry but what can we actually add? I could only add an entry which would have been cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result of an existing lookup. You could modify cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 database to do something like patch running code (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 application compatibility system is also used for hotfixes) but that would require administrator privileges. So I needed an existing shim to repurpose.

I built a copy of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SDB explorer tool (available from here) so that I could dump cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 existing database looking for any useful existing shim. I found that for 32 bit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a shim which will cause a process to start cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executable regsvr32.exe passing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original command line. This tool will load a DLL passed on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command line and execute specific exported methods, if we could control cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command line of a privileged process we could redirect it and elevate privileges.

AppCompat Regsvr32 (3).png
This again limits cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC to only 32 bit processes but that’s fine. The final step, and what caused a lot of confusion was what process to choose to redirect. I could have spent a lot of time investigating ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r ways of achieving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 requirement of starting a process where I control cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 command line. I already knew one way of doing it, UAC auto elevation. Auto elevation is a feature added to Windows 7 to reduce cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number of UAC dialogs a typical user sees. The OS defines a fixed list of allowed auto elevating applications, when UAC is at it’s default setting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n requests to elevate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se applications do not show a dialog when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user’s an administrator. I can abuse this by applying a cache entry for an existing auto elevating application (in this case I chose ComputerDefaults.exe) and requesting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 application runs elevated. This elevated application redirects to regsvr32 passing our fully controlled command line, regsvr32 loads my DLL and we’ve now got code executing with elevated privileges.

The PoC didn’t give someone anything cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y couldn’t already do through various ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r mechanisms (such as this metasploit module) but it was never meant to. It sufficiently demonstrated cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue by providing an observable result (arbitrary code running as an administrator), from this Microsoft were able to reproduce it and fix it.

Final Bit of Fun


As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was some confusion on whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r this was only a UAC bypass I decided to spend a little time to develop a new PoC which gets local system privileges without any reliance on UAC. Sometimes I enjoy writing exploits, if only to prove that it can be done. To convert cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original PoC to one which gets local system privileges I need a different application to redirect. I decided cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most likely target was a registered scheduled task as you can sometimes pass arbitrary arguments to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task handler process. So we’ve got three criteria for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ideal task, a normal user must be able to start it, it must result in a process starting as local system and that process must have an arbitrary command line specified by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user. After a bit of searching I found cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ideal candidate, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Windows Store Maintenance Task. As we can see if runs as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 local system user.

wstask.PNG

We can determine that a normal user can start it by looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task file’s DACL using a tool such as icacls. Notice cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entry in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following screenshot for NT AUTHORITY\Aucá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365nticated Users with Read and Execute (RX) permissions.

dacl.PNG

Finally we can check whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a normal user can pass any arguments to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task by checking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 XML task file. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case of WSTask it uses a custom COM handler, but allows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 user to specify two command line arguments. This results in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 executable c:\windows\system32\taskhost.exe executing with an arbitrary command line as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 local system user.

task_xml.PNG

It was just a case of modifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC to add a cache entry for taskhost.exe and start cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 task with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 path to our DLL. This still has a limitation, specifically it only works on 32 bit Windows 8.1 (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s no 32 bit taskhost.exe on 64 bit platforms to redirect). Still I’m sure it can be made to work on 64 bit with a bit more effort. As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability is now fixed I’ve made available cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new PoC, it’s attached to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original issue here.

Conclusions

I hope I’ve demonstrated some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 effort a vulnerability researcher would go to in order to ensure a vulnerability will be fixed. It’s ultimately a trade off between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time spent developing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chances of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability being fixed, especially when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability is complex or non-obvious.

In this case I felt I made cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right trade-off. Even though cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC I sent to Microsoft looked, on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 surface to only be a UAC bypass combined with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 report cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y were able to determine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 true severity and develop cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch. Of course if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’d pushed back and claimed it was not exploitable cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n I would have developed a more robust PoC. As a furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r demonstration of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 severity I did produce a working exploit which gained local system privileges from a normal user account.

Disclosing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC exploit is of value to aid in a user’s or security company’s mitigation of a public vulnerability. Without a PoC it’s quite difficult to verify that a security issue has been patched or mitigated. It also helps to inform researchers and developers what types of issues to look out for when developing certain security sensitive applications. Bug hunting is not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sole approach for Project Zero to help secure software, education is just as important.

Project Zero’s mission involves tackling software vulnerabilities, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 development of PoCs can be an important part of our duty to help software vendors or open source projects take informed action to fix vulnerabilities.

Thursday, January 22, 2015

Exploiting NVMAP to escape cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Chrome sandbox - CVE-2014-5332

Posted by Lee Campbell, Graphics Pwning Unit


[This guest post continues Project Zero’s practice of promoting excellence in security research on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Project Zero blog]

Background:

  • Chrome for Android implements a very different sandbox model to that of Chrome for Linux. One of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 platform features we make use of is enabled with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 android:isolatedProcess attribute on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tag in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 app manifest. The docs say:
android:isolatedProcess
If set to true, this service will run under a special process that is isolated from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system and has no permissions of its own. The only communication with it is through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Service API (binding and starting).
  • Under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 covers this places cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 specified Android Service into a more restrictive SELinux policy and is what Chrome uses for its renderer processes. All is good so far.
  • Back in September I decided to take a look at how ‘isolated’ this isolatedProcess actually is, and specifically look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel attack surface.
  • As it turns out access to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GPU drivers is not blocked and this blog is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 story of exploiting Nvidia’s NVMAP driver on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Nexus 9...

What is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NVMAP driver?

  • It’s used for GPU memory management on Nvidia’s Tegra chipsets. It’s used in many Android devices and more recently Chromebooks.
  • You can find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 driver code used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Arm64 Nexus 9 here and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fix is here.
  • Nvidia were very responsive and released an upstream fix within a matter of days—cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have recently released cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir bulletin CVE-2014-5332.

Some internals:

  • The entry point is /dev/nvmap with rw-rw-rw- permissions making it accessible by all.
  • There are a number of IOCTLs used to control this driver and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y’ll be our focus for exploitation.

NVMAP_IOC_CREATE:

  • This ioctl is used to create handles and returns a file descriptor.
  • Handles are allocated globally and stored in struct nvmap_handle.
struct nvmap_handle {
struct rb_node node; /* entry on global handle tree */
atomic_t ref; /* reference count (i.e., # of duplications) */
atomic_t pin; /* pin count */
u32 flags; /* caching flags */
...


  • Local client references are maintained by this struct:
struct nvmap_handle_ref {
struct nvmap_handle *handle;
struct rb_node node;
atomic_t dupes; /* number of times to free on file close */
atomic_t pin; /* number of times to unpin on free */
};

  • The following code is used to create this structure and allocate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file descriptor.
int nvmap_ioctl_create(struct file *filp, unsigned int cmd, void __user *arg)
{
struct nvmap_create_handle op;
struct nvmap_handle_ref *ref = NULL;
struct nvmap_client *client = filp->private_data;
int err = 0;
int fd = 0;

if (copy_from_user(&op, arg, sizeof(op)))
return -EFAULT;

if (!client)
return -ENODEV;

if (cmd == NVMAP_IOC_CREATE) {
ref = nvmap_create_handle(client, PAGE_ALIGN(op.size));
if (!IS_ERR(ref))
ref->handle->orig_size = op.size;
} else if (cmd == NVMAP_IOC_FROM_ID) {
ref = nvmap_duplicate_handle(client, unmarshal_id(op.id), 0);
} else if (cmd == NVMAP_IOC_FROM_FD) {
ref = nvmap_create_handle_from_fd(client, op.fd);
} else {
return -EINVAL;
}

if (IS_ERR(ref))
return PTR_ERR(ref);

fd = nvmap_create_fd(client, ref->handle);
if (fd < 0)
err = fd;
//POINT A
op.handle = fd;

if (copy_to_user(arg, &op, sizeof(op))) { //POINT B
err = -EFAULT;
nvmap_free_handle(client, __nvmap_ref_to_id(ref));
}

if (err && fd > 0)
sys_close(fd);
return err;
}
  • On successful completion cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle->ref count is 2: one reference held by our client, and one reference held by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA subsystem that provided cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file descriptor in nvmap_create_fd. This call always returns fd’s starting at 1024, so we can predict cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m.
  • When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fd returned by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ioctl is closed by user-space cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA subsystem releases its reference. When cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fd to /dev/nvmap is closed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client releases its reference. Once cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference count equals zero cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle structure is free’ed.

The bug:

  • If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 copy_to_user at point B were to fail cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n nvmap_free_handle will destroy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client reference and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle->ref count will drop to 1.
  • sys_close will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be called on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fd and this will release cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA reference, reducing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle->ref count to 0 and freeing it.
  • This is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct operation and no resources are leaked.
  • However, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 copy_to_user can be forced to fail by providing a userspace address in Read-Only memory, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 client reference will always be free’ed.
  • Unfortunately a race condition exists at point A where a second user thread can dup(1024) and acquire anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r handle to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA subsystem. Recall fd’s are allocated predictably starting at 1024. This is an easy race to win!
  • The function will continue to call sys_close and return failure. sys_close in this case will not release cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 DMA reference as user-space now has anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r handle.

Ok that’s great, what now?

  • When operating correctly, two references are held to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle. Due to triggering cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 race above, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is now only one.
  • This is a nice state for an attacker as userspace now has a reference to a handle that it can free asynchronously at any time, e.g., during anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r ioctl call.
  • To trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 free’ing of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle struct, userspace can call close() on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dup’ed fd.

So now we can free on demand, can we break stuff?

  • This is tricky, we need to win more races. ;-)
  • The ioctl calls take cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fd as a reference to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle. In this case cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dup’ed fd can be used to perform operations on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel.
  • Here is an example ioctl:
int nvmap_ioctl_getid(struct file *filp, void __user *arg)
{
struct nvmap_create_handle op;
struct nvmap_handle *h = NULL;
if (copy_from_user(&op, arg, sizeof(op)))
return -EFAULT;
h = unmarshal_user_handle(op.handle); //POINT C
if (!h)
return -EINVAL;
h = nvmap_handle_get(h); //POINT D

if (!h)
return -EPERM;
op.id = marshal_id(h);
nvmap_handle_put(h); //POINT E
return copy_to_user(arg, &op, sizeof(op)) ? -EFAULT : 0;
}

  • Most ioctl’s follow this pattern:
    • unmarshal_user_handle - to convert cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fd to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle
    • nvmap_handle_get - this grabs a reference, incrementing handle->ref
    • Do some work
    • nvmap_handle_put - this drops cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reference, decrementing handle->ref
  • Although userspace can now asynchronously (in anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r thread) decrement cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle->ref count and cause a free by calling close cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is only a small window to do this.
  • At point C cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle must be valid and close can not be called before this point (or NULL will be returned)
  • At point D anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r reference is taken on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle and calling close will not decrement cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 count to zero, so handle will not be free’ed until point E.
  • So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only place corruption can occur is if userspace frees cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle between points C and D. This race is much more tricky to win as very little happens between cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se two points.
  • Its made harder as to advance this exploit an attacker not only needs to free cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle but also needs to allocate something controllable in its space. As a result most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ioctls do not provide enough time between unmarshal_user_handle and nvmap_handle_get to set up an exploitable condition.

NVMAP_IOC_RESERVE to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rescue:
  • There is only one viable ioctl where I could generate enough time to create an exploitable condition. The IOC_RESERVE ioctl can be seen here (lots of checks removed for clarity):
int nvmap_ioctl_cache_maint_list(struct file *filp, void __user *arg,
bool is_reserve_ioctl)
{
struct nvmap_cache_op_list op;
u32 *handle_ptr;
u32 *offset_ptr;
u32 *size_ptr;
struct nvmap_handle **refs;
int i, err = 0;

if (copy_from_user(&op, arg, sizeof(op)))
return -EFAULT;
refs = kcalloc(op.nr, sizeof(*refs), GFP_KERNEL);

if (!refs)
return -ENOMEM;

handle_ptr = (u32 *)(uintptr_t)op.handles;
offset_ptr = (u32 *)(uintptr_t)op.offsets;
size_ptr = (u32 *)(uintptr_t)op.sizes;

for (i = 0; i < op.nr; i++) {
u32 handle;

if (copy_from_user(&handle, &handle_ptr[i], sizeof(handle))) {
err = -EFAULT;
goto free_mem;
}

refs[i] = unmarshal_user_handle(handle); //POINT F
if (!refs[i]) {
err = -EINVAL;
goto free_mem;
}
}
if (is_reserve_ioctl) //POINT G
err = nvmap_reserve_pages(refs, offset_ptr, size_ptr,
 op.nr, op.op);
free_mem:
kfree(refs);
return err;
}
  • In this ioctl unmarshal_user_handle is in a loop (point F), which must be completed before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handles are used at point G.
  • The iteration count, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time spent in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop, is user-controlled. This can be made fairly large (around 4k) to provide enough time to set up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack.
  • ref[0] is set to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dup’ed fd. The rest of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 refs[] are set to point anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r fully valid fd (created without cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dup race). They can all be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same.
  • While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 loop spins ref[0] can be free’ed in anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r thread at point G. Now we have a stale pointer that is about to be used!
  • nvmap_reserve_pages is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n called and is shown here:
int nvmap_reserve_pages(struct nvmap_handle **handles, u32 *offsets, u32 *sizes,
u32 nr, u32 op)
{
int i;
for (i = 0; i < nr; i++) {
u32 size = sizes[i] ? sizes[i] : handles[i]->size;
u32 offset = sizes[i] ? offsets[i] : 0;

if (op == NVMAP_PAGES_RESERVE)
nvmap_handle_mkreserved(handles[i], offset, size);
else
nvmap_handle_mkunreserved(handles[i],offset, size);
}
if (op == NVMAP_PAGES_RESERVE)
nvmap_zap_handles(handles, offsets, sizes, nr);
return 0;
}
  • By setting op != NVMAP_PAGES_RESERVE nvmap_handle_mkunreserved is called on each handle. This is a NoOp for all handles except handle[0] which has been free’ed.
  • nvmap_handle_mkunreserved is shown here along with its helper functions:


static inline void nvmap_handle_mkunreserved(struct nvmap_handle *h,
    u32 offset, u32 size)
{
nvmap_handle_mk(h, offset, size, nvmap_page_mkunreserved);
}


static inline void nvmap_page_mkunreserved(struct page **page)
{
*page = (struct page *)((unsigned long)*page & ~2UL);
}

static inline void nvmap_handle_mk(struct nvmap_handle *h,
  u32 offset, u32 size,
  void (*fn)(struct page **))
{
int i;
int start_page = PAGE_ALIGN(offset) >> PAGE_SHIFT;
int end_page = (offset + size) >> PAGE_SHIFT;
if (h->heap_pgalloc) {
for (i = start_page; i < end_page; i++)
fn(&h->pgalloc.pages[i]);
}
}

  • This code uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer h->pgalloc.pages stored in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle struct. This points to an array of pointers. This array is iterated through and bit two of each pointer is cleared.
  • start_page and end_page are user controlled so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 number of pages can be controlled and easily set to one.
  • As cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handle has been free’ed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a momentary opportunity to allocate attacker controlled data in its place and control h->pgalloc.pages
  • This would allow an attacker to clear bit 2 of any word in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system. A lot of work for a single bit clear but I’ll take it :)

Heap groom:
  • The handle struct is 224 bytes and is allocated with kzalloc. This puts it in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 256-kmalloc heap.
  • An attacker needs to find something that allocates quicky, is around 256 bytes long and has controllable content.
  • Seccomp-bpf provides such a facility in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 form of seccomp-bpf programs (or filters). I picked seccomp as I use it a lot, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are many ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r things in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel you could pick.
  • Allocating a filter (sized around 256 bytes) at point G will hopefully reallocate over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 free’ed handle struct.
  • The filter is invalid so it is immediately free’ed by seccomp-bpf  but its contents will remain long enough for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attack to succeed.
  • So now we control cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pointer to a single bit clear!

What bit to clear?
  • We now need to find a single bit in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel that will provide privilege escalation.
  • Arm64 does not protect its kernel text sections and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are writable by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel itself. As such cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 kernel can modify its own code. So I looked for a nice instruction to modify.
  • Here is a partial disassembly of setuid (Arm64 on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Nexus 9)
ffffffc0000c3bcc:       528000e0        mov     w0, #0x7
ffffffc0000c3bd0:       f9400821        ldr     x1, [x1,#16]
ffffffc0000c3bd4:       f9424034        ldr     x20, [x1,#1152]
ffffffc0000c3bd8:       97ffcd8f        bl      ffffffc0000b7214
ffffffc0000c3bdc:       53001c00        uxtb    w0, w0 //Point H
ffffffc0000c3be0:       35000280        cbnz    w0, ffffffc0000c3c30//POINT I
ffffffc0000c3be4:       b9400680        ldr     w0, [x20,#4]
ffffffc0000c3be8:       6b0002bf        cmp     w21, w0

and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 C version:
SYSCALL_DEFINE1(setuid, uid_t, uid)
{
// [.....]
retval = -EPERM;
if (nsown_capable(CAP_SETUID)) { //POINT J
new->suid = new->uid = kuid;
if (!uid_eq(kuid, old->uid)) {
retval = set_user(new);
if (retval < 0)
goto error;
}
} else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) {
goto error;
}
// [....]
return commit_creds(new);
error:
abort_creds(new);
return retval;
}

  • If we can make cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 condition at point J return non-zero cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it would be as if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 processes has CAP_SETUID and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker could call setuid(0) and elevate to root.
  • The asm code at point H is where this condition is evaluated.
  • uxtb w0,w0 just extends cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 byte value in w0 to a full word and stores it back in w0
  • At point I cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 branch is taken if w0 is non-zero, this is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 branch cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker would like to take to gain privilege.
  • The byte code for uxtb w0,w0 is 0x53001c00. Using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 clear bit primitive from above we can change this word to 0x51001c00.
  • This results in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new instruction sub w0,w0,#7.
  • Now w0 will contain cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 non-zero value -7 and it will appear as if CAP_SETGID is set.
  • Now we just call setuid(0) and we are root.
  • Easy as that!

Winning cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 race:
  • There are a number of races in this attack and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 probability of success (i.e., cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m all landing perfectly) is quite low. That said, a lose is non-fatal (for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most part) so an attacker can just keep trying until setuid(0) returns success.
  • On a real system this attack takes many thousands of attempts but usually gains root in less than 10 seconds.