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.

5 comments:

  1. Integer overflow issues are very hard to spot and I've found it's best to use compile time or run time checks which I've noted at http://www.pixelbeat.org/programming/gcc/integer_overflow.html Would any of those have helped in this case?

    ReplyDelete
  2. This comment has been removed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 author.

    ReplyDelete
  3. Why compiler doesn't complain about that? Don't you compile chrome with -Wconversion and -Wsign-conversion

    ReplyDelete
  4. Initially I thought its a Java article, nevercá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365less interesting read. Thanks JP

    ReplyDelete