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!