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