mitigations' property='og:title'/>

Wednesday, August 19, 2015

Three bypasses and a fix for one of Flash's Vector.<*> mitigations

Posted by Chris Evans, Cookie Monster

With cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 release of Flash 18.0.0.209, two mitigations were introduced to combat abuse of Vector corruptions -- we covered cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se in a previous blog post. Flash 18.0.0.232 has just been released and it includes a change to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigations is implemented, to address Project Zero bug 482.

This blog post notes some ways to bypass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way Adobe implemented cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector.<*> length checking mitigation. They are already fixed. It’s not uncommon for new mitigations to go through some iterations to strengcá 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ý bet365m after initial release and scrutiny. This blog post will cover cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigation used to work, three possible bypasses of this mitigation, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fix deployed.

How did cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector.<*> mitigation work?
The mitigation worked by using a secret cookie to XOR into a copy of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length field. This XOR’ed value should not be guessable by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker, and it is checked whenever cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length is used. Therefore, length corruptions should be trapped reliably at runtime.

All of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bypasses stem from where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie used to be stored. Let’s dig through a running Chrome Linux x64 process to show how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie used to be stored. For convenience, we allocate a 512MB Vector. object. It’s sufficiently large that it will get its own mapping, making it easy to find in /proc//maps:

16748d5a8000-1674ad8a8000 rw-p 00000000 00:00 0

We also set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first value in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector. to be 0xf2f2f2f2, meaning we can search memory to find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 header that precedes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data:

(gdb) find/w 0x16748d5a8000,0x1674ad8a8000,0xf2f2f2f2
0x16748d6a8018

So now we can dump cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object’s header and first couple of data entries:

(gdb) x/8xw 0x16748d6a8000
0x16748d6a8000: 0x07ffff83 0x07ffff83 0xfd0c714d 0x00000000
0x16748d6a8010: 0xda146000 0x000007d7 0xf2f2f2f2 0x00000000

0x7ffff83 appears twice, and represents cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 capacity of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector. The third 32-bit value is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length XOR’ed with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie. We can calculate 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 secret cookie with an additional XOR operation on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 XOR’ed length:

(gdb) p/x 0x07ffff83 ^ 0xfd0c714d
$4 = 0xfaf38ece

It’s worth noting that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to calculate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cookie in this way isn’t considered a “bypass”. The mitigation is attempting to prevent a blind buffer overflow from being turned into a read primitive (and thus bypassing ASLR). If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker already has a read primitive and can read cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length and XOR’ed length values, 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ý bet365y already have an ASLR defeat.

But -- here is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interesting part -- cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie that is checked against is stored inside a structure that is pointed to by a pointer at offset 0x10 of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 header we dumped out above. We can demonstrate that like this:

(gdb) find/w 0x7d7da146000,0x7d7da147000,0xfaf38ece
0x7d7da146c68

We see that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie is stored at offset 0xc68 into a large structure.

What are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 three bypasses?
All three bypasses stem from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fact that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie value is fetched from a pointer in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector header. The attacker that is trying to corrupt a Vector length can of course corrupt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 entire Vector header. With cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same buffer overflow, it is possible to corrupt all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se things at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same time:

  • The length of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector (len).
  • The length of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector XOR’ed with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie (lenXOR).
  • The pointer from which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie is fetched (ptr).

The validation employed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigation is effectively:

assert(len ^ lenXOR == ptr->cookie)

Unfortunately, a buffer overflow gives cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker control of all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 variables in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 above validation, enabling at least a cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365oretical bypass. To bypass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigation successfully, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker has to forge a value of ptr which points to predictable content in order to gain control of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie value. Of course, with good ASLR, knowing where something is in memory is supposed to be hard. The bypasses cover various different tricks to defeat ASLR in order to reliably forge a secret cookie value.

Bypass #1: Heap spraying
This is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 least sophisticated bypass because it relies on allocating large amounts of memory and is also only realistically feasible in a 32-bit address space. Above we used cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 phrase “good ASLR” and it is debateable whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r “good ASLR” is possible at all in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser context for 32-bit processes, but we include this bypass for completeness and because in practice it is practical.

The bypass is fairly simple: allocate e.g. 1GB of memory, perhaps with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ByteArray class. This will result in a 1GB contiguous allocation filled with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 NUL byte. It is not possible to guess cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 start address of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation, but due to restrictions in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32-bit address space, it is possible to very reliably guess an address that will mostly always be somewhere within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation. We can overwrite ptr above with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 guessed address, leading to a ptr->cookie value of zero. With a known cookie value, we have defeated cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigation.

Bypass #2: User Shared Data and vsyscall
Of course, a good bypass will work on 64-bit systems. This second bypass was first demonstrated on Windows 8.1 x64. It relies on a quirk of Windows ASLR where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re unfortunately exists a mapping called User Shared Data that is at a fixed address in Windows processes. This mapping has a long history of abuse, including in a Pwnium 2 use-after-free exploit. In older Windows operating systems, User Shared Data contained function pointers, making it very dangerous to have at a fixed address. In Windows 8.1, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is only read-only data and no pointers, but it is still a violation of good ASLR to have any mapping at a fixed address.

To abuse User Shared Data to bypass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cookie, we simply need to observe that it is one page of data, and is zero-filled at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 higher addresses in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page. Therefore, by setting ptr to be User Shared Data (0x7ffe0000), ptr->cookie is zero and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret validation value we need for a given length becomes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length.

To visualize how a buffer overflow would really go about this bypass, we can look at how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector header in memory would look both before and after a buffer overflow. Before:

       0x07ffff83      0x07ffff83      0x8b6fd5d7      0x00000000
       0x86f53000      0x00003d3c      0xf2f2f2f2      0x00000000

And after, with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bytes modified by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 linear buffer overflow colored in red:

       0x07ffff84      0x07ffff84      0x07ffff84      0x00000000
       0x7ffe0000      0x00000000      0xf2f2f2f2      0x00000000

As can be seen, we’ve bumped cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length up by one, set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 validation value to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new length, and set ptr to 0x7ffe0000 so that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie is zero. This is a fairly powerful bypass as it applies to any linear buffer overflow where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker can write NUL bytes and can write at least 24 bytes into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector header. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow writes more than 24 bytes into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 header, that’s fine because it would proceed to harmlessly corrupt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector’s data.

In my opinion, Linux generally has stronger ASLR than Windows, but unfortunately on Linux cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re sometimes exists a mapping called vsyscall. And you guessed it -- it’s at a fixed address:

ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

The higher parts of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page are filled with 0xcc (int 3), including at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure offset that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie is loaded from:

(gdb) x/16xw 0xffffffffff600c68
0xffffffffff600c68: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xffffffffff600c78: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xffffffffff600c88: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc
0xffffffffff600c98: 0xcccccccc 0xcccccccc 0xcccccccc 0xcccccccc

So, if we want a length of 0x07ffff84, we can calculate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 validation secret resulting from a secret cookie of 0xcccccccc, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n write memory to simulate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 linear buffer overflow leading to a bypass:

(gdb) p/x 0x07ffff84 ^ 0xcccccccc
$3 = 0xcb333348

(gdb) set *(unsigned int*)0x16748d6a8000 = 0x07ffff84
(gdb) set *(unsigned int*)0x16748d6a8004 = 0x07ffff84
(gdb) set *(unsigned int*)0x16748d6a8008 = 0xcb333348
(gdb) set *(unsigned int*)0x16748d6a8010 = 0xff600000
(gdb) set *(unsigned int*)0x16748d6a8014 = 0xffffffff

(gdb) x/8xw 0x16748d6a8000
0x16748d6a8000: 0x07ffff84 0x07ffff84 0xcb333348 0x00000000
0x16748d6a8010: 0xff600000 0xffffffff 0xf2f2f2f2 0x00000000

Fortunately, at least vsyscall on Linux is deprecated. You can already turn it off with likely no ill effects with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 boot parameter vsyscall=none. Hopefully cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next generations of Linux distributions will turn it off by default.

Bypass #3: Partial pointer overwrite
So, can we bypass cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigation on 64-bit Linux with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vsyscall=none boot parameter. It turns out that we can! We’re going to use a technique called a “partial pointer overwrite”. First, let’s look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory content immediately after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie value:

(gdb) x/16xw 0x7d7da146c68
0x7d7da146c68: 0xfaf38ece 0x00000000 0x00000000 0x00000000
0x7d7da146c78: 0x00000000 0x00000000 0x00000000 0x00000000
0x7d7da146c88: 0x00000000 0x00000000 0x00000000 0x00000000
0x7d7da146c98: 0x00000000 0x00000000 0x00000000 0x00000000

It looks like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie value might be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last item in a large structure. It’s not clear whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r we can rely on zero initialization of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fields, but for now we can demonstrate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se zero values. (An alternative would have been to find a reliably zero value earlier in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure.) The ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r observation we make is that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure that stored cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie is sufficiently large that it gets allocated at a page boundary. Putting it all togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, we can simulate a linear buffer overflow bypassing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigation like this:

(gdb) set *(unsigned int*)0x16748d6a8000 = 0x07ffff84
(gdb) set *(unsigned int*)0x16748d6a8004 = 0x07ffff84
(gdb) set *(unsigned int*)0x16748d6a8008 = 0x07ffff84
(gdb) set *(unsigned char*)0x16748d6a8010 = 0x04

The effect of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final write above is to overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 least significant byte of ptr with 0x4. Since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure pointed to is page aligned, we effectively increase cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value of ptr by 0x4, which causes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie to become zero.

Although cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 partial pointer overwrite works without needing any ASLR quirks or weaknesses, it does require that that attacker’s buffer overflow has perfect byte-by-byte control. Buffer overflows that write in multiples of (e.g.) 32-bit quantities will not be suitable.

Fixing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigation
Adobe fixed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigation by moving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 storage of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie from ptr into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 static BSS. Therefore, corrupting ptr will no longer enable cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker to change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 program’s view of what cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret cookie is.

In addition, Adobe have now enabled cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector heap partitioning mitigation for all platforms. Vector heap partitioning can be a useful defense-in-depth for attacks, including some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacks described here.

No comments:

Post a Comment