00:00:00.000-->00:00:05.042 >>Hi everyone, uhm, it's great to be here at DefCon! Uhm, I'm here to talk to you today about 00:00:05.042-->00:00:09.583 Breaking the x86 Instruction Set Architecture. Before I get into any of that, my name is, uh, 00:00:09.583-->00:00:13.333 Christopher Domas, I'm a cyber security researcher at a company called the Battelle Memorial 00:00:13.333-->00:00:17.583 Institute. I really really like working here, gives me the chance to encounter a lot of 00:00:17.583-->00:00:22.250 very hard problems. Uhm, but I think what I like the most about working here is the problems in 00:00:22.250-->00:00:26.292 people I encounter during the day, uhm, give a lot of interesting ideas for the 00:00:26.292-->00:00:30.333 fringe-areas of cyber security to explore. Kind of on my free time and that's what I wanted to 00:00:30.333-->00:00:34.375 show you today, Is one of these little side projects I've been working on on-and-off for the 00:00:34.375-->00:00:39.583 last couple of months. So, this whole things based around trust and I'm gonna start, uh, this 00:00:39.583-->00:00:43.542 presentation off, uh, With a really really obvious statement: We don't trust software and we 00:00:43.542-->00:00:48.708 shouldn't - software can be horrible. So, we audit software to make sure that it works the 00:00:48.708-->00:00:52.917 way we expect it to work; we reverse engineer software to make sure there's, uhm, secrets 00:00:52.917-->00:00:57.500 hidden inside of it. We don't want minesweeper dialing out to a Russian website. We break 00:00:57.500-->00:01:01.250 software, we try to find vulnerabilities and exploit them in order to harden it. 00:01:01.250-->00:01:05.333 [background noise] Make things more resilient. And despite all this effort, uhm, we still don't 00:01:05.333-->00:01:10.083 trust software, so we sandbox it so that when something goes wrong at least it's contained. 00:01:10.083-->00:01:16.208 But the, uh, the processor itself, you know, the thing responsible for actually running 00:01:16.208-->00:01:21.542 our software for enforcing all of our security checks - the processor itself we pretty much 00:01:21.542-->00:01:26.625 just blindly trust. And we don't really have a lot of choice here because we don't have reverse 00:01:26.625-->00:01:32.167 engineering or introspection or auditing tools for the processor the way that we do for software. 00:01:32.167-->00:01:36.375 Really, the best we have for the processor is a bunch of processor specifications and 00:01:36.375-->00:01:41.708 reference manuals, Of bunch of documents that tell us "This is how your processor operates". 00:01:41.708-->00:01:45.875 And we're just supposed to take it on faith that that's how the processor actually operates. And 00:01:45.875-->00:01:49.708 I think, think that's kind of crazy, right? Because we would never do that with software, we 00:01:49.708-->00:01:54.708 would never download just some totally random executable. Open up the readme see that it says 00:01:54.708-->00:01:58.750 "Totally not a virus" and think "Yeah, that's totally not virus, I can go ahead and run this". 00:01:58.750-->00:02:04.708 But that's exactly what we're doing with hardware right now. Uhm, why? Because hardware has, 00:02:04.708-->00:02:11.458 All the same problems as software. So, so, so why do we trust hardware but not software? 00:02:11.458-->00:02:15.458 Uhm, if we're worried about secret functionality, I'm worried about that in software, 00:02:15.458-->00:02:19.750 does hardware have that? Absolutely. Uh, Intel infamously had what was called the 00:02:19.750-->00:02:25.500 'appendix H documents' that described all the secret pieces of the x86 architecture and was 00:02:25.500-->00:02:30.125 only available to trusted Intel sources. What about bugs? You worried about bugs in the 00:02:30.125-->00:02:34.292 software, does hardware have bugs? Uhm, you've probably heard of several of these. The 'F00F 00:02:34.292-->00:02:40.208 bug' in the Intel Pentium could allow an unprivileged user to lock the system. The 'f-tip bug' 00:02:40.208-->00:02:44.125 in the Pentium, uhm, every couple of billion floating point operations, the Pentium would be 00:02:44.125-->00:02:47.500 off by a fraction of a percent. That cost Intel about five-hundred million dollars. 00:02:47.500-->00:02:52.667 Uhm, the 'txs bugs' and Haswell architecture - Intel had to completely disable transactional 00:02:52.667-->00:02:56.833 memory support in Haswell because of these bugs. Skylake has hyperthreading data 00:02:56.833-->00:03:01.667 corruptions, uhm, the Ryzen processor is crashing, faulting under heavy 'F May three' 00:03:01.667-->00:03:06.750 operation loads. Uhm, modern processors have tons and tons of bugs in them. What about 00:03:06.750-->00:03:09.833 vulnerabilities? We're worried about vulnerabilities in software, [background noise] 00:03:09.833-->00:03:14.750 Hardware's got those too. Like the 'SYSRET' uh, vulnerability, uh allowed, uhm, A user to 00:03:14.750-->00:03:19.042 escalate into kernel level permissions on almost every major operating system. The 00:03:19.042-->00:03:23.292 cache poisoning and memory sinkhole attacks allowed infiltrating x86's protected 00:03:23.292-->00:03:28.417 system management mode. So, vulnerabilities exist in processors too. So, the, the 00:03:28.417-->00:03:33.375 point here is, We should stop blindly trusting our hardware - if we don't trust software we 00:03:33.375-->00:03:37.083 shouldn't trust hardware either. So, what kinds of things do we need to worry about when we're 00:03:37.083-->00:03:41.333 talking about trusting hardware? [background noise] Well, the thing that I was mostly 00:03:41.333-->00:03:45.625 interested in for this research was hidden instructions inside of the processor. Like, maybe 00:03:45.625-->00:03:50.167 there's secret functionality that can give us backdoor, Or powerful access to the processor 00:03:50.167-->00:03:54.917 internals. Now, I know that sounds almost conspiracy theory-esque but it's not that 00:03:54.917-->00:03:59.583 far off from reality. There's actually some interesting historical examples of this in 00:03:59.583-->00:04:04.583 the x86 architecture. So, for example, early x86 chips had what was called the 'ice 00:04:04.583-->00:04:10.417 breakpoint instruction'. This was an instruction that wasn't documented anywhere; that would 00:04:10.417-->00:04:15.792 switch the processor over to a very privileged ice mode. Uhm, those same processors also had 00:04:15.792-->00:04:20.417 this 'loadall instruction' - another undocumented secret instruction that would give you 00:04:20.417-->00:04:24.792 access to, uhm, hidden pieces of the processors registers that you normally couldn't reach. 00:04:24.792-->00:04:30.958 Uhm, or just a more recent example, as you may have heard about the, uh, the 'API call 00:04:30.958-->00:04:35.083 instruction' in Microsoft's x86 emulator. Which, basically what Microsoft did was they 00:04:35.083-->00:04:39.958 backdoored the UD zero x86 instruction and turned it into something entirely different 00:04:39.958-->00:04:44.292 without ever, uhm, releasing that information. And that caused a fairly serious 00:04:44.292-->00:04:49.833 vulnerability, uhm, in their, in their emulator. So, these, these things can exist in real life 00:04:49.833-->00:04:54.375 and sort of highlight that point. If you actually go into your processor's documentation, 00:04:54.375-->00:04:59.583 if you look up Intel software developer's manual volume two, near the end of it you will see 00:04:59.583-->00:05:04.375 dozens and dozens of tables that look something like this. What these are, are, uh, the opcode 00:05:04.375-->00:05:08.458 maps - these are supposed to enumerate all of the instructions data processor 00:05:08.458-->00:05:12.625 supports. It's basically saying that when the processor see this byte, it's going to execute this 00:05:12.625-->00:05:16.625 instruction; when it sees this byte it's going to execute this instruction. So, uhm, that's 00:05:16.625-->00:05:20.833 what we're seeing in the, in the opcode maps. [background noise] But if you look really closely 00:05:20.833-->00:05:26.333 at these opcode maps, uhm, you'll notice something - there are gaps here and there. So, 00:05:26.333-->00:05:30.750 this is a document that's supposed to tell us everything the processor does. This is a 00:05:30.750-->00:05:37.292 document that we're basing all of our trust for this processor on, uhm, but it's leaving things 00:05:37.292-->00:05:42.500 out, uhm, with these gaps. That's not really a good start for trust, right? If we're 00:05:42.500-->00:05:46.375 relying on this document and it's intentionally not telling us certain things about the 00:05:46.375-->00:05:51.417 architecture. So, I wanted to find a way to actually audit the processors that are in all of 00:05:51.417-->00:05:56.583 our computers - I wanted to figure out what's really on my processor. So, I wanted to find 00:05:56.583-->00:06:00.917 these hidden instructions. How do we do that in this architecture? The challenge with 00:06:00.917-->00:06:07.250 x86 is the instruction format is very very complex. In x86 you can have one byte machines 00:06:07.250-->00:06:12.583 instructions like 'Increment eax is hex forty'. You can also have fifteen byte machine 00:06:12.583-->00:06:17.542 instructions like 'Add keyword CS override complicated memory access, complicated', uhm, 00:06:17.542-->00:06:22.500 'immediate value', Is a fifteen byte x86 instruction. And you can have everything in between 00:06:22.500-->00:06:26.625 as well. So, if we actually look at a worst case scenario and assume all the instructions are 00:06:26.625-->00:06:30.458 fifteen bytes, just for simplicity, you're looking at something like one point three 00:06:30.458-->00:06:34.958 undecillion possible instructors, On this architecture. Now, if I just 00:06:34.958-->00:06:39.875 want to find one hidden secret instruction in all of that, that's going to be really, 00:06:39.875-->00:06:43.917 really difficult. So, the obvious approach is to kinda like sort through all of these 00:06:43.917-->00:06:48.167 instructions just don't really work. So, you might think "Let's just try all of the x86 00:06:48.167-->00:06:52.250 instructions". And that might work for a risc chip with a fixed length instruction set - 00:06:52.250-->00:06:56.750 that's not going to work for x86. There's, there's way way too much. You might think "Well, 00:06:56.750-->00:07:01.500 what if we just do random instructions and see, uh, if we find anything interesting." The 00:07:01.500-->00:07:06.083 problem is you could run, run random instructions for the next ten years and you'd still cover 00:07:06.083-->00:07:11.792 such a tiny tiny portion of that search space, uhm, That it wouldn't be very useful. You 00:07:11.792-->00:07:15.750 might think "Well, we've got this documentation that kinda tells us what these instructions 00:07:15.750-->00:07:20.500 look like. Why don't we guide our base, our, uh, search based on the documentation?". But big 00:07:20.500-->00:07:25.542 problem with that is kind of like we already.. Established, uh, the documentation can't be 00:07:25.542-->00:07:29.500 trusted. If you're basing you search on the documentation, you're kind of doomed to fail 00:07:29.500-->00:07:33.958 from the start. The other big problem, you might think "Well, uhm, there's these gaps in those 00:07:33.958-->00:07:37.667 manuals, why don't we just explore those gaps? But those gaps really only tell you the 00:07:37.667-->00:07:42.333 first byte of the instruction. If you were looking for a secret instruction that's fifteen bytes 00:07:42.333-->00:07:47.958 long, uhm, you still got a long ways to search even basing it on a documentation. So, so, we 00:07:47.958-->00:07:51.750 don't want to do that, we want to find a better way to search through this instruction set. 00:07:51.750-->00:07:56.083 Really, our goal is to find the bytes in the instruction that actually matters so that we can 00:07:56.083-->00:08:00.750 fuzz those and ignore all the bytes in the instruction that don't matter. So, I wanna 00:08:00.750-->00:08:05.708 throughout an observation here that the meaningful bytes in x86 machine instruction impact 00:08:05.708-->00:08:10.625 either that instruction's length or its exception behavior. Basically, the meaningful bytes 00:08:10.625-->00:08:14.458 change something, important about the instruction and the bytes that don't really matter 00:08:14.458-->00:08:18.417 don't really change anything important about the instruction. So, I kinda came up with this 00:08:18.417-->00:08:22.292 idea, [background noise] Of a depth first search algorithm that would let us search through 00:08:22.292-->00:08:26.833 all the reasonably distinct instructions inside of the x86 instructions set. So, the way 00:08:26.833-->00:08:29.667 that this is going to work is we're going to guess an instructions - now, we don't 00:08:29.667-->00:08:32.542 know how long this instruction is. [background noise] Let's just guess fifteen bytes of 00:08:32.542-->00:08:37.375 zeros. Then I'm going to execute this instruction and from the execution I'm going to see how 00:08:37.375-->00:08:41.833 long was this instruction actually. You'll see that this instruction is two bytes long. 00:08:41.833-->00:08:45.125 [sneeze] So, we're going to increment the very last byte of this instructions and then 00:08:45.125-->00:08:50.042 repeat the process. Execute the instruction; observe its length; increment the last byte; 00:08:50.042-->00:08:54.625 execute; observe the length; increment the last byte. Very very simple algorithm here. But 00:08:54.625-->00:08:59.958 eventually what will happen when you do that final incrementation and execute the instruction 00:08:59.958-->00:09:04.083 you'll find that at some point the length changes. Uhm, Our instruction just went from two 00:09:04.083-->00:09:08.667 bytes to three bytes. So what we do when the length changes is we're going to move to the last 00:09:08.667-->00:09:13.542 byte and increment it; then execute the instruction; observe its length; increment the last 00:09:13.542-->00:09:16.833 byte. Uhm, over and over and over again, so if you repeat this process, these are what 00:09:16.833-->00:09:21.042 you're instructions kind of look like. Uhm, you can see that through this, like, 00:09:21.042-->00:09:27.708 incrementation approach, we very gradually sort of drill down into the instruction set, uhm, 00:09:27.708-->00:09:32.000 by generating more and more complex instructions as we go along. So, at some point you're 00:09:32.000-->00:09:36.375 gonna increment all possible bytes for that last byte and you're going to see that the 00:09:36.375-->00:09:41.500 length still didn't change. So, when you've done that, when the last byte is an F F, uh, two 00:09:41.500-->00:09:45.208 fifty-five, you're going to increment it one more time; let it roll over and then you're 00:09:45.208-->00:09:49.000 going to move back a byte. And that's going to be our marker byte. Uhm, so then we're going 00:09:49.000-->00:09:53.458 to increment that marker, So it becomes one. And we'll repeat the process - execute the 00:09:53.458-->00:09:58.042 instruction; observe its length - if the length hasn't changed yet, and it didn't here, 00:09:58.042-->00:10:02.292 increment the marker again. And just repeat that over and over and over, [background noise] And 00:10:02.292-->00:10:05.917 eventually in this situation that marker will roll over again. So, you move back a byte 00:10:05.917-->00:10:10.583 now; if the marker roles over, move back; marker rolls over, move back. And just keep that 00:10:10.583-->00:10:16.417 up, incrementing these bytes one by one and observing the length changes. So, eventually when you 00:10:16.417-->00:10:20.625 increment the marker, you're going to find when you execute the instruction that the length 00:10:20.625-->00:10:26.083 changed again. So, at this point we now move back to the end of the instruction and start the 00:10:26.083-->00:10:30.458 whole process over. Incrementing that last byte and seeing how long that instruction is. So, 00:10:30.458-->00:10:34.458 this is a, a sort of neat algorithm - this tunneling algorithm lets us search through 00:10:34.458-->00:10:37.542 the instructions space really quickly,. [background noise] Skipping over over the bytes 00:10:37.542-->00:10:42.167 that don't matter and focusing on those that do. Now, that let's us basically exhaustively 00:10:42.167-->00:10:46.250 search the bytes and the instructions that actually matter. Uh and effectively what 00:10:46.250-->00:10:50.417 that does, is it reduces your search space in this architecture from one point 00:10:50.417-->00:10:54.208 three times ten to the thirty-sixth instruction down to about a hundred million - 00:10:54.208-->00:10:57.875 something that you actually scan in about a day. Uh, so that's, that's pretty neat. I, I was, I 00:10:57.875-->00:11:03.292 was excited that I, I, I found a way to quickly search this ISA. Uhm, but there's a catch here 00:11:03.292-->00:11:07.667 that I, I kind of glossed over - namely that in order for those algorithm to work, we need to 00:11:07.667-->00:11:12.292 know the length of an x86 instruction. And it's not as easy as it sounds. We can't just 00:11:12.292-->00:11:15.792 disassemble the instruction to see it's length because we might be dealing with undocumented 00:11:15.792-->00:11:19.750 instructions or misdocumented instructions. [background noise] So, the simple approach here if 00:11:19.750-->00:11:24.125 you, if you're, if you're familiar with x86, might be to use the x86 trapflag, so the way 00:11:24.125-->00:11:28.875 the x86 trapflag works is if you've got an instruction and you set the trap flag before 00:11:28.875-->00:11:33.167 executing that instruction then you execute that instruction - the processor throws an 00:11:33.167-->00:11:37.292 exception and gives control to your trap handler. Now, that trap handler could look at that 00:11:37.292-->00:11:41.708 new instruction pointer; compare it to the original instruction pointer and that difference 00:11:41.708-->00:11:44.875 tells you the instructions length. So it's how you could try to do this with the trap 00:11:44.875-->00:11:48.833 flag but the trap flag has a really big limitation here - namely it fails to resolve the 00:11:48.833-->00:11:54.125 length of faulting instructions. Uhm, so why do we care about faulting instructions? Well, 00:11:54.125-->00:11:58.917 uhm, it's necessary if you want to search through privileged instructions. So, let's say 00:11:58.917-->00:12:02.875 we're executing this in ring three - the least privileged mode of execution on the x86 00:12:02.875-->00:12:06.458 processor. We still want to figure out if there are instructions that only exist 00:12:06.458-->00:12:10.083 only in ring zero. So, for example, loading a control register can only get into 00:12:10.083-->00:12:14.167 kernel and ring zero. There are instructions that can only be executed in hypervisor - like VM 00:12:14.167-->00:12:18.333 enter. Or instructions that can only be executed in system management mode like 'resume'. 00:12:18.333-->00:12:22.667 So, regardless of what, uh, mode of execution or privilege level we're scanning at - we want to 00:12:22.667-->00:12:27.375 be able to resolve the instructions that occur in any other mode. So, we gotta come up 00:12:27.375-->00:12:30.333 with a better approach for figuring out the length of an instruction. What I came up with 00:12:30.333-->00:12:35.333 this, for this was, uh, sort of page fault analysis. So, the idea here is choose an arbitrary 00:12:35.333-->00:12:39.542 instruction - we don't actually know how long this instruction is right now but we wanna figure 00:12:39.542-->00:12:43.583 out how long it is. So, we're gonna map two pages into memory, uh. The first page is going to 00:12:43.583-->00:12:46.708 have 'rewrite execute permissions' and the second page is only going to have 'rewrite 00:12:46.708-->00:12:50.792 permissions'. Then what we do is we place our instruction in memory so that the first byte of 00:12:50.792-->00:12:55.375 the instruction is on the last byte of the executable page. And the rest of the instruction is 00:12:55.375-->00:12:59.000 at the beginning of the non-executable page. Then you execute this instruction 00:12:59.000-->00:13:02.292 basically just jump to the instruction and see what happens. So, internally the 00:13:02.292-->00:13:07.958 processor's fetcher is basically going to grab that first byte - that ' O F' here and it's going 00:13:07.958-->00:13:12.083 to see O F is not an instruction by itself - I need more bytes. So it tries to grab the next 00:13:12.083-->00:13:16.542 byte of the instruction but now it sees that that next byte is on, A non-executable page. So, 00:13:16.542-->00:13:21.333 the processor throws, uh, a page fault, uh, specifically the processor's going to generate a 00:13:21.333-->00:13:26.667 page fault exception with a fault address in a CR2 register. So, CR2 points to the address of 00:13:26.667-->00:13:30.625 that second page. So, whenever that happens we receive a page fault and CR2 is set to the 00:13:30.625-->00:13:34.958 address of the second page - we know that the instruction, instruction is longer than, uh, 00:13:34.958-->00:13:39.458 what we have in the executable, uh, page. So, in this situation I know the instruction is longer 00:13:39.458-->00:13:43.958 than just O F. So, we move the instruction back a byte and repeat the instruction - execute 00:13:43.958-->00:13:47.833 the instruction, uh, the decoder's gonna grab that first byte; it's gonna see the 00:13:47.833-->00:13:52.125 instruction continues beyond O F. Uhm, so, it's gonna grab that next byte - that works now 00:13:52.125-->00:13:56.500 because this is an executable page - uh, it's gonna see that if this is 6A I still need more 00:13:56.500-->00:14:00.542 bytes to finish the instruction. Uhm, and then it's gonna try and grab the next byte, again it's 00:14:00.542-->00:14:04.417 going to fault here because the byte is on a non-executable page. [background noise] Uhm, so 00:14:04.417-->00:14:08.750 we basically just repeat this process over and over, uhm, as long as we recieve page fault 00:14:08.750-->00:14:12.917 exceptions with CR 2 set to the second page address - keep moving the instruction backwards 00:14:12.917-->00:14:16.208 one byte. And eventually what will happen when you execute the instruction is. [sneeze] You're 00:14:16.208-->00:14:19.917 gonna find that that entire instruction resides in an executable page. So, the 00:14:19.917-->00:14:23.917 processor could do a lot of different things here. Uhm, this instruction could run; the 00:14:23.917-->00:14:27.792 instruction could throw a different kind of fault; it could throw a page fault as well 00:14:27.792-->00:14:32.583 but it's going to have different address in the CR2 register. So, regardless of what happens here 00:14:32.583-->00:14:37.042 - all of those situations mean that this instruction has now been successfully decoded so it 00:14:37.042-->00:14:41.458 must reside entirely in the executable page. That means that we know the instruction length, 00:14:41.458-->00:14:47.083 uh, at this point. So, we know the instruction length - we know how many bytes the instruction 00:14:47.083-->00:14:51.083 decoder consumed. What we don't actually know at this point is whether or not this instruction 00:14:51.083-->00:14:56.292 really exists. The processor has to decode even non-existing instructions - fortunately it's 00:14:56.292-->00:15:02.583 pretty easy to check if this instruction exists or not at this point. Basically if the 00:15:02.583-->00:15:04.667 instruction does not exist on the processor - like, it;s really not there; not just that 00:15:04.667-->00:15:06.667 it's un, or it's undocumented, [sneeze] If the instruction is really not there the processor 00:15:06.667-->00:15:11.792 generates an undefined opcode exception at this point. So, if we receive anything other than a 00:15:11.792-->00:15:17.167 UD-exception then we know that this instruction actually exists on this processor. So, this is 00:15:17.167-->00:15:20.750 kind of a neat approach. It lets us resolve the lengths for successfully executing 00:15:20.750-->00:15:24.000 instructions, faulting instructions, privileged instructions - things that can 00:15:24.000-->00:15:29.417 only execute in ring zero; ring minus one and system management mode. And so, I, I threw all 00:15:29.417-->00:15:33.333 this functionality into little process that I called 'The injector'. The injector 00:15:33.333-->00:15:38.333 basically does this page fault analysis and the instruction search operations. The injector 00:15:38.333-->00:15:43.417 has a really big problem though - it's fuzzing the device that it's actually running on. So, 00:15:43.417-->00:15:47.208 how do we keep the injector from crashing itself with these random instructions that it's 00:15:47.208-->00:15:50.667 generating? Uhm, well, the first step is we're gonna restrict ourselves to running inside of, 00:15:50.667-->00:15:55.750 uh, ring three. [background noise] And it's not such a big limitation because even in ring 00:15:55.750-->00:15:59.083 three using this approach we can find out whether or not certain instructions exists in more 00:15:59.083-->00:16:03.292 privileged rings as well. So, that's, uh, not a big limitation but it does mean, uh, that 00:16:03.292-->00:16:09.042 we're, uh, essentially not accidentally totally crash the entire system through these 00:16:09.042-->00:16:15.208 random instructions. Uhm, unless you've got a very serious processor bug. Uhm, and so the 00:16:15.208-->00:16:18.417 next thing we're gonna do is try and hook all the exceptions that this instruction could generate. 00:16:18.417-->00:16:22.292 Uhm, in Linux that means we're gonna hook the 'SEG fault exception'; we're gonna hook 00:16:22.292-->00:16:25.833 'illegal instruction exceptions'; we're going to hook, uhm, a 'floating point 00:16:25.833-->00:16:33.917 exceptions'; bus errors, traps. Uh, and whenever we receive one of these exceptions the process 00:16:33.917-->00:16:37.125 is basically gonna clean up after itself, uh, so, by that I mean that the process is going, 00:16:37.125-->00:16:41.333 uh, essentially reload all of the registers to known good values. [background noise] That 00:16:41.333-->00:16:44.458 way, no matter what happened with that instruction that we generated we reset the system to 00:16:44.458-->00:16:48.792 a known good state. So, uhm, at, at step three what we're going to do to prevent other types of 00:16:48.792-->00:16:55.083 crashes is we'll set all the general purpose registers, uh, on that processor to 'zero' 00:16:55.083-->00:16:59.292 before we try to execute the instruction. So, what that does for us is it mean an arbitrary 00:16:59.292-->00:17:03.417 memory write instruction like this - like this instruction adds the value nine one oh two, 00:17:03.417-->00:17:08.667 uhm, into some location in memory. We don't want that to actually hit something that our 00:17:08.667-->00:17:14.042 program needs. We don't want that location in memory to fall into our process' address space. 00:17:14.042-->00:17:19.500 Uhm, so by loading all the registers to zero we ensure that, uhm, the memory, uh, uh, 00:17:19.500-->00:17:23.708 address portion of this instruction resolves to zero. Uh, but, That's not quite enough 00:17:23.708-->00:17:27.458 just yet because x86 has some complicated addressing modes - we can have an address like 'e a 00:17:27.458-->00:17:34.292 x plus four times e c x plus' some, uhm, weird long offset. [cough] So, even though we can 00:17:34.292-->00:17:39.542 ensure that the part on the left resolves to zero; the part on the part on the right might 00:17:39.542-->00:17:41.958 still fall into the instructions address, or the process's address space. Uhm, in which 00:17:41.958-->00:17:46.542 case you could corrupt yourself beyond repair, so, we don't want that to happen. Uhm, fortunately 00:17:46.542-->00:17:51.000 we're actually in good shape here because of the way that the tunneling search works. Uhm, 00:17:51.000-->00:17:55.000 essentially tunneling ensure that those offsets are constrained. Uh, if we have a 00:17:55.000-->00:17:58.667 four byte offset, three of those bytes will always be zero when we're searching these 00:17:58.667-->00:18:03.125 instructions. So, there's a range of different values we can get for that offset but none of 00:18:03.125-->00:18:08.083 those actually fall onto the normal, uhm, Linux process address space. Uhm, meaning that 00:18:08.083-->00:18:12.042 our process won't accidentally corrupt itself. Now, those instructions will segfaults, 00:18:12.042-->00:18:15.917 uhm, but that's perfectly okay - we catch SEG fault and can correct those. [background 00:18:15.917-->00:18:24.083 noise] Uhm, so, we've handled faulting instructions at this point - what about non-faulting 00:18:24.083-->00:18:27.417 instructions? The instructions that actually; the instruction we generate that actually do 00:18:27.417-->00:18:29.875 run, uhm, how do we handle those? We need some way for the analyses to continue after these 00:18:29.875-->00:18:32.583 instructions. So, imagine that you randomly generated, uhm, like, an instruction like jump 00:18:32.583-->00:18:38.167 backwards fifty bytes, uhm, the processor would jump back fifty bytes and then just start 00:18:38.167-->00:18:42.667 executing random garbage that could, could corrupt your, your process beyond recovery. So we 00:18:42.667-->00:18:47.583 don't want that to happen but here's where the trap flag can actually help us right. 00:18:47.583-->00:18:50.625 Basically right before we execute an instruction we're gonna set the trap flag, uh, so 00:18:50.625-->00:18:55.708 what will happen is when that instruction executes a trap will trigger that gives control over 00:18:55.708-->00:19:00.875 to our program and our program can restore our registers to known good state again. So, with 00:19:00.875-->00:19:03.792 all of these things. Limiting ourselves to ring three; handling exceptions; 00:19:03.792-->00:19:07.542 initializing registers; keeping register sets in known good values. Uhm, trapping execution 00:19:07.542-->00:19:12.833 - the injector, uh, survives, basically, it won't crash itself now. So, so we've got an 00:19:12.833-->00:19:19.000 effective way to search the x86 instruction space. Now, the next question is how do we make sense 00:19:19.000-->00:19:23.833 of these instructions that we're actually generating? Uh, so for this I, I designed what I call 00:19:23.833-->00:19:27.792 the 'sifter process'. It's kind of a wrapper around the injector. And the filter's job 00:19:27.792-->00:19:32.417 is to look at what the injector's doing, uhm, and pull out anomalies from the injector. 00:19:32.417-->00:19:37.167 So, so what I mean by anomalies, what's an anomaly in, in x86? Well, I thought, what I really 00:19:37.167-->00:19:41.917 want to find is somewhere where the actual processor execution deviates from the processor's 00:19:41.917-->00:19:46.625 specifications, uh, so my idea here was we could use a disassembler as a sort of ground 00:19:46.625-->00:19:50.708 truth for this search because a disassembler is somewhat presumably written based on a 00:19:50.708-->00:19:54.792 processor specifications - a good abstraction of those specification for us. Uhm, so 00:19:54.792-->00:19:59.167 for this, for this work I used a Capstone disassembler - a really great, a really great tool. Uhm, 00:19:59.167-->00:20:04.042 so, so using this by comparing the results of the actual execution to the disassembled 00:20:04.042-->00:20:08.708 results we can start pulling out interesting things, uhm, from the architecture. For example we 00:20:08.708-->00:20:12.458 can find undocumented instructions now, uhm, basically if the disassembler does not 00:20:12.458-->00:20:17.792 recognize a byte sequence, uhm, but that byte sequence generates anything other than an 00:20:17.792-->00:20:22.000 unidentified opcode exception when it executes that means that this instruction exists on the 00:20:22.000-->00:20:26.542 processor even though it's not on the documentation. Uhm, we can find software bugs this - 00:20:26.542-->00:20:30.917 the disassembler recognizes an instruction but the processor says that that instruction's 00:20:30.917-->00:20:35.375 length is something different. Uhm, that's usually indicative of a software bug. And with the 00:20:35.375-->00:20:39.167 search we can also find hardware bug and there's actually a really good heuristic I came up 00:20:39.167-->00:20:43.125 with for, for these hardware bugs. Basically when everything goes haywire you can dive in and 00:20:43.125-->00:20:46.250 figure what's really going wrong, uhm, on a system. So, I wanna give you a quick demo, 00:20:46.250-->00:20:49.667 uhm, not sure how well this is gonna show up on our, on our projectors but, uh, [background 00:20:49.667-->00:20:55.708 noise] Uhm, we're gonna run the sand sifter tool. [pause] And what we see here is, uh, our 00:20:55.708-->00:21:01.375 tool fuzzing the x86 processor, now in the top half of this image, uhm, we're seeing these 00:21:01.375-->00:21:05.917 instructions that the sifter, uhm, the injector is generating. On the right side you'll see the 00:21:05.917-->00:21:10.250 actual machine code - the raw bytes, uhm, that the processor is executing. The part 00:21:10.250-->00:21:13.667 highlighted in white down here - that's the observed length of the instruction on this 00:21:13.667-->00:21:17.667 processor. And Then on the left we see what capstone's doing, our disassembler, our ground 00:21:17.667-->00:21:21.375 truth think this instruction actually is. And the sifter is basically just watching for 00:21:21.375-->00:21:25.833 differences between those two sides and whenever it find a difference, whenever it finds an 00:21:25.833-->00:21:30.875 anomaly it's going to toss it into, uhm, this little section down here. Uhm, so that we can, 00:21:30.875-->00:21:36.625 uh, investigate that in a little bit more depth. So, after a little while, uhm, it will spit 00:21:36.625-->00:21:40.917 out a couple of anomalies, uhm, and we can, I will talk a little bit about what these actually 00:21:40.917-->00:21:47.167 are momentarily. But, uhm, uhm, the, the tunneling approach we're using right now is very 00:21:47.167-->00:21:52.292 very thorough. It does a really good job of searching the x86 instruction space, uhm, but it's 00:21:52.292-->00:21:57.083 also not very fast. It takes about a day for this scan to complete so, uhm, if want just 00:21:57.083-->00:22:02.292 quick results we can sort of change the fuzzing mode that we're using. So I added totally 00:22:02.292-->00:22:06.083 random fuzzing, Into this and it doesn't do as good a job searching but it does let you 00:22:06.083-->00:22:11.125 get very quick results. So, if we change over to totally random fuzzing mode we'll start to 00:22:11.125-->00:22:15.125 really see a lot of anomalies appearing in the processor. Basically what every one of 00:22:15.125-->00:22:20.708 these indicates is an instruction that exists on my x86 chip but that we're not told 00:22:20.708-->00:22:25.208 about in the reference manuals and I think that's, uhm, that's kind of scary that all of these 00:22:25.208-->00:22:30.708 things are on my processor, uhm, but nobody's acknowledging what they actually are. So, if you 00:22:30.708-->00:22:35.167 let this run for a day it will, uh, it'll quit, it'll dump out all the results, uhm, on most 00:22:35.167-->00:22:40.167 modern system it'll come up with one to three million, uhm, interesting things too look at. 00:22:40.167-->00:22:44.667 Now, that's a lot to go through by hand and try to make sense of so, I built this, uhm, 00:22:44.667-->00:22:49.667 summarizer, uh, tool. Again, I don't know how well that's gonna show up on the, on the monitors. 00:22:49.667-->00:22:53.625 But what the summarizer does is it tries to condense all that information and tries to pull 00:22:53.625-->00:22:57.125 out the most meaningful parts for you. So, for example, what you summarizer is saying here is 00:22:57.125-->00:23:02.417 that it found thirty-two different instructions that start with OF 18 that appeared 00:23:02.417-->00:23:06.667 to not be documented. Or if I dive into, uihm, one of these instructions I can drill down in 00:23:06.667-->00:23:12.583 a little bit more depth. So, it's telling me the instruction OF A7 C1 existed on this 00:23:12.583-->00:23:18.042 processor but, uhm, none of the three disassemblers that we gave that, uh, byte sequence to, 00:23:18.042-->00:23:22.375 understood what that instruction was. That's a really strong indication that this is an 00:23:22.375-->00:23:29.167 undocumented instruction sitting on my processor. So, uhm, [sigh] So basically this gave us a way 00:23:29.167-->00:23:35.167 to systematically scan our processors for secrets and, and bugs. So I, I scanned eight of 00:23:35.167-->00:23:39.208 the systems in my, in my test library and I want to share with you the things that we found. 00:23:39.208-->00:23:42.042 Cause we find some really interesting things. First we found hidden instructions in 00:23:42.042-->00:23:46.125 every single processor we scanned. [background noise] We found ubiquitous software bugs; 00:23:46.125-->00:23:49.917 software bugs; hypervisor flaws and some very very serious hardware bugs as well. So, I, 00:23:49.917-->00:23:53.583 when I set out to do this, uhm, I was trying to find hidden instructions on the processor, 00:23:53.583-->00:23:59.125 so let me share the hidden instructions , uh, with you first. So, when I scanned an 00:23:59.125-->00:24:03.958 Intel core i7 chip, so this was a chip manufactured in 2012. And these are some of the, some of 00:24:03.958-->00:24:11.833 the hidden instructions that I found. OF OD, OF 18, OF 1A, OF AE, uhm, most of these 00:24:11.833-->00:24:16.083 instructions are documented for certain combinations of bits inside of the instruction but 00:24:16.083-->00:24:20.458 even instruction without that specific combination - the ones that aren't documented - still 00:24:20.458-->00:24:25.958 run. Now, some of these, Intel has recently updated their, their processor specification to 00:24:25.958-->00:24:30.917 document these instructions. So, for example, OF 18 was added to a processor documents in 00:24:30.917-->00:24:37.000 December of 2016. The thing is I was scanning a chip made in 2012. These instructions were 00:24:37.000-->00:24:41.375 sitting on these processors for a a very, very long time before they were acknowledge by 00:24:41.375-->00:24:48.208 anybody. Uhm, this was another set of instructions I found on that Intel chips: DB EO, DF F1, 00:24:48.208-->00:24:53.708 CO DO, D2F6F7, uhm, a whole wide range of instructions which have absolutely no documentation in 00:24:53.708-->00:25:00.250 the reference manuals. Uhm, so that's a, a little worrisome to me so I started scanning other, 00:25:00.250-->00:25:03.875 uh, I scanned an AMD Geode processor. And what I found when I started scanning, uhm, 00:25:03.875-->00:25:09.500 processors from other manufacturers is that there's actually a lot of overlap in the 00:25:09.500-->00:25:15.500 undocumented instructions between these processors which kind of indicates that there's 00:25:15.500-->00:25:19.375 some kind of collaboration going on between different manufacturers as to what these 00:25:19.375-->00:25:22.583 undocumented instructions are actually going to be doing. Uhm, so the really interesting parts 00:25:22.583-->00:25:26.417 i thought were the places there was no overlap. Where this was really a unique set of 00:25:26.417-->00:25:30.708 instructions only on that processor. So for the AMD chip I scanned, the part where there 00:25:30.708-->00:25:35.917 was no overlap - the OF OF 40 80 followed by some byte. Now, AMD documented some versions of the 00:25:35.917-->00:25:39.542 last byte but the vast majority of those instructions aren't documented - it's just 00:25:39.542-->00:25:44.458 functionality hidden in the processor. So, next I scanned a VIA, a couple of VIA nano-chips, 00:25:44.458-->00:25:49.958 uhm, the unique parts of the VIA architecture were the instructions around OFA 7. So 00:25:49.958-->00:25:55.208 OF, OFA 7 is a unique VIA extension instruction set called the 'padlock instructions'. So 00:25:55.208-->00:26:01.667 you can actually lookup VIA's padlock reference manual and see that all of these instructions 00:26:01.667-->00:26:05.458 have to do with cryptographic functions. However, the padlock reference manual doesn't 00:26:05.458-->00:26:11.333 acknowledge the existence of C1 through C7 as that final byte. So, these are cryptographic 00:26:11.333-->00:26:14.000 instructions that are doing something on the processor, uhm, but there's no, no hint as to, 00:26:14.000-->00:26:21.292 as to what they're actually doing. So, so what do these do? Uhm, some of these instructions 00:26:21.292-->00:26:26.042 - if you Google around you'll find that people have stumbled across these in the past and 00:26:26.042-->00:26:28.208 have reversed engineered what they do. Basically looking at the register differences before 00:26:28.208-->00:26:31.167 and after an instruction executes in order to find out what that instruction must be 00:26:31.167-->00:26:34.417 doing. But some of these instructions have absolutely no record at all - they're not in 00:26:34.417-->00:26:37.875 the documents; they're not in the processor, processor specifications; they don't 00:26:37.875-->00:26:43.333 appear anywhere online, uhm, that's, that's, I think, Uhm, scary, In terms of trust for 00:26:43.333-->00:26:49.250 these things. So, uhm, so those are the hidden instructions I found, uhm, this thing also 00:26:49.250-->00:26:52.833 ended up returning a lot of software bugs. So, this is not what I set out to find but it's 00:26:52.833-->00:26:57.292 sort of interesting some of the results we got. Uhm, so the issue here is that the sifter 00:26:57.292-->00:27:01.583 process is forced to use a disassembler as its ground truth - it turns out every single 00:27:01.583-->00:27:06.333 disassembler that we tired for our ground truth was absolutely littered with bugs. So, most of 00:27:06.333-->00:27:10.792 the bugs we encountered with this tool. Uhm, only appeared in a couple of tools so they 00:27:10.792-->00:27:16.208 weren't all that interesting. Uhm, but some of the bugs we, we encountered appeared in all 00:27:16.208-->00:27:20.083 tools that we checked. Those can actually be used to an attacker's advantage. So, two of 00:27:20.083-->00:27:24.917 the more interesting ones I found were this 'jump and call' instruction. So, in a 64 bit 00:27:24.917-->00:27:31.250 version of the x86 architecture, uhm, the E9 instruction is a jump instruction; E8 is a call 00:27:31.250-->00:27:35.833 instruction and 66 is supposed to be what's a data size override prefix. The idea is 00:27:35.833-->00:27:41.000 that that 66 prefix on these instructions is supposed to change the default operand sizes 00:27:41.000-->00:27:49.125 of the instruction. Now, the default operand size here is 32 bit - so 66 is supposed to 00:27:49.125-->00:27:51.375 change that to either 16 or 64. But, on Intel processors, for whatever reason, they silently 00:27:51.375-->00:27:57.583 ignore that 66 prefix on these instructions alone. So, uhm, why does that matter? Well, turns 00:27:57.583-->00:28:04.167 out because of that everyone is parsing these instructions wrong - I tried this in IDA, Valgrind, 00:28:04.167-->00:28:11.542 GDB, objdump, visual studio, capstone, QEMU, uhm, every single tool I tried is parsing 00:28:11.542-->00:28:14.833 these instructions incorrectly. And, and here's sort of how we can use that to our advantage as 00:28:14.833-->00:28:18.333 an attacker. So, uhm, here we're seeing how AIDA parses this instruction - you'll see that 00:28:18.333-->00:28:23.542 IDA thinks this is a 4-byte instruction; it saw the 66 override - thought that changed 00:28:23.542-->00:28:28.833 the next, uh, uh, operand to 16 bits instead of 32 bits so IDA's getting the wrong length for 00:28:28.833-->00:28:32.208 this instruction. Here's visual studio's view of the instruction, visual studio 00:28:32.208-->00:28:37.667 actually recognizes that 66 didn't change the operand size, uhm, but it thinks that 66 00:28:37.667-->00:28:41.708 caused the destination of this jump to get truncated to 16 bits - that's also not the correct, 00:28:41.708-->00:28:46.458 uhm, behavior. So, visual studio isn't able to resolve the, uh, the target of this jump. So, you 00:28:46.458-->00:28:50.958 can actually use this uhm, for some malicious things by throwing off the disassembler - 00:28:50.958-->00:28:57.167 so I made a little bit, a little malicious program. And, and had obs jump try to analyse it. So, 00:28:57.167-->00:29:02.125 you'll see here obs jump is miss analyzing, miss parsing that jump instruction. It gets the 00:29:02.125-->00:29:06.458 wrong size for that jump instruction. Now our obs jump thinks we have a jump followed 00:29:06.458-->00:29:10.958 by an add, followed by an add, followed by an add, followed by an move adds except obs jump got 00:29:10.958-->00:29:16.792 the wrong size for this instruction - it's messed up all of the previous instruc; or all 00:29:16.792-->00:29:20.000 of the following instructions that it tries to disassemble. So, that's useful to because I 00:29:20.000-->00:29:24.625 embedded a malicious instruction inside of the operands for one of these move abbs instructions. 00:29:24.625-->00:29:27.375 What this jump is really gonna do it's gonna jump into the middle of one of these 00:29:27.375-->00:29:32.667 instructions and execute malicious code that obs jump can't see. And to highlight that 00:29:32.667-->00:29:36.958 - a sort of implications of that, uhm, I wrote this little program that you can run in 00:29:36.958-->00:29:40.833 QEMU, uhm, so it's a popular emulator. So, what I'm going to do here, I'm going to SSH into 00:29:40.833-->00:29:47.125 our QEMU vm and I'm gonna run my little program and as far as QEMU can tell when this program 00:29:47.125-->00:29:51.625 runs it's just totally benign behaviour - it prints out "I'm totally benign". And no matter 00:29:51.625-->00:29:56.000 how many times you run this QEMU is only going to see benign behavior but that's because QEMU 00:29:56.000-->00:29:59.583 is miss parsing a jump instruction in this code. So, you, when you run this in Bare 00:29:59.583-->00:30:02.958 Metal you find this is actually a malicious program - it prints out "I'm actually malicious". 00:30:02.958-->00:30:09.583 [laughter] And the neat thing about this there's, there's not any QEMU detection logic inside 00:30:09.583-->00:30:14.917 of this program. The only thing that allow this is one misparsed jump instruction that, Everybody 00:30:14.917-->00:30:19.208 is getting wrong. So, I think that was, uh, that was kinda interesting. Uhm, so I was 00:30:19.208-->00:30:23.000 curious about why everybody was miss parsing these jump instructions, uh, and my best 00:30:23.000-->00:30:28.250 theory right now is that AMD actually obeyed that override prefix on this whereas Intel 00:30:28.250-->00:30:33.083 ignores that override prefix in their architecture. Uhm, and that's a little bit troubling 00:30:33.083-->00:30:37.500 when we can't agree on a standard for our processor architecture. The last time when 00:30:37.500-->00:30:41.458 that happened, when Intel deviated from AMD's specifications, uh, just a 00:30:41.458-->00:30:45.708 little bit it resulted in the very serious vulnerability called the 'sysread bug' that 00:30:45.708-->00:30:50.458 allow kernel privilege escalation. Uhm, so you might think why don't we update all of 00:30:50.458-->00:30:54.125 our tools to fix this issue? Why don't we just do it the way Intel does? They have 95% of the 00:30:54.125-->00:30:58.333 market share. Well, you can do that but then AMD is going to be vulnerable. There's really no 00:30:58.333-->00:31:02.542 winning here, no correct answer. Uhm, and I think it kind of highlights the impractically 00:31:02.542-->00:31:06.333 complex nature of this architecture when tools can't even analyze a simple jump 00:31:06.333-->00:31:11.792 instruction correctly. So, uhm, switching gears a little bit - uhm, early on in the development 00:31:11.792-->00:31:16.792 of this I was getting fairly tired of waiting a day for my scans to, uh, Complete. So, I 00:31:16.792-->00:31:20.833 wanted scans that could run a lot faster - I wanted to enumerate the instructions in 00:31:20.833-->00:31:24.625 the instruction, the instruction set in an hour instead of a day. So, I added multi-core support 00:31:24.625-->00:31:28.375 to this fuzzer, uhm, and I thought wouldn't it be neat if could run this thing on 20-core? 00:31:28.375-->00:31:33.042 So, I rented an Azure instance, uhm. And ran this tool. But I very quickly find out that my 00:31:33.042-->00:31:38.167 tool wasn't running correctly on my Azure instance. And tried to that there's a small bug in the 00:31:38.167-->00:31:41.875 Azure hypervisor. Namely Azure doesn't emulate the trap flag correctly - if the trap flag is 00:31:41.875-->00:31:47.708 set on the CPUID instruction. So, the idea here is that if you execute CPUID, uhm, it causes a 00:31:47.708-->00:31:53.167 vm exit and the hypervisor takes over. [background] And the supervisor's supposed to take 00:31:53.167-->00:31:56.500 over and emulate that CPUID instruction and then the last thing it's supposed to do is 00:31:56.500-->00:31:59.833 check whether or not the trap flag was set - if it was it should inject the trap into the 00:31:59.833-->00:32:05.833 guest vm. Azure forgets that last step, uhm, and what that, uh looks like is, is something 00:32:05.833-->00:32:11.500 like this. So, I've got a little program here, uhm, and I'm gonna run it on Bare Metal, uh, it's 00:32:11.500-->00:32:16.042 basically gonna check that, CPUID trap behaviour. And it's telling me it's gonna execute a 00:32:16.042-->00:32:20.833 CPUID NOP NOP instruction and the trap flag is gonna be set on the first CPUID instruction. Now 00:32:20.833-->00:32:25.458 it expects to get a trap at that first NOP and sure enough when ti ran the code it got a trap at 00:32:25.458-->00:32:30.167 that first NOP instruction. But now what I'm gonna do - I'm gonna SSH into, uh, my Azure 00:32:30.167-->00:32:35.292 instance and try to run that exact same piece of code. Uh, what you'll see is we get 00:32:35.292-->00:32:41.708 different results inside of the Azure hypervisor, uh, when I executed the CPUID NOP NOP, We 00:32:41.708-->00:32:45.750 expected a trap at that first NOP but Azzure gave us a trap at that second NOP. Uhm, that's a 00:32:45.750-->00:32:50.125 very small bug in the hypervisor. So, uhm, this isn’t a security protocol bug, it's 00:32:50.125-->00:32:53.125 not an especially big deal, it would be pretty hard to run across this in a normal 00:32:53.125-->00:32:57.500 situation but it's always a little bit troubling when the hypervisor can't faithfully 00:32:57.500-->00:33:02.417 emulate the underlying hardware. Uhm, do that sort of brings us to the last class of issues I 00:33:02.417-->00:33:07.333 found with this processor scanning tool. Uhm, we found some hardware bugs, and hardware 00:33:07.333-->00:33:11.458 bugs are always troubling no matter how small they are because a bug in your hardware 00:33:11.458-->00:33:16.417 means you have that exact same bug in all of your software. Hardware bugs are very hard to 00:33:16.417-->00:33:21.208 find and they're very difficult to fix. So, I started out scanning some Intel processors - 00:33:21.208-->00:33:25.792 a core, a Pentium, and a core i7 processor. And I didn't actually find anything too interesting on 00:33:25.792-->00:33:31.417 these - I did find the F00F bug on the Intel Pentium - that's a, a, a malform instruction that 00:33:31.417-->00:33:35.958 can totally lock the processor but that's a very old, very well-known bug. Uhm, so that was 00:33:35.958-->00:33:40.875 kind of anticlimactic but it sort of validate that this tool is capable of finding these 00:33:40.875-->00:33:46.250 malformed instructions that could have serious, uh, uh, consequences. Uh, next, I 00:33:46.250-->00:33:51.250 scanned an AMD - a couple of AMD systems. On several of these AMD systems I noticed, uhm, uhm, 00:33:51.250-->00:33:56.583 some odd behavior - basically they could generate an undefined opcode exception before they 00:33:56.583-->00:34:00.625 completed the instruction fetch. So, I dove into AMD specifications that's not the 00:34:00.625-->00:34:05.042 correct behavior for these processors, uhm, basically a page faltering instruction fetch 00:34:05.042-->00:34:11.625 should, should take priority over an undefined opcode exception. Uhm, so that was an 00:34:11.625-->00:34:15.542 errata. Uhm, until when I was getting these slides ready, uh, to present I found AMD - 00:34:15.542-->00:34:18.917 somebody at AMD must have found this recently because they updated their document in March 00:34:18.917-->00:34:23.958 of 2017 - to have this tiny little footnote down here. This footnote basically says "okay, 00:34:23.958-->00:34:28.333 this behavior is allowed". And I think this is a bit, a bit of a copout. Uhm, if you've got a 00:34:28.333-->00:34:32.708 processor errata and you update your documents to allow that errata - is it still an errata? 00:34:32.708-->00:34:38.292 [laughter] Uhm, I think it is, but, uhm, maybe it's not anymore. I scanned a Transmeta 00:34:38.292-->00:34:42.542 processor - so, transmitter's not so popular anymore but they were kind of popular few years 00:34:42.542-->00:34:45.792 ago. Uhm, I found some interesting behavior on a Transmeta processor with the 00:34:45.792-->00:34:51.875 instructions OF 71, 72 or 73 the Transmeta would give us a, uh, floating point exception during 00:34:51.875-->00:34:56.917 the instruction fetch. So, this is also the incorrect behavior. Basically, if you had an FPU 00:34:56.917-->00:35:02.500 exception pending and executed one of these instructions you'd receive an FPU exception in the 00:35:02.500-->00:35:07.708 middle of that instruction fetch. Uhm, the correct behavior here, if that last byte of the 00:35:07.708-->00:35:11.083 instructions on an invalid page is the page fault. Uhm, so again, this is a very minor 00:35:11.083-->00:35:15.542 errata but it's always little unsettling when there are bugs in our processors. Uhm, but 00:35:15.542-->00:35:19.542 that, that takes us to our last finding and I thin, I think this is the most interesting one. 00:35:19.542-->00:35:24.708 Uhm, we actually found that on one specific processor what appears to be a halt and catch 00:35:24.708-->00:35:29.417 fire instruction. So, a, [laughter] A 'halt and catch fire' instruction, if you 00:35:29.417-->00:35:33.583 haven't, if you haven't seen this, uhm, is a - well, it can mean a lot of things but in this 00:35:33.583-->00:35:37.542 case it's a single malformed instruction that when we execute it, execute it in ring three - 00:35:37.542-->00:35:42.542 the least privileged realm of execution on these processors - it completely locks, uh, the 00:35:42.542-->00:35:48.042 processor. So, I wanted to make really sure this wasn't a, uh, kernel bug, uh, instead. So, I 00:35:48.042-->00:35:51.583 tested this on two different, two different windows kernels; three different Linux kernels 00:35:51.583-->00:35:55.458 but then I really, really wanted to be sure this wasn't a kernel bug. Uhm, so I actually wrote a 00:35:55.458-->00:35:59.875 small loadable kernel module for Linux that would hook all of the interrupts and the interrupt 00:35:59.875-->00:36:02.792 description table dump serial debug information whenever interrupts occurred. I was a 00:36:02.792-->00:36:06.958 little bit worried that maybe this infrastructure was causing what's called an 'interrupt 00:36:06.958-->00:36:10.292 storm' to make it look like the processor was locked when it wasn't really locked. But this 00:36:10.292-->00:36:13.667 also seems to validate the processors is completely locked when we execute this 00:36:13.667-->00:36:18.417 instruction. So, unfortunately I found this about two weeks ago during one my scans which means 00:36:18.417-->00:36:21.500 the vendor has not had time to respond to this issue. So there's no detail available 00:36:21.500-->00:36:27.875 right now on the actual chip affected; the vendor or the actual instruction format. But I 00:36:27.875-->00:36:31.458 did wanna give you, uh, demo of, uh, this thing in action. So, I've got Debian booted on this 00:36:31.458-->00:36:36.792 processor - you can see it can just run pretty much any program. It can run 'Hello 00:36:36.792-->00:36:40.583 World' and print out 'Hello World'. But when I run 'A dot out', uhm, it's gonna do 00:36:40.583-->00:36:45.500 something different. Now, the only instruction in A dot out is this one malformed instruction - 00:36:45.500-->00:36:49.708 that's, that's all there is. And when I run it the processor locks. Now, I don't mean the 00:36:49.708-->00:36:55.083 process locks, uhm, I mean the processor itself is completely locked up at this point. You can 00:36:55.083-->00:36:58.833 try and use 'control C' to break out of this problem. you can choose to change levels. Uhm, 00:36:58.833-->00:37:04.542 the system won't respond anymore. You can even try the Linux magic SYSRET keys in order 00:37:04.542-->00:37:08.583 to just crash or reboot the system and you'll get no response. Cause that processor 00:37:08.583-->00:37:15.125 is done executing instructions at this point, [laughter] So, uh, uh, I was pretty excited 00:37:15.125-->00:37:20.250 about this, uhm, as far as I know this is the first such attack on x86 found in 20 years. 00:37:20.250-->00:37:33.083 The original version of this, uhm, [applause] [cheering] So, so the,. [applause] Alright, so 00:37:33.083-->00:37:39.125 the original uhm, halt and catch fire instruction was that Pentium F00F bug on the original 00:37:39.125-->00:37:43.167 Pentium in, uh, 1997, uhm so I think that's, that's pretty cool and I don't wanna, don't wanna 00:37:43.167-->00:37:48.708 try to make people panic, Uhm, this is on, uh, very specific chip that is not in widespread 00:37:48.708-->00:37:54.917 use. So, it's not like the sky is falling here. I think the, the interesting part about this 00:37:54.917-->00:37:59.708 is that we have a tool that can actually find these kinds of very serious bugs because it is, 00:37:59.708-->00:38:04.083 uh, a serious bug. And should be apparent I think that this is a, a very serious security concern 00:38:04.083-->00:38:10.292 if an unprivileged user on the process can initiate an entire processor DOS, That's gonna lock 00:38:10.292-->00:38:15.250 everyone else out of the system. Um, so, so it is a really neat thing. And, uh, I'm hoping and, 00:38:15.250-->00:38:19.125 uh, and if everything goes well with responsible disclosure I'll be able to tell you more about 00:38:19.125-->00:38:24.000 that within the next month if you, uh, stay tuned. So, uhm, I didn't want this to just be an 00:38:24.000-->00:38:27.458 academic thing. I wanted people to actually be able to use this tool and scan their processors. 00:38:27.458-->00:38:34.125 So, this now is open sourced on GitHub - that's Github dot com xor EAX; EAX, EAX, slash 00:38:34.125-->00:38:37.792 sandsifter. Uhm, and I encourage you to try this thing out because we don't really know 00:38:37.792-->00:38:41.750 what's in our processors. So, uhm, you should use this to audit your processor, find your 00:38:41.750-->00:38:46.833 secret, secret instructions in it. Break disassemblers, break emulators, hypervisors. Find 00:38:46.833-->00:38:51.167 these halt and catch fire instructions like my system didn't literally halt and catch 00:38:51.167-->00:38:54.958 fire but yours might and I think that would be awesome! [laughter] So, [laughter] So, 00:38:54.958-->00:38:59.375 you won't know unless you, you actually try this out on your specific system. And I wanna, I 00:38:59.375-->00:39:03.292 wanna highlight I've only scanned few systems with this and this is really just a 00:39:03.292-->00:39:07.500 fraction of what I found on those few systems. This is just what I could cram into a 45 00:39:07.500-->00:39:11.333 minute presentation and so if that's what I found on these few scans - who knows what you'll 00:39:11.333-->00:39:15.417 find on, uh, on your computers. So, uhm, check your system, if you're, if you're not sure, uhm, 00:39:15.417-->00:39:19.875 about the results that this thing is generating - you know, dumps out all these weird 00:39:19.875-->00:39:23.750 instructions, uhm, You can send me those results, I'd be happy to, uh, try to dissect them for 00:39:23.750-->00:39:27.708 you. Uhm, but the real point here is we need to to stop blindly trusting specifications. 00:39:27.708-->00:39:34.000 Uhm, if we don't trust software we shouldn't trust hardware. We need tools that would actually 00:39:34.000-->00:39:37.458 audit our processors and make sure that they're really doing what we're told they're doing. 00:39:37.458-->00:39:42.375 And that's what sandsifter let's us do. It sort of gives us a really important critical first 00:39:42.375-->00:39:47.917 step in introspecting this black box that's at the center of all of our systems. Uhm, so, again, 00:39:47.917-->00:39:51.083 you can find this on Github right now - it's the sandsifter project. Uhm, you can find some 00:39:51.083-->00:39:55.708 other, uhm, fun things that I've tinkered with over the last few years on there. Like I wrote a 00:39:55.708-->00:39:59.750 single instruction C-compiler for no reason. [laughter] Uhm, I wrote some tools for 00:39:59.750-->00:40:04.833 manipulating program control flow to, uh, show images in IDA. A couple of years ago I released 00:40:04.833-->00:40:10.417 an architectural exploit on x86 and there's there's lots of other random things that I've, 00:40:10.417-->00:40:13.042 I've played around with over the last few years that you can check out on there. If anybody 00:40:13.042-->00:40:16.750 has feedback or ideas I would absolutely love to discuss that with you. Uhm, so grab me after 00:40:16.750-->00:40:20.333 the talk or, uh, you can reach out to me - my name is Christopher Domas, I'm at 00:40:20.333-->00:40:27.208 twitter at xor EAX EAX EAX - or same thing at gmail dot com.' And like I said I'll hopefully 00:40:27.208-->00:40:33.375 be releasing all the details for that processor vulnerability within the next month. Uhm, so 00:40:33.375-->00:00:00.000 thank you everyone! [applause]