 This is, uh, gonna cover a little bit about Linux kernel exploitation, um, specifically, um, using an uninitialized stack pointer. Um, I thought it was an interesting exploit, but I'll get to that. Um, so this is a 20 minute talk, so I'm going to blast through as much as I can. Um, with a quick intro. Um, I'm case, uh, it's pronounced case, the spelling is Dutch and it's my grandfather's fault, but um, you can see me on Twitter there. Um, I've been coming to Defcon for quite some time, uh, started participating in, um, Capture the Flag in about 2003 and, uh, along with the rest of, uh, Team Last Place, we won CTF in 2006 and 2007, so that was quite a bit of fun, but since, uh, we played CTF so much, I rarely actually went out to go, uh, see any talks or try to give any talks since we were doing CTF the whole time. Um, but I still play in quals cause that's fun. Um, I'm a member of the, uh, Ubuntu security team. I started that in 2006. Um, so my background is in trying to get compiler hardening in better shape for Ubuntu and now I'm, uh, looking a little bit more at kernel hardening. So, uh, a quick overview of Linux kernel exploitation. Um, the, the main, the main goal for any kind of kernel attack is to get, uh, control over execution flow. Um, usually you can just set the user ID of the process you're using to zero in your root and you have full control over the system. Um, but, uh, actually finding targets to do this is, is what's tricky. Um, you need an arbitrary write to start with and then going from there is what, what makes things more fun. Um, so with an arbitrary write once you've got that, um, the way to change program flow is to change function pointers. So you can aim the, the normal operation of the kernel into something that you have written as the attacker. Um, function tables are great for that because they're just lists of functions that if you can find a way to trigger that function, then you have managed to trick the kernel into running your code. Um, one of the first ones that, uh, I, I played with a bit was, uh, security ops since I was familiar with the Linux security module interfaces. Uh, that's basically for SE Linux, App Armor, other LSMs use the security ops function table for high level actions. Um, so I like replacing the ptrace access check because it was up the top. It didn't require too much cleanup after you used it. Um, there's plenty of other things. Um, you could use the IDT. There's a good frack article on that. There's plenty of stuff to read on that. Um, but, uh, my favorite at this point is now using a, a single sock struct. So if you can create a socket, you've got a, uh, you've got the destructor when the socket goes away that gets called. And if you can write, overwrite that function when you close the specific socket, it'll actually run the code that you wanted, uh, wanted it to run. And it's very easy to find that function because it's exported by the kernel for you see. Um, but all that's unimportant if you don't have a flaw. Obviously you need that arbitrary write to begin with. Um, so I started looking at interface boundaries, you know, where things make transitions. Uh, and I was especially interested in, uh, copy from user because that's where you're pulling, you're pulling information from user space and putting it somewhere in the kernel. So anything that goes wrong in that is gonna be an issue, is gonna be a nice thing. So, um, there are a lot of collars, uh, about 4,000. So, um, it was a bit daunting to just start with that. But, uh, so looking, I'm looking for things that were, length isn't checked, source isn't checked, destination isn't checked, all that. Um, we don't really need advanced static analysis. Grep will work most of the time. Um, in fact, there's a version of copy from user that does not perform access checks at all. Uh, there were very, very few collars of that and, uh, one of them was in Intel DRM, another one was in RDS. Um, but, uh, with just standard copy from user, I thought that I should go a little bit beyond standard regular expressions. Um, so I started looking at a tool called, uh, Cookson L, which is traditionally used for semantic patching. You wanna, you wanna patch a behavior that's going on in a source tree. Um, you know, replace the, something about a structure, it was much easier to do that. But I, I was really using it for semantic grep, and I'll give you a quick example. Um, uh, the first thing I would do is basically, you define a position, so the copy from user is at position P, is the first top of, the top of that. And then, a whole extensive list of, of white lists, of things that are verifiably correct. Um, so an example, white list pattern here is copy from user into the address of a, of a, of a structure that we've actually done a size of on. So that's not overflowed, we know it's the right size. So you can create a huge list of white, of good patterns that make sense, and you don't need to pay attention to. And then the final, uh, chunk of the semantic grep is just to, if you have a copy from user and it is not at the same position as any of the white lists, then you have something that actually needs analysis. Um, and that let me look at, uh, a bunch of different things. Um, so I tried to focus on areas that didn't have a lot of usage or users. Um, there's, there have been plenty of vulnerabilities in rare network protocols. Um, or interfaces with not a lot of consumers. Um, especially compact. Um, so when you're dealing with running 32 bit on a 64 bit or you'd have different API versions like the, the Linux for video stuff, there's a lot of issues. In fact, the issues are so bad that you have severe problems come back. Um, the, the CVE that I mentioned, CVE, uh, 2007, 45, 73 and 2010, 33, 01, it's the same issue. They just reintroduced it three years later. Um, so what I found was actually a compact interface that had no users because the code could not possibly have ever worked the first time. Um, so I apologize for dense code. Hopefully you can read some of this. But, um, this was in the V4L compact issues. And, uh, the, the first top bold piece was a copy from user that immediately jumped out on a semantic patch, uh, because KP data, which is the target and UP data size have no relationship at all. That's obvious. And as I went back through it, I realized that KP, this, this pointer in KP was not validated anywhere. In fact, it wasn't even filled in anywhere. It came from a local stack, uh, area of memory. And they're just, there was no way to control KP data. So if you ever called this IO control, you would crash your system because you'd be writing crap into who knows where. Um, but I got the thinking, you know, it's uninitialized, which really is, means that it was initialized, but you just didn't know from what. So if you can control the execution environment leading up to that, then it is initialized because you put something there ahead of time. Um, so, uh, and the question is, uh, one of the questions is why, you know, why does this even show up? Why didn't anyone notice it? And the problem is that we passed everything by, by pointer values. So the compiler just ignored it, figured we knew what we were doing when we built it. So, uh, to control this variable, you find something else that builds the stack in a similar fashion. Um, lucky for me, this was in an IO control, which means that you just pick a different option for your IO control and you'll actually have exactly the same stack layout. And in this case, they had a union of options. It was like it was made to be, uh, overlapped. So there's this other function, get video tuner 32, um, that would copy everything from user space into this union on the stack and do some other stuff in return. And that would actually leave us with the stack in, in the state that we had left it. Um, so I, you had to take a look at the two different structures that are there. Um, our, our target here is the video code 32. We want data. We want to be able to control data. So we have to figure out where it is in relation to the other structure in the union. Um, and it was relatively straightforward because, uh, in video tuner, there was this large name string. Um, so looking at it more graphically, there's all the crap before the IO control on the stack. And then after we've returned from, uh, from the, the tuner IO control, what's left on the stack is whatever we had put in, in that structure. And then we can go and call the microcode function and whatever was there will end up in, inside the, the data field. Um, and there are no special tricks for data size and for the length and source that we're doing. Um, the only thing we need to do is calculate, and that's the C for just quickly calculating where we are offset inside the other, uh, the other structure. Um, now the one problem that you run into is that you have to, you have to call these IO controls in order because if you do anything else between the two IO controls, you've just used the stack for something else. So you can't use any, any syscall wrappers like libcsyscall. You can't actually use that because it's going to go off and do other things with your stack. Um, you have to actually call it directly in assembly. You can't, you know, aid in debugging by sticking a printf between the two because of course you're making yet another syscall in between. So, um, you have to be very careful about that. Additionally, the kernel may go off and do other work, uh, between the two, uh, on behalf of your process if it's a new code path. Uh, so the, the solution for that was just to call the IO control a whole bunch of times in a row first so that it finished any work it had to do with page tables, got everything in line for you to then call the final one. Um, and another small challenge is these are all compact syscalls. So they're in 32-bit, but we're actually trying to attack a 64-bit host. So we have to call a 32-bit syscall from a 64-bit executable, um, which is just some more assembly, um, which I have here. Basically the, the int 80 will force a 32-bit syscall. So this is a, a quick C wrapper to shove the arguments I need into a 32-bit syscall, um, and return. And then the action is to beat on it with the one that will prime the stack. Um, so call it a bunch of times first, the, the tuner IO control, and then go after it with the buggy code since we know what's in memory now and we can actually reliably write stuff. But that just gets us an overwrite. How do we actually control it? Um, I used the, the sock struct exploit, um, from Dan Rosenberg's code recently, um, and you basically open up a socket and it shows up in prognet tcp. In bold is the, uh, first is the port that I'm listening on in hex and the, the other bold value is the actual kernel location of the socket that you need to target. So you just ask the kernel nicely for what, um, for what, uh, you want to overflow or overwrite rather. Um, in modern versions of the kernel, uh, K point of restrict now blocks prognet tcp, but you can still get the same information out of a, out of a net link thing that is still open. Um, so you just have to modify your code a little bit. So then we're gonna create a payload that we want the kernel to run. Uh, this is based on Brad Spengler's enlightenment, uh, code where you basically just create new credentials as root and commit them to the local process. So you're just setting your UID to zero. This is the, this is the entire function that the kernel needs to run to, to give you root as that process. Um, and finally you just, after you perform the overwrite, uh, you just close the socket and it'll call that function for you and everything's nice. The kernel cleans up for you. Um, and, uh, I can show you a small demo of this running. If I can see that, hopefully everyone can see that. It's not gonna let me. How about that? Okay. So, uh, a lot of demos sort of, um, aren't very interesting because they effectively just, uh, show you a prompt. Like that's not very useful. That doesn't prove much and it's not very exciting. It's not very dramatic. Um, so I decided I ought to have this demo with a useless Hollywood drama mode. Um, so you can, it can be exciting and we can be on the edge of our seats waiting for something to happen. So this is resolving the credentials or the, the cred, the cred calls. And we have to find where we are in memory, open the socket and figure out where it is in memory, open the video device. It's very exciting. Do the IO control. Did it work? It did. It did work. And if you don't wanna wait for it, just run it without the dash dash Hollywood option. We'll just run straight through. Um, and that's basically it. I can go all the way through all my slides again and get to the end that says questions. And that's it.