Thursday, July 16, 2015

Significant Flash exploit mitigations are live in v18.0.0.209

Posted by Mark Brand and Chris Evans, isolators of heaps


Whilst Project Zero has gained a reputation for vulnerability and exploitation research, that's not all that we do. One of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 main reasons we perform this research is to provide data to defenders; and one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 things that defenders can do with this data is to devise exploit mitigations.

Sometimes, we'll take on exploit mitigations ourselves. Recently, we've been working with Adobe on Flash mitigations, and this post describes some significant mitigations have landed over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 past couple of Flash versions.

Now is a good time to check your current Flash version because you really want cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 latest one. For example, if you're running Google Chrome, you can visit about:version to check cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 versions of various components. If you have Flash v18.0.0.209 (or newer), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n you have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new goodies. If not, you can (on Windows) visit chrome://chrome to give cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 autoupdater a kick. (If you’re running an older version of Chrome, you will in fact receive a more active warning and block when encountering Flash content.)

Before we dive into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 technicalities of some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigations landed, it's worth reminding ourselves how cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vast majority of recent Flash 0-day, 1-day and research exploits have worked:



In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 above diagram, we see a heap overflow vulnerability being exploited. The attacker has performed "heap grooming", which attempts to place an object of interest after cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object from which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap overflow originates. The chosen object of interest is a Vector. buffer, which starts with a length. The desired corruption is to corrupt and increase this length. This technique was used in recent 0-days, as well as various 1-days.



And in this diagram, we see a use-after-free vulnerability being exploited. The attacker has caused a heap chunk to be freed whilst it is still referenced. The attacker cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n allocates a Vector. into this freed heap chunk and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 subsequent use-after-free writes over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector. length with a larger value. This technique was used in at least two of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 recent Hacking Team 0-days.

The commonality between both cases is an abuse of a corruption of a Vector. buffer object's length, which has been cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 go-to method for Flash exploitation for a while. Aside from 0-days and 1-days, Project Zero's own research has used this technique. For example, when working on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new exploit primitive "parallel thread corruption", we used Vector.. And why wouldn't we? There's no point in doing something complicated when something simple exists to solve cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem. And it is exactly because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector. primitive is so simple and powerful that it needs to be addressed.

Mitigation: Vector. buffer heap partitioning

Heap partitioning is a technique that isolates different types of objects on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap from one anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r. Chrome uses heap partitioning extensively, and it has become a common defensive technique in multiple browsers. We have now introduced this technology into Flash. In its initial form, Vector. buffer objects (and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r very similar objects) are now isolated from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 general Flash heap, because we put cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 standard system heap:



We have now defended cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 integrity of Vector. buffers from both heap overflow and use-after-free attacks! In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case of a heap overflow within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash heap, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector. buffer objects are simply not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re to corrupt. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use-after-free, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker tries to allocate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector. buffer to occupy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 free heap chunk of interest, it will not end up being allocated cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re because it lives in a different heap.

It's worth noting that this defense is much more powerful in a 64-bit build of Flash, because of address space limitations of 32-bit processes. Now is a good time to upgrade to a 64-bit browser and Flash. For example, if you're using Chrome on Windows 7 x64 (or newer), you might be running a 32-bit browser on a 64-bit capable system. To check, visit chrome://chrome and look for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 string "64-bit" -- its presence or absence will indicate whecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r you have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32-bit or 64-bit build. Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r details on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 advantages of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 64-bit Windows build are covered on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Chromium blog.

Mitigation: stronger randomization for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash heap

One day, while browsing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap mappings for a Flash process on x64 Windows 7, we noticed a strong determinism in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 position of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash heap. We filed bug 276, which is now fixed. Beyond fixing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 immediate issue of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash heap being at a predictable location, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch we provided had useful side effects to hamper exploitation:

  • Large allocations (> 1MB) are also randomized better than cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y used to be. This means, for example, that this previous Project Zero work, which relied on 1GB+ allocations being packed in predictable locations, is no longer a viable exploitation technique.

  • On 64-bit systems, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash heap will likely end up very far away from ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r memory mappings. This provides some interesting properties. For example, in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same exploit, a buffer length is corrupted and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n used to read function pointers in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PLT section of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash library. A buffer length is typically 32-bit, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 range of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corruption that can be effected by an errant buffer might be something like 2^32 * sizeof(unsigned int), or 16GB. With this new mitigation in place, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary sections are unlikely to be close enough to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash heap for buffer corruptions to be able to reach cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m. The attacker would need an additional level of indirection.

To look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 runtime effect of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 combination of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 above two mitigations, we can run a simple Flash program which allocates a large Vector. and a large ByteArray:

     _bigVec = new Vector.;
     _bigVec.length = ((512 * 1024 * 1024) - 500) / 4;
     _bigVec[0] = 0xf2f2f2f2;
     _bigArr = new ByteArray();
     _bigArr.length = 512 * 1024 * 1024;
     _bigArr[0] = 0xf1;

And cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n look at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting process mappings; Chrome Linux x64 in this case:

2d7ef200000-2d7ef209000   rw-p 00000000 00:00 0
35001005000-35022005000   rw-p 00000000 00:00 0  // Isolated 512MB ByteArray buffer.
a7026000000-a7026100000   rw-p 00000000 00:00 0
[...]
11655c57f000-11657c87f000 rw-p 00000000 00:00 0  // tcmalloc heap; Vector.
                                                // buffer at 0x11655c6ae000
[...]
3d3c8715f000-3d3c8716f000 r-xp 00000000 00:00 0  // Main Flash heap mappings (x3)
3d3c8716f000-3d3c8760b000 rw-p 00000000 00:00 0
3d3c8760b000-3d3c87f4b000 ---p 00000000 00:00 0

This new heap partitioning is currently enabled for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Pepper plug-in versions of Flash, so you can see it in action right away in Google Chrome (all operating systems). Adobe are planning to extend cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 partitioning to cover non-Pepper plug-ins in August.

Mitigation: Vector.<*> length validation

In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same Flash patch, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are not one, but two mitigations for Vector length corruptions! This second mitigation was authored by Adobe. It works by storing Vector lengths alongside a validation secret. If cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker corrupts a length, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y do not know what value to set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 secret to, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting mismatch results in a runtime abort. This mitigation is present across all Flash builds as of 18.0.0.209.

It may sound strange to have two mitigations for one exploitation primitive, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mitigations actually complement each ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r very nicely. Heap partitioning is very effective in 64-bit builds, but address space limitations can cause a bit of a squeeze in 32-bit. Perhaps cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best example of this is our blog post on bug 229, which is a bug that only has impact on 32-bit builds. The primitive provided by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to write at any absolute address in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 32-bit address space. Obviously, this primitive crosses partitions and a heap spray on 32-bit can make a chosen address likely to be mapped. Therefore, attempts to exploit this bug on 32-bit may sidestep partitioning but get hampered by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length validation.

Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap partitioning does not cover Vector. buffers due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way garbage collection works. The length validation covers this and all types of Vector. Finally, we note that Vector. buffers are (currently) in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system heap as opposed to a distinct partition. So even though most allocations in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash process occur in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Flash heap, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s still cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 possibility that a memory corruption in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system heap could corrupt a Vector. buffer and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length validation helps here.

The future

We believe we've contributed a strong step forward in Flash security, but we're very far from finished. For every mitigation landed by defenders, attackers will attempt to devise a counter-mitigation. It's a cat-and-mouse-game, but we'll be looking out for attackers' attempts to adapt, and devising furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r mitigations based on what we see. Perhaps more importantly, we're also devising a next level of defenses based on what we expect we might see. Our partitioning mitigation is far from finished. We’ll be analyzing object types to see what else might benefit from partitioning, and moving forward incrementally.

On top of this, we're continuing to help lock down cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 various browser sandboxes, and working on compiler-based mitigations. As always, we'll fully share our work when we have something interesting to show.

We'd like to thank Adobe for working with us.

Friday, July 10, 2015

From inter to intra: gaining reliability

Posted by Chris Evans, avoider of crossing (heap) lines. Part 2 of 4.


In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first post in this series, we concluded with a traditional exploit for Adobe Flash bug 324, and noted that it could never be 100% reliable. We also challenged ourselves to do better! Is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re some way we can leverage cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same vulnerability more reliably?

It turns out that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is. The breakthrough comes when we re-examine cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primitive we have. The bug manifests when we are resolving input parameters to a shader program. This process is fairly simple: a parameterized shader program contains placeholder constant definition opcodes for each input value, and just before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 program is run, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 placeholder constants are replaced with parameter values. A parameter “knows” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 index of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 opcode that it is going to write into, but an index that is valid in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of one program may not be valid in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r of different length:




To trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability, we take a parameter from one program and associate it with a different program. There are two types of invalidity:

  1. The parameter index is out-of-bounds for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 program’s opcodes. This leads to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 inter heap chunk memory corruption that we abused in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previous post:




  1. A new possibility: cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parameter index is in-bounds for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 program’s opcodes, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 indexed opcode is not a placeholder constant definition.

The exciting thing to note about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new possibility is that we do not cross a heap chunk. We’re triggering an intra-chunk corruption that will be deterministic. So — is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re a useful side-effect we can abuse if we corrupt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 compiled program opcodes? The answer is maybe. Unfortunately, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corruption we can cause is an overwrite of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last 4 bytes of a 20-byte opcode. This is not a commonly used field of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 opcode and at first glance it appears to only be used for constant values. However, upon a closer look, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s an opcode that operates similarly to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 C ternary operator, so we can corrupt it:


The ternary opcode works like this:

DEST_REG = (CONDITION_REG == 1) ? SRC_REG_1 : SRC_REG_2

As you can see, this opcode references a lot of registers. And this last register, SRC_REG_2, is stored in bytes 16 - 19 of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ternary opcode. We can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365refore corrupt this register number to be whatever we want. By cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time we corrupt it, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 register number has been pre-validated (and rewritten) so maybe this leads to a useful side-effect?

The SRC_REG_2 register is used only as a read. At first glance, this doesn’t sound too exciting — turning a very controlled write into a wild read. But if we take cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 trouble to look at 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 read during shader program execution, we note something promising. There’s a single heap chunk which contains a C++ object relating to shader execution, prepended with space for register state. So let’s say a given shader program uses 8 registers. When our corrupted ternary opcode references (zero-indexed) register 8 or higher, that is an out-of-bounds read. But critically, if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 out-of-bounds read isn’t too wild, it will not cross a heap chunk (think determinism, 100% reliability). Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rmore, we’ll be reading from a raw C++ object. C++ objects often contain vtables, including this one! Reading a vtable is a very important first step towards defeating ASLR.



A demonstration of this vtable leak is attached to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug. There are some fun aspects to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit code. The exploit starts by causing a fully deterministic memory corruption via ActionScript and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n proceeds in shader bytecode to render pixels based on out-of-bounds content into a virtual render buffer. Finally, back to ActionScript to recover cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 values from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual render buffer, into a recognizable pointer value.

When we run it, it doesn’t look very impressive. On Linux x64, it outputs something like: 0x00007f434a1a34d0

That’s cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of a vtable. But, refresh cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC repeatedly and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 value will never change and neicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re be a crash or failure retrieving it. We can try and introduce Flash process state variation by running videos, games, animations in ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r tabs — but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable recovery is 100% deterministic, so it will always work.

This was a non-goal during development, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit is also pretty portable. Without any furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r effort, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit can be run on Windows 8.1 x64 to yield, in my case: 0x00007ffc2e800a50. Run it on Windows 7 x86 and it’s 0x691e2dc800000000.

In summary, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit follows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following deterministic steps:
  • An unexpected shader parameter setup performs an out-of-bounds write within a heap chunk, to corrupt validated shader bytecode.
  • The corrupt shader bytecode performs an out-of-bounds read, also within a heap chunk, to leak a vtable value.

We now have a fully deterministic (dare I say 100% reliable?) way to leak a vtable value. However, this is fairly far away from “arbitrary code execution” — something we did achieve, albeit unreliably, in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first post in this series. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next posts in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 series, we’ll investigate possible avenues forward from here, whilst keeping our “100%” reliability.

Tuesday, July 7, 2015

When ‘int’ is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new ‘short’

Posted by Mark Brand, Truncator of Integers

This is going to be a quick post, just describing a particularly interesting Chrome issue that I found last month; how I found it; and what is interesting about it…

I was looking through some Chrome networking code; and I noticed an interesting API design choice that piqued my interest; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOBuffer interface. These are used throughout cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 networking stack to manage buffer lifetimes; and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are few things that are interesting about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m:

class NET_EXPORT IOBuffer : public base::RefCountedThreadSafe {
public:
 IOBuffer();
 explicit IOBuffer(int buffer_size);

 char* data() { return data_; }

protected:
 friend class base::RefCountedThreadSafe;

 // Only allow derived classes to specify data_.
 // In all ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r cases, we own data_, and must delete it at destruction time.
 explicit IOBuffer(char* data);

 virtual ~IOBuffer();

 char* data_;
};

So, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are several questions that I immediately want to ask about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 design of this interface; but we’ll stay on track for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 question that will lead us to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug. Why does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 constructor takes an int for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer_size parameter?

Why is this interesting? There are perhaps too many integer types in C/C++; and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 misuse of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m is a common cause of vulnerabilities. The language has a specific type for representing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sizes of objects; this is size_t, and it’s perhaps relevant to quote cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 C standard here:

The types used for size_t and ptrdiff_t should not have an integer conversion rank greater than that of signed long int unless cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation supports objects large enough to make this necessary

I assume that this recommendation was made precisely to prevent this kind of issue from occurring; having int and size_t be compatible types would make things safer for programmers that have been taught that int is always cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 correct numerical type to use. For completeness sake; I’ll note that 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 issue would be one of signedness; size_t is required to be an unsigned type; and this means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 range of size_t and int is not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same, even on systems where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same bit-width; however, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case of integer overflow resulting in a negative length is handled correctly in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 IOBuffer constructor.

Now; on x86_64, with gcc and clang an int is still a 32-bit integer type; but as we can have allocations over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 2^32 limit, size_t is necessarily a 64-bit integer type, and so in any location where we use a size_t type to initialise an IOBuffer instance, we risk truncating cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size and allocating a smaller buffer than we expect. It turns out that in content::CertificateResourceHandler, which handles cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mime-type ‘application/x-x509-user-cert’, that is exactly what’s going to happen. This is quite a simple class, which simply stores chunks of a certificate in an internal list as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y are received, totals 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ý bet365n reassembles those chunks.

bool CertificateResourceHandler::OnReadCompleted(int bytes_read, bool* defer) {
 if (!bytes_read)
   return true;

 // We have more data to read.
 DCHECK(read_buffer_.get());
 content_length_ += bytes_read;

 // Release cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ownership of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer, and store a reference
 // to it. A new one will be allocated in OnWillRead().
 scoped_refptr buffer;
 read_buffer_.swap(buffer);
 // TODO(gauravsh): Should this be handled by a separate thread?
 buffer_.push_back(std::make_pair(buffer, bytes_read));

 return true;
}

We’re summing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length in a member variable, content_length_ (which is of type ‘size_t’), and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n we later encounter cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 discussed integer truncation issue when we come to put cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pieces back togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r.

void CertificateResourceHandler::AssembleResource() {
 // 0-length IOBuffers are not allowed.
 if (content_length_ == 0) {
   resource_buffer_ = NULL;
   return;
 }

 // Create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 new buffer.
 resource_buffer_ = new net::IOBuffer(content_length_); // allocation truncated

 // Copy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data into it.
 size_t bytes_copied = 0;
 for (size_t i = 0; i < buffer_.size(); ++i) {
   net::IOBuffer* data = buffer_[i].first.get();
   size_t data_len = buffer_[i].second;
   DCHECK(data != NULL);
   DCHECK_LE(bytes_copied + data_len, content_length_);
   memcpy(resource_buffer_->data() + bytes_copied, data->data(), data_len); // heap corruption will occur here
   bytes_copied += data_len;
 }
 DCHECK_EQ(content_length_, bytes_copied);
}

So, we can serve up a certificate with a ridiculously long length, for example 0x100001000 bytes, and once this has all made it down cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 HTTP pipe to Chrome, we’ll try to copy those many, many bytes into a buffer of (int)0x100001000 bytes.

Truncation will happen like this:
size_t 00000001 00001000
int             00001000

And it’s pretty easy to see that bad things are now going to happen. See cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 tracker for a crash PoC.

Now, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 more astute reader will point out that I just sent over 4 gigabytes of data over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 internet; and that this can’t really be all that interesting - but that argument is readily countered with gzip encoding, reducing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 required data to a 4 megabyte payload. Of course, you do need to wait a little while for Chrome to perform cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 gzip deflation; something like 30 seconds for me; but this is not a major issue as this is taking place in a background thread in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser process, and will not really be noticeable, except for high processor usage.

And that leads us to probably cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most interesting thing about this bug. This is taking place in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser process; for those not familiar with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Chrome sandbox model; http://blog.azimuthsecurity.com/2010/05/chrome-sandbox-part-1-of-3-overview.html is a nice introduction. The browser process is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 trusted, unsandboxed process; making this bug a single-bug full compromise issue, potentially resulting in unsandboxed arbitrary code execution from a drive-by with a single bug.

This is a little bit scary; considering that typical pwnium entries consist of quite lengthy and convoluted bug chains. It just serves to highlight cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 importance of minimizing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 unsandboxed attack surface.

It’s going to be a difficult issue to exploit; even on a 64-bit system, surviving a 4-gigabyte out-of-bounds memcpy is a nontrivial problem. To make things worse, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser process is interacted with frequently by all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 live renderer processes; so achieving determinism from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap is going to be a serious challenge; but as in this Safari exploit; if stable exploitation is possible, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first step is likely going to be to manage to arrange for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap corruption caused by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow to corrupt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer_ vector, so that we can control cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow.