34c3 intro
Herald: This is Audrey from California and
she's from the University of California
Santa Barbara, security lab, if I'm
informed correctly, and it is about
automated discovery of vulnerabilities in
the Android bootloader. Wow, not really my
problem but definitely Audrey's. So here
we go. Please let's have a big hand for
Audrey Dutcher. Thank you.
applause
Audrey: Good evening everybody. Today
we're talking about Android boot loaders.
As a brief aside I didn't actually work on
this work I just sit across from the
people who worked on this work and I was
the only one who could make it to Germany.
I have, do work on some of the stuff that
it depends on, so this is my field but
this is not my project. Just brief
disclaimer, thanks. So today we're talking
about Android boot loaders. Phones are
complicated, bootloaders are complicated,
processors are complicated and trying to
get at the bottom of these is very
difficult subject; if you ever done any
homebrew kernel dev or homebrew retro-
gaming, you know that interacting with
hardware is really complicated and trying
to do this in a phone, a system connected
to a touchscreen and a modem and lots of
complicated, money sensitive things, it's
really not, it's really complicated and -
but every single one of you has one of has
probably has a phone in your pocket and
all of these are immensely valuable
targets for attacks, so we want to be able
to inhales detect bugs in them
automatically, that's the name of the
game. So the bootloader in a device: it
takes - it's the it's the job of "oh,
we've powered on, we need to get
everything initialized", so we initialize
the device and the peripherals and then
the final the final gasp of breath of the
bootloader is to take the kernel and
execute it. And the kernel obviously needs
to be loaded from storage somewhere. For
Android specifically, this is what we
worked, on most Android devices are ARMs,
there's no particular standard for what an
ARM bootloader should look like but the
ARM people do give you some guidelines.
There's an open-source implementation of
what a secure boot letter should look
like. There are in fact several boot
loaders on ARM, we'll go over this later.
But it's some mor- it's a complicated
affair that needs to preserve several
security properties along the way. And
above all, the whole goal of this process
is to make sure that things are secure and
to make sure the user data is protected.
That's what we're trying to do. Like we
said the phones in your pockets are
valuable targets. If you can attack the
bootloader you can root you can roo- get a
rootkit on the device, which is even more
powerful than just getting root on it. If
an attacker were to compromised your phone
he could brick your device or establi- I
talked about rootkits already but but
additionally you might want to circumvent
the security properties of your phone's
bootloader in order to customize it:
rooting, jailbreaking. "Unlocking" is the
key word in this situation.
The Android bootloader establishes
cryptographic integrity over basically
what's happening at all times, so on your
phone there is a master key and that will,
that kno- that knows that it should only
it should only run some code that has been
signed with the key associated with the
hardware and then the next stage of
bootloader has a key that it will verify
that the next stage of the bootloader
hasn't been tampered with. And this is
where we get the term "chain of trust",
where each part establishes "oh, I'm very
very sure, cryptographically sure,
assuming RSA hasn't been broken yet, that
the next bit of code is going to be doing
something that I authorized."
Circumventing this is valuable, as we've
talked about, phones have to have a way to
buil- to do that built-in, unless you're
Apple, and but obviously protecting this
mechanism from attackers is a point of
contention, so really you need to make
sure that only the real owner of the
device can actually unlock the phone. So
wha- this project is about making is about
discovering vulnerabilities that let us
circumvent this process, so the threat
model that we use for this project is that
there is, the phone is rooted and the
attacker has this root control. This is
pretty out there, no not that out there,
root vulnerabilities exist, but it's it's
enough to make you scoff "Oh what's the
point of this", well, the security
properties of the phone are supposed to
extend above the hypervisor level. It's,
you're supposed to have these guarantees
that things should always work, assuming
the chain of trust works, regardless of
what how what's happening in the kernel.
So today we are going to be talking about
BootStomp, which is a tool that
automatically verifies these properties
and discovers bugs. I'm going a little
slow, I'll speed up.
So first of the booting process in Android
ecosystems is pretty complicated and
multi-stage; there is the there's the base
bootloader BL1, which loads and verifies
another bootloader, which loads and
verifies another bootloader and this is
important, because the first on's in a ROM
and is very small and the second one is
probably going, is probably by the
hardware vendor and the third one is
probably by the OS vendor, for example,
and they all need to do different things.
So the important part here is these EL
things; those are the ARM exception
levels, which are basically the global
permission levels for an android
processor. The EL3 is basically the god
mode. There's EL2 for hypervisors, it
isn't in this chart, there's EL1, which is
the kernel and the EL0, which is user
space. So when we boot you're obviously in
the highest execution level and gradually,
as we establish more and more
initialization of the device, we're going
to cede control to less privileged
components, so the bootloader is operate
very privilegededly and one of the things
they need to do is establish what's, the
ARM trust zone, the trusted execution
environment that lets people do really
secure things on Android phones.
That's, this is something that is set up
by built by the BL31 bootloader and in
secure world you need to do things like
establish, initialize hardware and
peripherals and in the non secure world
you're norm- you're running like the
normal kernel and the normal users apps.
And on some phones you actually have a
final bootloader, which runs in EL1, BL33
or the aboot executable and that's the
that's the one that we're generally
targeting for for this stuff. So this is
what I was talking about the chain of
trust: each of those arrows represents
cryptographic integrity, so the next stage
only gets loaded if there's a valid
signature indicating that we really trust
what's going on here. And that's the
unlocking process that we were talking
about; if you, the verified, physical
owner of the device, wants to you can
disable that last bit and cause and allow
untrusted code to run as the kernel.
That's totally fine, if you own the
device.
The unlocking process is supposed to
really specifically verify these two
things: that you have physical access to
the device and that you actually own it,
like you know the pin to it, that's what
establishes ownership of our device.And so
specifically when you when you go through
that process it does set some specific
flags on your persistent storage, saying
this is an unlocked device now, you can do
whatever but making sure that that can
only happen when it's authorized is the
point of contention here. It should, the,
typically what happens is this security
state is itself cryptographically signed,
so you can't just set unlocked, you have
to set unlocked but signed by the people
that we really trust. And but but
generally you probably shouldn't be able
to write to it just from the normal user
space. So the question is: we saw that the
operating system is separate from the
bootloader. So what we want to be able to
do is get from the Android OS to affecting
the, to the bootloader. And can this
happen? Well, of course, that's why we're
here. So the, let's see. Oh I didn't
realize there were animations on the
slides, that's unfortunate. So this is
sort of the normal flow chart of how these
things normally come about.
You've got the bootloader, which has to
read from persistent storage in order to
initialize the operating system. Like, of
course you have to read, for example,
whether or not the device is unlocked, you
have to load the kernel itself. There are
lots of inputs to the bootloader and
intuition is that the bootloader is, these
just serve as normal inputs to a program,
which can be analyzed for vulnerabilities.
Oh lord, this is a mess. So so from the
OS, you're allowed to, you ha- if you have
root privileges in the operating system
you can write to this persistent storage,
which means that you have that this serves
as another input to the bootloader and
this can cause bad things to happen. So we
need some sort of tool, it's the point of
this project, to automatically verify the
safety properties of these boot loaders.
That's BootStomp. Bootloaders are
complicated. There's a lot of stuff, which
means you have to automate - the analysis
has to be automated in order to really
sift through something as big and
complicated as a bootloader, with the care
necessary to actually find bugs that are
sitting there.
And but these things aren't usually things
that you have source code for, so it needs
to be a binary analysis and furthermore
you can't really do a dynamic execution on
something that needs to run on the highest
privilege level of a processor, so you
have to have your - step back - and it has
to be static as well. And furthermore this
needs to be a fully free-standing analysis
that doesn't assume anything other than
"oh, we're executing code on a system",
because there's no known syscalls or API's
to checkpoint process or say "oh, we know
what this means, we don't really have to
analyze it." So it's a tall order but you
can do it with enough work. So BootStomp
specifically is the tool that we built. It
will automatically detect these inputs,
that we talked about, to the bootloader
and then it will determine if these inputs
can be used to compromise various security
properties of the device.
One such example is if you can use this to
just achieve memory corruption for example
or more abstract forms of vulnerability,
such as code flows that will result in
unwanted data being written by the more
privileged bootloader somewhere. And the
important thing about this analysis is
that its results are easily verifiable and
traceable and it's very easy to like look
at the outputs and say "oh, well, this is
what's happening and this is why I think
this happened and therefore I can
reproduce this, possibly?" This happens
through symbolic taint analysis. This is
the part that I know about, because I work
on angr, which is the symbolic execution
analysis static analysis tool that
bootstomp uses in order to do its taint
analysis. That taint analysis of all
execution are kind of loaded words, so
this is what specifically is meant is that
when we discover these sources and sinks
of behavior, through person particularly
static static analysis and some
heuristics, of course. And then we
propagate these taints through symbolic
execution, while maintaining tractability.
And notice wherever
we meet wherever we can find pause from
taint sources to behaviors sinks that we
think are vulnerable. Specifically, we
think these these behavior sinks are
vulnerable behavior if you can arbitrarily
write to memory, or read from memory.
Like, really arbitrary, if there's a
pointer which is controlled by user input
- memory corruption stuff. And
additionally, if you can control loop
iterations through your input, that
indicates the denial of service attack.
And finally, the unlocking mechanism, the
bootloader unlocking mechanism, if there
is if we can detect specific code paths
which indicate bypasses - those are
valuable. So, yeah, so this is the
specific architecture of the tool. There
are the two main modules one which is
written as an IDA analysis. You know, the
big tool that everyone probably doesn't
pay enough money for. And then there's the
other component written in angr which is
the symbolic change analysis. And this is
probably the point where I break out of
here and actually start the live demo.
That's big enough.
Okay, so we're working on a Huawei boot
image here, the fastboot image. We're
going to load it up in IDA real quick. So
here, IDA has understands, oh this is what
the executable is. So if we just sort of
run the initial script, find taints, it'll
think real hard for a little bit. There's
no real reason this couldn't if it's part
couldn't have been done an angr or binary
ninja or r2 or (???), god forbid. But,
this is a collaborative project if you saw
the huge author list and people write
stuff and whatever they're comfortable
with. So it's IDA in this case.
Realistically, because this is just a
binary blob when you load it in IDA it
doesn't immediately know where everything
is, so you have to sort of nudge it into..
oh here's where all the functions are.
Okay, we finished, and what it's done is:
we've got this taint source sync dot txt
which shows us, "oh, here are all the sources
of tainted information, and here's a few of
the sinks that we established." Obviously
you don't need a sink analysis to
determine if you've got memory corruption
or not but we like knowing where the
writes to persistent storage are and where
all the specifically the memcopy functions
are valuable for analysis. And then, if we
run our taint analysis bootloader, taint
on the - oh this configuration file is
real simple. It just says, "oh here's what
we're analyzing: it's a 64-bit
architecture, don't bother analyzing thumb
mode, etc cetera, simple stuff." And it'll
do this for about 20 minutes. Uh, config;
and it'll do this for about 20 minutes. I
hope it finishes before the demo is over.
If not, I'll do some magic and we'll a
pre-prepared solution. But, so, we talked
about these seeds there used the the seeds
for our taint analysis or for our
persistent storage. And that I used by the
unlocking procedure. So the heuristics I
was talking about - we want to identify
the reads from persistent storage through
log messages, keyword keyword analysis and
long distances. So the eMMC is this is a
specific memory module used by
the bootloader for secure purposes. And
just it's the persistent storage device
basically. And you can identify these log
messages and then we just do a diff -u
analysis back from the guard condition on
that block to its source and you say, "oh
that function must be the read." It's
pretty simple. It works surprisingly
often. Of course, if this isn't enough you
can just manually analyze the firmware and
provide, "oh here's where we read from
persistent storage, here's what you
should taint."
Cool. So the taint
analysis: our taints are specifically
sy-- this is specifically symbolic taint
analysis so it's not just like what Triton
does where you've got a concrete value
that has metadata attached. This is a real
symbol being used for symbolic execution.
If you're not familiar with symbolic
execution, it's a if it's a form of static
analysis in which you emulate the code,
but instead of having the values for some
of things you can just have symbols. And
then when you perform operation on those
symbols you construct an abstract syntax
tree of the behavior. And then when you
run into branch conditions based on those
things you can say, "oh, well, in order to
get from point A to point B this
constraint must be satisfied." And of
course, now you can just add z3 and stir
and you have passed the inputs to generate
paths to the program. So for the sinks of
the taint analysis, we want we wants to
say, "oh, if tainted data come comes into
and is is the argument to memcpy then
that's a vulnerability." I don't mean
like, it's the I don't mean like, the
taint data is the subject of memcopy, like
it's one of the values passed to memcpy.
That's a memory corruption vulnerability
generally. Yeah, we talked about memory
corruption, and we talked about loop
conditions, and we talked about writes to
persistent storage with the unlocking
stuff. Cool. For taint checking
specifically -- oh this is exactly what I
just said. Yeah, and part and what I was
talking about with the symbolic predicates
and trace analysis means
that when you see something,
you automatically have
the input that will generate that
behavior. So the output is inherently
traceable. Unfortunately, symbolic
execution has some issues. I was actually
at CCC two years ago talking about the
exact same problem. You have this problem
where, oh, you generate paths between
different between different states and
there can be too many of them. It
overwhelms your analysis. So you can use
some heuristics to say, "oh, we don't want
to we can; because it's the static
analysis we have a more powerful step over
than what a debugger can do." We don't
have to actually analyze the function, we
can just take the instruction pointer and
move it over there. And, this does cause
some unsoundness, but it's not a problem
if you like make sure that the arguments
aren't tainted, for example. Or sometimes
you just accept the unsoundness as part of
the tractability of the problem. Limit
loop operation: that's classic technique
from static analysis. And the time out, of
course. So, what are the bugs we found? We
evaluated this on four boot loaders and we
found several bugs. Six of which were zero
days. So that's pretty good. It's like,
okay, so you found some bugs but it could
just be you; oh there are some errors and
an initialization that don't really
matter. But on the other hand you can
crash it 41 41 41. That's pretty serious.
So as we saw, some of the bootloader is
like do work in ARM EL3 so this is pretty
significant. You can do whatever you want
in the device if you actually have
sufficient control over it. This is
rootkit territory. You could break
anything you wanted. Then there's another
component in the analysis that says, "can
we'd find bypasses to the unlocking
procedure." For example, this is this is
basically one of the ones that we found:
it's so it says boots on detected this,
this flow from data that was read from the
device to data that was written to the
device, and what this code is supposed to
do -- do I have animations? yes --it's
supposed to,
like, take some input
and verify that it hashes
to a certain value. And if so, hash
that value and write it back to disk, and
that constitutes the cryptographically
secure unlocking thing. However, the thing
that we write to is compared to the
identical to the thing that was read from
the disk. So you can just; the thing that
boots on purported was the code flow from
the disk backs the disk indicating that if
you can read from the disk, you know how
to produce the thing that will unlock the
phone. So this isn't secure. Mitigations.
So, the thing that Google does in order to
prevent attacks of this class is that the
key ness is the secure encryption key that
unlocked, that decrypts the like userland
data is, has embedded in it the unlock
state. So clearly, if you change the
unlock state you brick the entire phone.
Well, not brick, but have to reset it have
to lose all your data. That's still not
really good enough but realistically we
should probably be using a more trusted
form of storage that's not just the normal
normal partitions in the SD card in order
to just sort of store this state. It
should probably be part of the eMMC, or
specifically the replay protected memory
block which uses cryptographic mechanisms
to synchronize the, what's it called,
synchronize this writes to the memory with
the authenticated process. And so that
would make that would make sure that
only the bootloader could unlock it. But
of course that wouldn't protect against
memory corruption vulnerabilities and
there's nothing really to be said about
that other than, "hey, this is a serious
problem." In conclusion, all these bugs
have been reported, most of them have been
fixed. As far as I'm aware this is the
first study to really explore and
develop analyses for Android boot loaders
and in it we developed an automated
technique to analyze boot loaders with
tractable alerts. I found six 0days in
various boot loaders and our
implementation is open source. I will be
taking questions, thank you for listening.
applause
Herald: That was quite amazing.
Okay we'll be taking some
questions from people
that understood exactly
what it was all about. Yes
I see somebody walking up to microphone
one.
Mic 1: Thank you very much for talk--
Herald: Are you talking the mic otherwise
we can't record it.
Mic 1: Okay, thank you very much for that
work, that was really cool. Your mystic
investigations didn't include devicing the
code better. Do you think it's possible to
write the code so that your tools can
analyze it and maybe it would be secure?
Or not yet?
Audrey: Well, there's certainly things to
be said for having things in open source,
because necessarily doing analysis on
source code is a much more, a much better
defined field than the than doing analysis
on binary code. Additionally, you can
write your stuff in languages there is
safer than C. I don't know if it's, I
didn't know if it's safe to talk about
rust yet, but rust is cool. Yeah, there's
lots of things that you can do. I just
realized I didn't show off; I didn't show
off the still running, the analysis: the
automated results. It did not finish in
time so I will run some magic, and now we
have some results. Which..
applause
So, here's a here's one of the analysis
results. We found at this location in the
program a tainted variable, specifically
the tainted at offset 261 into the tainted
buffer. This variable was used as a
pointer. And that involved following the
path from along along this way. So there
is a vulnerability that I discovered for you.
So we can go on with question sorry that
was a bit.
Herald: Any more questions from the
audience? There is no question from from
the internet. Okay, one question, go
ahead: talk into the mic please.
Question: You said that the bugs you found
where responsibly disclosed and fixed.
Were they actually fixed in real existing
devices or did the vendors just say, "oh,
we'll fix it in future devices."
Audrey: I wish I knew the answer to that
question. I wasn't on the in the did this.
Yeah, I can't speak to that. That was just
that was just a slide on the slides that I
was given. I sure hope they were really
responsibly disclosed. It's real hard to
push updates to the bootloader!
Herald: Okay, any more questions? okay so
let's conclude this talk. People, when you
leave the hall, please take all your stuff
with you. Your bottles, your cups. Don't
forget anything, have a last check. Thank
you very much let's have one final hand
for Audrey Dutcher, from California!
applause
34c3 outro
subtitles created by c3subtitles.de
in the year 2018. Join, and help us!