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.

Friday, June 26, 2015

What is a "good" memory corruption vulnerability?

Posted by Chris Evans, register whisperer. Part 1 of 4.


There are a lot of memory corruption vulnerabilities in software, but not all are created equal. To a certain degree, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “usefulness” of a given memory corruption vulnerability is determined by how reliably it might be exploited. In some favorable instances, a given bug might be exploitable with near 100% reliability.


In this series of blog posts, we’ll examine what types of memory corruption vulnerabilities have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best potential to lead to 100% reliable exploits, using a few recent public bugs in our bug tracker as learning tools. By providing research and data of this nature to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 defensive community, we can guide defensive and mitigation efforts. The tools and techniques for reliable exploitation can be studied and dissected to both find new ideas for mitigations, and to improve existing mitigations. For example, we note below that type confusion vulnerabilities can be quite nasty and we’re investigating compiler-based mitigations for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se.


What do we mean by reliable?
At first this might sound like a silly question, but in fact that are a lot of facets to “reliable”. We’re not trying to give an authoritative definition of reliable here, and we’ll narrow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 scope below, but here are some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problems under cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 umbrella of “reliability”:


  • Does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit ever crash? This is probably cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 worst outcome for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker: a crash is a noisy signal that may lead to detection.
  • Does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit ever bail out cleanly? We’ll call this “aborting”, and an abort is defined as a clean exit without successful exploitation but also without any crash or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r detectable signal.
  • Does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit work uniformly across an exhaustive test matrix of different patch levels?
  • Does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit work in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 presence of additional security software such as EMET, Grsecurity, Anti-Virus products, etc.?
  • How is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit likely to behave upon encountering an unusual environment? Will it succeed, crash or abort?
  • Is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit cross-platform and cross-version?
  • Does cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit have a robust “continuation of execution” story, i.e. no post-exploitation instability or ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r untoward effects?


Given all this complexity, we need to define what we mean by “100% reliable” in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of this post. A “100% reliable” exploit is one that is:

  1. Guaranteed to succeed against a specific version and environment, on account of comprising a series of deterministic and fully understood steps;
  2. Provides adequate control that at a minimum, all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 above sources of unreliability can be detected and lead to aborts, not crashes.


Bug class: stack corruptions
Despite modern compiler technologies such as stack cookies and stack variable re-ordering, we still see cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 occasional stack corruption that is interesting from an exploitation point of view. For example, bug 291 details a very interesting stack corruption in an open-source JPEG XR image decoder where an array indexing error on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack leads to a write that “jumps over” cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack cookie and causes a corruption that is not detected by stack protections. The PoC reliably  and dare we claim, deterministically, crashes with ebp==0xffffffef. That hints to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug’s potential reliability.


Stack corruptions do have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potential to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 basis for 100% reliable exploits, because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack is often laid out very consistently at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time a vulnerability triggers. The follow code sample illustrates cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point nicely by popping a calculator due to a stack corruption. If it works for you cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first time, it’ll also work for you cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second!


// Fedora 20 x64: gcc -fstack-protector ./stack.c
void subfunc() {
   char buf[8];
   buf[16] = 1;
}


int main() {
   int run_calc = 0;
   subfunc();
   if (run_calc) execl("/bin/gnome-calculator", 0);
}


Bug class: inter-chunk heap overflow or corruption
Probably still cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most common vulnerability class we encounter, writing linearly off cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of a heap allocation is usually readily exploitable. However, it is unusual for such a vulnerability to lead to a 100% reliable exploit. One case where we almost got cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re was this off-by-one heap overflow in glibc. That’s an unusual case because we were attacking a command-line binary, where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap does end up in a deterministic state at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit attempt. Far more common is where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker is attacking a heap which is in a completely unknown state -- perhaps in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 context of a remote service, a web browser renderer process or a kernel.


There does exist a well-used technique called “heap grooming” which attempts to take a heap from an unknown state into a state where heap chunks are lined up in a productive arrangement for exploitation. There are good examples from previous Project Zero blog posts, such as this Safari exploit, this Flash regex exploit or this Flash 4GB-out-of-bounds exploit. Although heap grooming can generate very reliable exploits, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is still usually a probabilistic element to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 technique, so we end up lacking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 determinism needed to claim 100% reliable exploitation.


The following code sample illustrates some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 concepts of determinism vs. non-determinism:


// Fedora 20 x64: gcc ./interheap.c; n=0; while true; do ./a.out; done
int main(int argc, const char* argv[]) {
   void* ptrs[1024];
   int i;
   void* ptr1;
   int *run_calc;
   int seed = (argc > 1) ? atoi(argv[1]) : getpid();
   srandom(seed); printf("seed: %d\n", seed);  // ./a.out 21526 pops.
   for (i = 0; i < 1024; ++i) ptrs[i] = malloc(random() % 1024);
   for (i = 0; i < 1024; ++i) if (random() % 2) free(ptrs[i]);
   ptr1 = malloc(128); run_calc = malloc(128);
   *run_calc = 0;
   memset(ptr1, 'A', 4096);
   if (*run_calc) execl("/bin/gnome-calculator", 0);
}


For a given seed on a given machine, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap often ends up in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same state because a command-line binary starts with a fresh heap. (We’re going to stop shy of calling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 state deterministic because we haven’t studied all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potential influences. We also note that different installations of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same Linux OS will vary due to e.g. different malloc() patterns in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 dynamic linker depending on installed libraries.) Some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap states will lead to a calculator and some will not.


Bug class: use-after-free
Use-after-free vulnerabilities can lead to very reliable exploits, particularly when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “free” and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 “use” are close togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r, and / or cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker gets to trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 free via a scripting language. A lot of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 reliability comes from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way modern heap allocators tend to work: if an object of size X is free’d, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n it will typically be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next free heap slot handed out for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next allocation of size X. This maximizes cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use of “cache hot” memory locations. It is also extremely deterministic. For those wanting to study a good use-after-free exploit, one possibility is this Pinkie Pie exploit from 2013. Although cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re are very non-deterministic elements to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit, step 2) is where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 free’d object is re-purposed and that does represent a fairly deterministic step.


But, use-after-free bugs are not a perfect basis for a 100% reliable exploit. Generic challenges include:
  • Threading. Depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap implementation, a secondary thread might grab cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 free’d slot that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 primary thread wanted.
  • Heap corner-cases. Depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap implementation, a free operation might well trigger some reshuffle of central structures. Whilst unlikely, it is hard to be sure this will not happen if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap is in an unknown state at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 time of exploitation.
  • Sensitivity to object sizes changing. Although this will not affect reliability against a specific software version, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s always cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chance of an exploit breaking (and perhaps even difficulty to repair it) if a patch comes out which makes important object sizes bigger or smaller.


This simple code sample should illustrate cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 point that use-after-free bugs can be pretty nasty, though:


// Fedora 20 x64: gcc ./uaf.c
struct unicorn_counter { int num; };

int main() {
   struct unicorn_counter* p_unicorn_counter;
   int* run_calc = malloc(sizeof(int));
   *run_calc = 0;
   free(run_calc);
   p_unicorn_counter = malloc(sizeof(struct unicorn_counter));
   p_unicorn_counter->num = 42;
   if (*run_calc) execl("/bin/gnome-calculator", 0);
}


Bug class: intra-chunk heap overflow or relative write
Intra-chunk heap overflows or intra-chunk relative writes can provide a very powerful exploitation primitive. This time, we’ll start with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 sample code:


// Fedora 20 x64: gcc ./intraheap.c
struct goaty { char name[8]; int should_run_calc; };

int main(int argc, const char* argv[]) {
   struct goaty* g = malloc(sizeof(struct goaty));
   g->should_run_calc = 0;
   strcpy(g->name, "projectzero");
   if (g->should_run_calc) execl("/bin/gnome-calculator", 0);
}


A bug like this is extremely powerful because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memory corruption does not cross a heap chunk. Therefore, all of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 uncertainty and non-determinism arising from unknown heap state is eliminated. The heap can be in any state, yet cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same program data will always be corrupted in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same way. Bugs like cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se are very capable of leading to 100% reliable exploits. Bug 251 is a real-world example of a linear buffer overflow within a heap chunk. Bug 265 is a rare but very interesting example of an indexing error leading to an out-of-bounds write but within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 confines of a single heap chunk. The trigger is also interesting: a protocol where a virtual pen writes characters on to a virtual screen, and we use a protocol message to set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 virtual pen location to co-ordinates that are off-screen! The PoC deterministically crashes whilst operating on a wild but constrant address, free(0x2000000000).


Bug class: type confusion
Type confusion bugs can be very powerful, with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 potential to form cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 basis of 100% reliable exploits. When triggering a type confusion vulnerability, a piece of code has a reference to an object which it believes to be of type A (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API type), but really it is confused and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object is of type B (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 in-memory type). Depending on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 in-memory structure of type A vs. type B, very weird but usually fully deterministic side-effects can occur. Time for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code sample:


// Fedora 20 x64: gcc ./confused.cc -lstdc++
#include

class IShouldRunCalculator { public: virtual bool UWannaRun() = 0; };

class CalculatorDecider final : public IShouldRunCalculator {
public:
   CalculatorDecider() : m_run(false) {}
   virtual bool UWannaRun() { return m_run; }
private: bool m_run;
};

class DelegatingCalculatorDecider final : public IShouldRunCalculator {
public:
   DelegatingCalculatorDecider(IShouldRunCalculator* delegate) : m_delegate(delegate) {}
   virtual bool UWannaRun() { return m_delegate->UWannaRun(); }
private: IShouldRunCalculator* m_delegate;
};

int main() {
   CalculatorDecider nonono;
   DelegatingCalculatorDecider isaidno(&nonono);
   IShouldRunCalculator* decider = &isaidno;
   CalculatorDecider* confused_decider = reinterpret_cast(decider);
   if (confused_decider->UWannaRun()) execl("/bin/gnome-calculator", 0);
}


As you can see from 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ý bet365re’s a general attempt to say no to calculation, but a type confusion causes CalculatorDecider::UWannaRun() to perform a boolean check on an underlying piece of memory that is really a (non-null) pointer. So we’ll always end up calculating. (Or will we? It happens to calculate reliably on my machine but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a source of non-determinism here for readers that enjoy a thought exercise.)


A good study of a real type confusion bug and exploit is MWR Infosecurity’s blog post regarding cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir Pwn2Own 2013 entry against Google Chrome. Interestingly enough, this is one case where cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug does not easily lend itself to a 100% reliable exploit. In this instance, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is a small in-memory type confused against a much larger API type. Therefore, when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code is accessing most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 raw fields, a heap boundary is crossed because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 offset of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 field in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 API type is larger than 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 in-memory type. As we have seen above, crossing heap boundaries is a no-no for reliability. The following diagram shows cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two main possibilities of type confusion member use. The object on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 left is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 compiler has emitted code for, on account of a bad cast. But at runtime, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object memory pointed to happens to be smaller because cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 type in memory is different. Accesses that happen to be within bounds of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 runtime object will behave deterministically -- such as an ASLR defeating pointer infoleak in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GetSize() method. Accesses that cross a heap boundary are out-of-bounds and are unlikely to behave deterministically -- such as a memory corrupting write in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 SetFlags() method.





Case study: ShaderParameter heap corruption, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 old school way
This post has been about bug reliability, so it may seem strange that we’re about to present an unreliable exploit. But this is a story about demonstrating conventional wisdom and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n challenging ourselves to produce something more reliable using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same bug primitive. We start with poor reliability and will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n improve until we have excellent reliability.


So, we end this post by exploiting a recently patched vulnerability in Adobe Flash. It’s bug 324, an out-of-bounds write relating to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ShaderParameter ActionScript class. The attacker gets to write a chosen 32-bit value at a bad index relative to a shader program. A large index will result in an out-of-bounds write off cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of a heap chunk.


Given an out-of-bounds write primitive like this, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s now a highly standard way of exploiting Adobe Flash: simply use heap grooming to arrange for a Vector. buffer object to follow cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 object which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 write goes off cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of. The errant write will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n clobber cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 length of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector, resulting in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ability to read and write arbitrary process memory past cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 end of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Vector.



A reasonably commented exploit for Linux x64 is attached to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug. No particular attempt has been made to make it reliable; it could probably be tidied up to be much more reliable. But we’re not going to get to 100% reliability with this particular exploit for reasons covered above, because we’ve blindly corrupted across a heap chunk boundary.


After Adobe released cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch to fix this bug, but well before we released details of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bug, non-zero day exploits started showing up in exploit packs in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 wild. Perhaps cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attackers are fast at binary diffing, or have a MAPP leak, or were already using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability in a more targeted manner; we may never know. However this happened, it did generate us anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r data point and anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r exploit to study -- which also uses cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 standard Vector exploitation tricks according to @HaifeiLi on Twitter.


We’ll conclude this post here with a promise that we’re not done with this specific bug. In cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 next post in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 series, we’ll ask cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 question, “can we do something more reliable with this bug?” and as you might guess, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 answer will be yes.