We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Kernel Exploitation Via Uninitialized Stack

00:00

Formal Metadata

Title
Kernel Exploitation Via Uninitialized Stack
Title of Series
Number of Parts
122
Author
License
CC Attribution 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
Leveraging uninitialized stack memory into a full-blown root escalation is easier than it sounds. See how to find these vulnerabilities, avoid the pitfalls of priming the stack, and turn your "memory corruption" into full root privileges. Kees Cook is part of the Ubuntu Security Team, where he tries to harden Ubuntu in particular, and Linux in general, against attack. In addition to being an Ubuntu developer, he's a member of the Ubuntu Technical Board, a Debian Developer, and a Kernel.org admin. As a long-time DEF CON Capture the Flag participant, he's especially proud of being part of Team 1@stPlace and winning in 2006 and 2007. Twitter: @kees_cook
54
106
112
Stack (abstract data type)Canonical ensembleKernel (computing)Control flowFunction (mathematics)Directed setRootKernel (computing)Pointer (computer programming)CASE <Informatik>BitExploit (computer security)
Motion captureFlagInformation securityBitKernel (computing)Motion captureShape (magazine)CASE <Informatik>Information securityMultiplication signCompilerTwitterComputer animation
Kernel (computing)Read-only memoryControl flowTable (information)Function (mathematics)Ideal (ethics)TheoryBoundary value problemInterface (computing)Exploit (computer security)Kernel (computing)1 (number)Electronic mailing listGoodness of fitGame controllerInformation securityBitSystem callProcess (computing)Operator (mathematics)CodeFunctional (mathematics)Point (geometry)Network socketMathematicsPhysical systemModule (mathematics)Latent heatTable (information)Normal operatorPointer (computer programming)Level (video gaming)Group actionControl flowInterface (computing)RootBoundary value problemDataflowSingle-precision floating-point formatBookmark (World Wide Web)Right angleMobile appWritingRoutingComputer animation
SpacetimeInformationKernel (computing)Computer animation
Regulärer Ausdruck <Textverarbeitung>Fluid staticsMathematical analysisCAN busCommunications protocolComputer networkInterface (computing)Focus (optics)System callRevision controlPatch (Unix)Goodness of fitCommunications protocolRevision controlInterface (computing)Position operatorAreaDigital rights managementData structureVideoconferencingSemantics (computer science)IntelDifferent (Kate Ryan album)Multiplication signLengthPattern languageBitFluid staticsExtension (kinesiology)CodeStandard deviationElectronic mailing listSource codeAddress spaceRegulärer Ausdruck <Textverarbeitung>Mathematical analysisVulnerability (computing)Computer animation
CAN busStrutVideoconferencingFunction (mathematics)Maxima and minimaReading (process)Shooting methodOvalExecution unitConvex hullCodeFluid staticsContent (media)Stack (abstract data type)Patch (Unix)Integrated development environmentPointer (computer programming)Semiconductor memoryCrash (computing)CodeAreaSemantics (computer science)CompilerGame controllerArithmetic meanMultiplication signComputer animation
OvalFunction (mathematics)Range (statistics)FlagAsynchronous Transfer ModeVariable (mathematics)Greatest elementRead-only memorySource codeStack (abstract data type)Maxima and minimaKernel (computing)Process (computing)System callSpacetimeWeb pageTable (information)Prime idealoutputHoaxCodeStack (abstract data type)Multiplication signTheory of relativitySystem callKernel (computing)Computer configurationData structureString (computer science)Parameter (computer programming)Row (database)Data compressionCodeWrapper (data mining)Group actionSemiconductor memoryLength32-bitFunctional (mathematics)Game controllerSource codeOrder (biology)Interior (topology)Web pageSpacetimeState of matterVideoconferencingLine (geometry)Process (computing)Field (computer science)outputCASE <Informatik>SeitentabelleLibrary (computing)Computer animation
RootStrutCodeOvalGamma functionComputer wormNetwork socketDemo (music)Kernel (computing)RootSystem callElectronic mailing listEntire functionUniform resource locatorCodeNetwork socketProcess (computing)Block (periodic table)LengthWeightComputer wormDemo (music)Revision controlFunctional (mathematics)Buffer overflowPointer (computer programming)HexagonFunction (mathematics)Link (knot theory)BitComputer animation
Demo (music)Information securityComputer animation
Demo (music)Network socketSystem callVideoconferencingOpen setDemo (music)Semiconductor memoryQuicksortComputer configurationAsynchronous Transfer ModeFigurate numberGame controllerComputer animation
Stack (abstract data type)Kernel (computing)TheoryBoundary value problemInterface (computing)Canonical ensembleSource codeCodeSlide ruleComputer animation
Transcript: English(auto-generated)
This is gonna cover a little bit about Linux kernel exploitation, specifically using an uninitialized stack pointer. I thought it was an interesting exploit, but I'll get to that. So this is a 20 minute talk, so I'm going to blast through as much as I can with a quick intro.
I'm Case, it's pronounced Case. The spelling is Dutch and it's my grandfather's fault, but you can see me on Twitter there. I've been coming to Def Con for quite some time. I started participating in Capture the Flag in about 2003, and along with the rest of team last place,
we won CTF in 2006 and 2007, so that was quite a bit of fun. But since we played CTF so much, I rarely actually went out to go see any talks or try to give any talks since we were doing CTF the whole time. But I still play in quals because that's fun.
I'm a member of the Ubuntu security team. I started that in 2006. So my background is in trying to get compiler hardening in better shape for Ubuntu, and now I'm looking a little bit more at kernel hardening. So a quick overview of Linux kernel exploitation.
The main goal for any kind of kernel attack is to get control over execution flow. 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.
But actually finding targets to do this is what's tricky. You need an arbitrary write to start with and then going from there is what makes things more fun. So with an arbitrary write, once you've got that, the way to change program flow is to change function pointers.
So you can aim the normal operation of the kernel into something that you have written as the attacker. 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. One of the first ones that I played with a bit
was security ops since I was familiar with the Linux security module interfaces. That's basically for SELinux, AppArmor, other LSMs use the security ops function table for high level actions. So I like replacing the ptrace access check because it was up at the top. It didn't require too much cleanup after you used it.
There's plenty of other things. You could use the IDT. There's a good frack article on that. There's plenty of stuff to read on that. But my favorite at this point is now using a single sock struct. So if you can create a socket, you've got the destructor when the socket goes away
that gets called. And if you can overwrite that function when you close the specific socket, it'll actually run the code that you wanted it to run. And it's very easy to find that function because it's exported by the kernel for you to see. But all that's unimportant if you don't have a flaw. Obviously you need that arbitrary write to begin with.
So I started looking at interface boundaries, where things make transitions. And I was especially interested in copy from user because that's where you're pulling information from user space and putting it somewhere in the kernel. So anything that goes wrong in that is gonna be a nice thing.
So there are a lot of callers, about 4,000. So it was a bit daunting to just start with that. So I'm looking for things that length isn't checked, source isn't checked, destination isn't checked, all that. We don't really need advanced static analysis. Grep will work most of the time.
In fact, there's a version of copy from user that does not perform access checks at all. There were very, very few callers of that. And one of them was in Intel DRM, another one was in RDS. But with just standard copy from user, I thought that I should go a little bit beyond standard regular expressions.
So I started looking at a tool called Cookson L, which is traditionally used for semantic patching. You wanna patch a behavior that's going on in a source tree, replace something about a structure. It was much easier to use that. But I was really using it for semantic grep, and I'll give you a quick example.
The first thing I would do is basically you define a position. So the copy from user is at position P is the top of that. And then a whole extensive list of whitelists of things that are verifiably correct. So an example whitelist pattern here is
copy from user into the address 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 good patterns that make sense and you don't need to pay attention to. And then the final 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 whitelists, then you have something that actually needs analysis. And that let me look at a bunch of different things. So I tried to focus on areas that didn't have a lot of usage or users.
There have been plenty of vulnerabilities in rare network protocols or interfaces of not a lot of consumers, especially Compat. So when you're dealing with running 32-bit on a 64-bit or you have different API versions like 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. The CVE that I mentioned, CVE-2007-4573 and 2010-3301, it's the same issue. They just reintroduced it three years later. So what I found was actually a Compat interface that had no users because the code could not possibly
have ever worked the first time. So I apologize for dense code. Hopefully you can read some of this. This was in the v4lcompat issues. And the first top bold piece was a copy from user that immediately jumped out on a semantic patch
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 pointer in KP, was not validated anywhere. In fact, it wasn't even filled in anywhere. It came from a local stack area of memory
and there was no way to control KP data. So if you ever called this IO control, you'd crash your system because you'd be writing crap into who knows where. But I got to thinking, it's uninitialized, which really 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. So, and the question is, one of the questions is, why does this even show up? Why didn't anyone notice it? And the problem is that we passed everything by pointer value, so the compiler just ignored it,
figured we knew what we were doing when we built it. So to control this variable, you find something else that builds the stack in a similar fashion. 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 overlapped. So there's this other function, getVideoTuner32, 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 the state that we had left it. So you had to take a look at the two different structures that are there. Our target here is the video code 32, we want data. We wanna be able to control data, so we have to figure out where it is in relation to the other structure in the union. And it was relatively straightforward
because in video tuner, there was this large name string. 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 the tuner IO control,
what's left on the stack is whatever we had put in that structure. And then we can go and call the microcode function and whatever was there will end up inside the data field. And there are no special tricks for data size and for the length and source that we're doing. 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 structure. Now the one problem that you run into is that 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 syscall wrappers like libc syscall, you can't actually use that because it's gonna go off and do other things with your stack. You have to actually call it directly in assembly. You can't aid in debugging by sticking a printf between the two because of course you're making yet another syscall in between. So you have to be very careful about that.
Additionally, the kernel may go off and do other work between the two on behalf of your process if it's a new code path. So the solution for that was just to call the IO control a whole bunch of times in a row first that it finished any work it had to do with page tables, got everything in line for you to then call the final one.
And another small challenge is these are all compat 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, which is just some more assembly, which I have here. Basically the int 80 will force a 32-bit syscall. So this is a quick C wrapper to shove the arguments
I need into a 32-bit syscall and return. And then the action is to beat on it with the one that will prime the stack. So call it a bunch of times first, 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? I used the sock struct exploit from Dan Rosenberg's code recently and you basically open up a socket and it shows up in ProcNet TCP.
In bold is the, first is the port that I'm listing on in hex, and 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 you want to overflow, or overwrite, rather. In modern versions of the kernel,
kpointer restrict now blocks ProcNet TCP, but you can still get the same information out of a net length thing that is still open. 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. This is based on Brad Spengler's enlightenment 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 entire function that the kernel needs to run to give you root as that process. And finally, you just, after you perform the overwrite, you just close the socket and it'll call that function for you, and everything's nice, the kernel cleans up for you.
And I can show you a small demo of this running. If I can see that. Hopefully everyone can see that. And it flipped back.
It's not gonna let me. How about that? Okay. So a lot of demos sort of aren't very interesting because they effectively just 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. So I decided I ought to have this demo with a useless Hollywood drama mode. 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 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. This is very exciting. Do the IO control. Did it work?
It did. It did work. And if you don't wanna wait for it, you just run it without the dash dash Hollywood option. I'll just run straight through.
And that's basically it. And I can go all the way through all my slides again and get to the end that says questions. And that's it.