 Hi folks, I think I'm gonna start just a couple of minutes early because I got a lot of slides for you today and Yeah, I'm gonna try and keep up one slide per minute, but um if If it's unclear, of course, you know tell shout-out just tell me to clear something up for you Okay, so my talk from no way to Odea weaponizing the unweaponizable I had to come up with a name that was gonna be kind of catchy and I think it actually turned out a little bit lame But that's all right. I'm Joshua wise So right, so here's so kind of here's what I plan to talk about today Quickly I'm gonna give you a quick little intro figure out who I am who you all are We're gonna talk about briefly we're gonna talk about vulnerabilities kind of in the general case I'm gonna go across and an old style vulnerability that everybody here knows about everybody learned about in CS 101 And we're just kind of dissect it using these three points that I'm going to use kind of for for the big one I'm gonna give and then I'm gonna give a case study of taking a very difficult vulnerability Or at least something that I think is a very difficult vulnerability and I'm going to use this I'm gonna use these three points that I've developed to make something very difficult into something very doable to exploit and Briefly I'm gonna talk about kind of what went wrong, you know things things that could have been done differently that That would have made this not you know that could have mitigated this how did this happen? And I'm gonna have a demo for you and with any luck I'm gonna have time for a Q&A session. Otherwise, we're gonna go to the Q&A room down the hall So without further ado, let's begin Okay, who am I I'm just some guy, you know I'm I kind of call myself an all-purpose embedded hacker, you know, I do I've done HP I pack stuff back in the day At some point I got roped into to doing Android stuff. I'm one of the Unrevoked guys if you have a rooted evo or rooted incredible you're probably running my code And right so yeah, there you go and revoked At some point I kind of got roped into it and that's in a sense That's where this presentation started off. I like to classify myself nowadays as a recovering software guy I used to do software guy now and kind of trending towards ASIC design And of course, I'm buzzword compliant I am working on my integrated masters and bachelors in electrical and computer and engineering at Carnegie Mellon University Although that doesn't really matter Okay, so now that you know a little bit about who I am. Oh, by the way, I have a website, too It's my first name last name concatenated calm. I think it's probably linked somewhere, too Although I didn't link in this presentation a little bit about you now So that's a little about me. Who are you? So hopefully hopefully people here have a little bit of experience writing or running code in in kernel space Maybe somebody maybe some of you guys have experience in particular with a Linux kernel and working kind of inside that infrastructure all of you guys here are interested in security And in particular, you know exploiting exploiting Linux kernel is is what we're going to be doing today Nobody here I hope is a script kitty No code for you to compile here. I'm not going to be I guess I could potentially be convinced to release at the binary that doesn't actually give you root but But I'm not releasing code today But however in the in this presentation, there really should be enough if you really wanted to reproduce this on your own To to be able to do that. So so that's kind of hopefully who you are And of course, you know all this all this is going to be all C based So hopefully you have a good understanding what's going on inside the machine even if you haven't worked inside of kernel space before so Here's a vulnerability I'm going to be talking about today So we were looking through we were looking through very early on we were looking for ways to root the HTC incredible because nobody had really come across that nobody had really solved that problem yet and We came across this exploit CV or CVE 2010 1084 so This is this is what they called a kernel denial of service attack, you know, you could crash the kernel and They wrote it as bad memory access with CIS FS files Allows attackers to cause a denial of service memory corruption. Okay, so it's a DOS attack, right? We're going to bring down the kernel and So what right? All of my stuff is transactional all of my stuff is going to be safe. We're running journaling file systems the machine crashes. So what and so this this first showed up in 2 6 18 and It got fixed in 2 6 23 That's a lot of kernels, you know, that's a lot of vulnerable kernels If to give you an idea of who's running things that aren't 2 6 23 if you're running an Android phone that hasn't been upgraded to Froyo yet Then you're running 2 6 29 and it hasn't been patched yet This every single Android phone that I know of that's not running Froyo is vulnerable to this So who here hasn't patched up to 2 6 20 or 2 6 33? You're brave. You're brave for admitting it So Let's talk let's talk quickly about what's going on inside this vulnerability How this vulnerability works and we're going to go into a whole lot more detail about it later But I'm going to kind of go for the brief overview from 10,000 feet of what's going on inside this that causes the machine to roll over and die and You know how we can how we can cause a crash even if we don't know how to exploit it yet So this this one's this one's really really a standard one, okay? This lives inside the Bluetooth layer inside this socket the socket control layer Called L2 cap L2 cap is a subsystem of Bluetooth And it and you can and the user and user can open sockets can open L2 cap sockets Just using the socket syscall the same way you'd open any other sock same way you'd open a TCP socket But what makes this interesting is they decided they were going to export Debug data about all active L2 cap sockets not through the interfaces that you'd get you know with net stat by looking through FDs things like that right, but they decided hey This is the new Linux kernel. This is Linux 2.6 and we can provide debug info through sysfs This is the new Linux kernel, and it's not really sensitive information really So everybody gets to read this debug info out of sysfs, you know if you're running a machine with Bluetooth then What do you really care about who's connected about which connections are active, right? You're not really leaking sensitive data. It's it's a machine with Bluetooth You know you can walk around and see who else is in the room, so what do they do? They take this buffer, okay? they they take this buffer and For each for each Bluetooth socket that that the user has created for each L2 cap socket Actually, this exists pervasively throughout the Bluetooth stack, and it was correct And the one that we're gonna be looking at today is the L2 cap one And they just say okay I'm just going to keep a pending onto this buffer that sysfs is allocated for us for each Socket BAM, we're just going to sprint F right on to the end of it and Well, they didn't really bother to check for the end of it So so how does this buffer kind of show up? How does this buffer live? Well, it gets So this isn't really a simple stack buffer overflow because it gets the buffer from the frame allocator, okay, and and We'll talk a little bit more about what that means in a moment It's it's kind of a little bit of a twist because we don't really control the contents of What's going what's going through right? We only we kind of get a fixed ASCII string that's sprint F on over there Right, we really don't get a chance to control that and we don't really control how much we print either Because we don't really know how far into the string our target is going to land so Let's let's take a step back here, and I'm going to we're going to Analyze an old vulnerability Everybody knows about this one. Everybody's favorite gets And we're going to think about it in terms of these three things that I mentioned. Let me go back here real quick Target contents length remember that we're gonna be focusing a lot on that today target contents length So here's here's the old vulnerability, okay? we Have this program that was written for CS 101 and there's a and it's set you would root because the professor is an idiot and Told the student that in order to access the terminal you have to be set you would root I don't know but it happens, you know So we have our fixed length buffer, and we're gonna ask what the user's name is and we're going to get Son in there, and we're gonna print their name back and we're just gonna say hello This is this is a really easy to exploit Vulnerability why is it so easy to export or exploit because it's got a controlled target? We know exactly where it's going to go. It's going to go on to the stack every single time Relative to the same things every single time controlled target It's very easy because it's a controlled length We only have as many characters copied as I bang in on the keyboard or into standard in or whatever it wants to be Right the length is exactly what I want it to be every single time and not only that But the the contents are controlled I get to decide exactly what it's going to be every single time So let's let's go take a little look here, and we're going to I'm gonna give you a little memory diagram What's going on, and I think this is kind of a useful visualization just as a refresher? I'm sure I'm sure everybody here knows about how How a stack smash works, but I think it's gonna be a very useful visualization So let's let's talk a little bit through this here We have the user input something bad through gets and where does it go? Where in memory is this gonna go? Let's take a look at this I've drawn a nice little picture for you By the way by the way these addresses no they're not really for any machine in particular I just kind of made these up all right don't don't base any kind of exploit on this or Do and it won't work So where's it going to go we have we have the buffer here and by the way lower addresses are towards the bottom of the screen And we have so we have gets a stack frame and gets is going to go stick things into buff and things go up all right and So so here we go So we have we have the user that input something bad in here very very long string full of the letter a and it gets Written normally it would get written into buff and this time it kind of gets written through the greeter stack frame And then gets written through greeter's return address greeter's return address gets set gets reset to inside buff into that code that we've injected and owned right Return return address now contains the address of code and buff buff now contains code. Why did this work so well? All right, why this works so well? three controls Attack or control target every single time return address gets blasted Right return address every single time return address is always on top of buff Attack or controlled length We always type in as many characters as many characters as we want Get blasted right up through there We don't ever have to worry about blasting off the top of the stack if we blast over CZero zero zero zero zero zero Right Then we're done then we seg fall we're out of we're out of mapped frames. We're out of map pages. We're done so So we don't ever have to worry about that and we have we have attacker controlled contents We can write anything we want using gets except for the null character and except for a new line Okay, we want to overflow that buffer as long as our exploit code doesn't contain zero And as long as our exploit code doesn't contain a new line. We're good All right Everybody ready every day that makes sense to everyone. Okay, let's talk about let's talk about the need of this presentation So here's here's what's gonna go on in today's exploit all right in the exploit that I'm gonna be talking about today If you're following along at home This is gonna be in the L2 cap module the function name is L2 cap sysfs show And I think this bears a little bit of explaining the the sysfs stuff whenever you open a sysfs file It goes and allocates this buffer right Stir equals get zeroed page gfp kernel every time you open sysfs or a sysfs file It gets this buffer. All right, it doesn't necessarily run the print Immediately, okay, it doesn't it doesn't call this show function immediately But as soon as you do the read is when you do the read for the first time it calls this show function L2 caps sysfs show and And let me show you a little bit of what's inside here for each L2 cap list right for each socket and we're gonna call it sock string plus equals sprint f string and Then a bunch of crap What year is it guys who does that still? Okay This is a problem. This is a bit of a problem for us We can see how this is gonna crash the machine, right? This is always gonna run off the end of that string if we have too much stuff in there We said get zeroed page. That's gonna be one page long. We there is the overflow right there, okay? But You know, how do we control the target? How do we control? But we don't know what's gonna be in the frame in the page after that and that says get zeroed page I'm gonna be talking a lot about pages and frames, okay? I'll talk about that in a moment. But how did how is the buff? How is the buffer allocated? How is that string allocated the sysfs string comes from the frame allocator? That's that get zeroed page function And what comes after that? Well some other some other poor bastards frame that you know Just kind of got unlucky and happens to be hanging out after the frame that we're gonna smash So I'm briefly a little refresher on virtual memory for you guys So what's a frame? Don't confuse it with a stack frame. I think we're pretty much done talking about stack frames for today Okay, a frame is a physical memory backing of a page Okay, a page is a chunk of virtual memory Pages do not necessarily have to have frames associated with them at all times, okay? And so so I've given you a little drawing here So we have two processes running on our on our little virtual system here one of them had and both of them by the way Have stack data and text okay? These are and they each have one page for each each virtual memory address space You know virtual memory address spaces composed of pages physical memory composed of frames So the so here's what memory looks like to process a Text is there and it's backed by a physical memory frame All right data is backed by physical memory frame stack is backed by a physical memory frame Process B is the same process. Okay. It's just the same program, which means that it can share the same text frame Okay, so the page both of those pages map to the same frame and it's read only so it's okay Um Process B hasn't been run in a while and data has gotten swapped out to disk. Sorry process B It's stack is still in memory and So so what's important about this what's important about this is that the Linux kernel has both Physical frames they had it has a whole bunch of physical memory mapped into the address space and Has whoever used to be running whoever whatever user land process used to be running It has their It has their user address space Also mapped in and this is this is to make context switches faster blah blah blah take take an OS course, right? but the the upshot of this anyway is that you need user memory to be accessible if you want to do things like read write I Octel and you need you need kernel memory accessible if you want to do frame allocations You know to get a DMA buffer for the hard drive for instance Okay, so so that's right. So that was controlled target now now we know how the How the buffer allocation works a little bit? Let's talk about let's talk about the next issue of our three controls issue the issues obvious crashes inevitable Control number two is the length okay So we know that writes take place Through that sprint F to a strange place and we can't we can't stop it We don't determine how long it goes because that sprint F is just a fixed length format string And even if the thing that we want to smash is in the middle it'll just kind of keep going off the end So we'd hope we can't stop it before it overwrites something else important later on, okay? and Here's our third control Controlled contents, okay, what are the contents of the buffer in so remember remember in our elementary exploit? The contents were the letter a a whole bunch of times some shellcode and then a return address But we don't control that okay no data comes directly from me in this exploit No data all of this data is formatted through sprint F. So What's what's going on here? We're zero for three. How are we going to exploit this? Well, okay? It's time to start controlling our environment The environment is not you know the environment isn't set up for us to control. It's time for us to start taking control and So let's go for it How are we going to control the target? Well, let's go for an old-fashioned heap spray The what's the idea behind heap spray the idea behind heap spray is that we're going to We're going to scatter a whole bunch of things around memory and we're going to just hope and pray that the things that we want to the thing that we want to smash shows up after the buffer and The way that's going to work is we're just going to litter memory with the with things that we could potentially smash So What are we going to spray across the heap by the way target practice you more have all heavy industries with you more? Have all your target is our target So the first idea for things that we could smash a kernel stack We know how to smash stacks. We've done that before it worked. You know it worked really well in that little easy gets exploit We know how to smash kernel stacks. We just overwrite a return pointer and let's go so Let's keep an eye on that here. So let's take let's assume for a little while the best-case scenario, okay? The kernel stack all right The kernel stack is going to be in the frame after the sysfs page the heap spray worked so it goes there all right and The other best-case scenarios that we know What process ID that kernel stack belongs to okay? So we know who to yield to to make this execute Given that given those given those two kind of best case what happens right what does a kernel stack even look like? I got a picture for you Like so like other stacks like every other stack in the world a kernel stack has stacked frames Don't confuse these with physical frames kernel stacks live in physical frames, but they have stacked frames Like other stacks the kernel stack has stacked frames all right So what are we looking at here? We have we have some guys stack there right? This is this is There's a threat control block the stack grows down so we go down from the top of the stack frame Okay, there's more stack frames register save space and then a return address return address I like return addresses. I can trample on return addresses Okay, there's a bit of a problem here There's a bit of a problem Um Kernel stacks have another thing in them called the thread control block a thread control block kind of describes a Thread control block describes what state the thread is in and threads I guess in Linux we call them processes, but a thread control block describes what state the thread is in whether it's runnable right now Who its children are who its parent is what a dress space it lives in a kernel stack has a thread control block attached to it Every thread has one kernel stack and one TCB. By the way, these addresses are bogus So Let's take a look Okay, let's take a look at what happens when when we write when we're going to smash the string buffer um So we have our sprint f does it kind of a simplified sprint f and it's it's got all of our text and it's going to go from the string up um So in order to get to that return address We've got to hit the thread control block Okay, whenever we whenever we write the thread control block is clobbered So by the way, this isn't the end of the world Okay, this isn't the end of the world if we clobber the thread control block And here's why not If if we have control of the data Okay, then we can write something that would have been a valid thread control block Into that spot and it might not have been valid enough to keep the system running for hours and hours longer But it would be valid for long enough, you know for us to switch to that thread and Hit his return address and take control of the system and then drop a root kit and reboot the machine or whatever, right? Well, we don't have control of the data this time. We just get ASCII characters and not even ASCII characters that we control and Best I can tell a thread control block Well, you just can't do one of those with with those specific ASCII characters So so this is dead in the water, all right? This case stack idea not going to happen Well, what else are we going to do? There are other things that go in physical frames one of the but the uh, the big important thing I think that goes in physical frames Is controlled by the slab allocator, all right the slab allocator is a central memory allocation structure in the kernel and They switched to that actually probably late 2.4 And the idea behind this slab allocator is in a kernel you create a lot of objects that are about the same, okay? You create a lot of objects that are about the same sort of thing And so what we're going to do is to reduce fragmentation of having a whole bunch of differently sized objects We're going to localize Every object that's similar in memory, okay every object that's every object of the same type We're just going to pack into a frame and now we have frames full of these objects Right, so these caches are frame size sometimes they can be two frames long, but there you go, right? And this and so not only is this better in terms of memory fragmentation But it's also better in terms of performance because of the algorithm that they use So this was originally designed by the sun microsystems guys. I think I think it was probably jeff bondwick jeff bondwick does everything who Described this in a paper and they use it in the solaris kernel and they have some paper showing like a ridiculous speed up under load in the kernel So let me let me show you a little bit about inside the slab allocator here. What's inside of a slab? Okay, so by the way, each of these lines is a frame boundary I don't know if you can read that text there, but each of those lines is the boundary of One physical memory frame and the way these slabs work is that they have a fixed number of slots in them in this case We these are huge objects one kilobyte large But you fit any of them into into a frame, okay? And so from somewhere outside in the world There is a pointer to the first free slot in each slab that has free that has free slots So when you want to do an allocation you go, okay, I'm going to follow this first free slab pointer Okay to find a slot that I can a slot that I can allocate And so now where do we now sooner or later? We're going to have to update that pointer So each free slot has a pointer to the next free slot available and since they're all the same It doesn't we don't have to do any kind of best fit allocation First fit no, they're all the same So we just take the absolute next slot available or if there's nothing left right the pointer goes to null There's nothing left available in this slab then Then we just take this slab out of the list of slabs that that we can allocate from And the idea is that we want to fill slabs and we want to keep up and we want to empty slabs also We want either full slabs or empty slabs so that we can release a frame back to the system so Where's the list of slabs available slab metadata is stored In a slab. It's a whole bunch of stuff of the same type. Well, where's the metadata for that sort and stored elsewhere in memory? blah blah blah but okay, so What's important about this slab thing to us? Why am I spending so much time talking about it? What's important about it to us? Well, there's no header on the front of a slab the the first thing in the frame In a slab is the object. All right Very first thing we can see it right here and my drawing is perfectly accurate because drawings are always accurate Is an in-use object? Okay This is convenient for us This is really convenient We can just kind of drop that string there that that would be a good place to drop that string. I think All right, who uses slabs? Well, I'm not sure if you can read that text from all the way in the back. So I'll read it for you But every every kernel subsystem uses slabs. All right Every kernel subsystem uses slabs the So I've done I've done a little grep inside of the linux kernel For every time we call this the main slab entry point Kmem cache alloc kmem cache alloc and they call it cache alloc because they're allocating caches and They're allocating objects from a cache So how many how many times does that show up? Well, there are 305 times in the linux kernel that we call kmem cache alloc You know, that's not that they're all unique, but so how many different types of slabs are there available? well The developers very nicely gave us some debug info that we can use okay In and you can try this at home if you want on your own linux machine You can cat slash proc slash lab info. Actually, it's there's some very interesting data in there and there are As it turns out on my machine sitting back in my dorm room at school There are 183 different types of slabs Both any luck One of those is going to be an easy target, right? I'm going to pick completely randomly something that just so happens to work and Let's hit file descriptors. It's very easy to create. Why did I choose this by the way? It's very very easy to create file descriptors and each and you know from a user space perspective a file descriptor has a number, right? um fd number That's what you get back from the open syscall but those numbers have to map to something in the kernel and They get a whole structure associated with them. Those are called struct file And unsurprisingly, there are a lot of them in the kernel. So it's really a good match For um for a slab allocator. So we store these struct files in slabs What's a struct file look like Well, I'm going to give you the first couple of fields there that are interesting to us There is a union that's this linked list which the kernel guys decided to call f u And really it's two pointers for all we care. There's a um, there's this path structure That's saying this is the path on disk that we opened it and morally that's also kind of two pointers There's this there's this other pointer here called f op Anybody know about this? This is the this is the so every time you open a file Files can have files or many different things on a unix machine Such as such as pipes Such as special devices and each special device has its own list of file operations that can be performed because not everything is the same We're not running a plan 9 machine So this is a pointer To the file operation structure for this specific file for this specific fd that we have open Um, and what's by the way, what's the file operation structure look like? Well, it's just an owner And the list of function pointers, okay um So following file it following f op Okay Is um f count the number of times it's open f flags some generic bs about the uh file descriptor And f mode the mode which that it was opened with and then there's like a whole bunch more crap after that too, but So, uh, let's take a best case scenario here. Why by the way, why is this the best case? This is the best case because it's at the beginning of a frame boundary, okay It's right there ready for us, okay um This is why this is the best case for us. It's at the start of a slab. There is no slab metadata there And you know just kind of for reference here um Each block in here is one pointer size just just so you know, right? Um to give you an idea of scale. By the way, nothing else in this presentation is to scale um So what's the really really best case? Well the really really best case is that our string just so happened to line up Before before our struct file, okay It's at the start of a slab And it came from the same uh and get zeroed page comes from the same kernel pool That the slab allocator that uh grabs from the slab allocator uses get zeroed page or something very much like it Um, and the sys of s buffery allocator uses get zeroed page Uh, by the way, I'm going to talk a little bit more about that frame allocation mechanism In a moment um Okay, so what's a struct file look like? um This is what it is right But and I and I've darkened this time the parts that the kernel can survive for a little while With being smashed, okay? It's not you know the kernel Isn't going to survive forever if you do a lot of operations on this file It's going to be bad if you exit the program. It's going to be bad if you don't clean it up later It's going to be bad the kernel is probably going to crash But um, there's only one pointer in here. There's only one Member of this struct that that really matters, you know That's fop great news. That's really good news, okay? um That means that um, that means that we can pave over this struct file if we want, okay? We can pave over the beginning of it We can pave over the end of it as long as we get something that we're okay with in that file operation structure Okay, as long as we get something that we're okay with in that file operation structure The rest of the struct file can be smashed For a little while Okay, we're one for three Let's let's kind of get back to to why we're doing this here. What are the three controls that we're going for we're going for We're going for length We're going for contents attacker controlled contents We're going for an attacker controlled target The length is not an issue anymore, all right We still don't have control over the length, but we found some place that it doesn't matter We can go over by a little bit not, you know We can't go over into many many struct files But if we if we kind of open the number of sockets very very carefully We can go over by a little ways without causing the system to blow up and die immediately so, um So what's next we have length Let's try and control the content all right So so here's here's the x or here's the code that we're going to try and exploit again for your reference Your string plus equals sprint f stir and then a bunch of format string for those of you in the back It's So we can't write arbitrary content with this right ba to stir always produces a MAC address for us Percent d always produces a decimal Percent x always produces a hexadecimal all of this is is controlled by them not controlled by us The good news is that we can we can open sockets with the properties that we want right So it's very easy to predict the content So if we open a bunch of sockets directed to nobody bound to no socket With no data pending blah blah blah blah blah then if we cat this file We're going to get a lot of stuff that looks a lot like that. Okay No MAC address no MAC address two zero hex blah blah blah repeated a bunch How many times that repeated that's repeated as many times as we want Okay What does this mean? What does this mean? Data all right So data so data that what this means that data that looks like that Is going to end up in the file structure if we if we go down this path Data that looks like that is going to end up in the file structure no matter what else happens That's gonna happen. So we better make the most of it and What does that mean for fop? Well, it means that a substring of that four characters of those if you're on a 32 bit machine Four characters of that is going to end up in fop no matter what happens. All right So, um Well, what can go in fop? Anyway, what what does it make sense to put in fop? And can we can we have this? Go in fop the stuff One of those substrings. Okay. One of those substrings. Can we put that in fop safely? The only thing that matters From right now Is to make sure that something that makes sense Shows up in fop Something it's the only thing we care about in struct file without something that makes sense showing up in fop the gig is blown All right, we're done without it. So we better we better make it good. How we can do this? well fop is just kind of a pointer into the kernels address space, okay fop is a pointer into the kernels address space It's a dereference by the kernel and since the kernel thinks that it controls it usually It doesn't do any checking on it. That's okay. That's all right because the kernel is supposed to be controlling this What's interesting about that the kernels address space is a strict superset of the user's address space on x86 um On x86. It is a strict subset of the user's address space Um And so that means that it would be okay If fop was a pointer into user memory. It would be okay It doesn't have to be a pointer into kernel memory So let's come up with a little bit of a game plan here To uh to get this pointing to something reasonable in user memory um We're going to we're going to take this string that we uh that we saw a moment ago that string and we're going to map All of the substrings of it to become something something valid of an fop target, okay so for each of these um So the first substring is zero zero colon zero and in ascii that's going to be hex blah blah blah blah We trim off the end and make sure that that address points to a valid fop target Okay, zero colon zero zero right and we're just going to keep walking through the string for every for every member there Bam bam bam bam bam we're just going to keep we're just going to keep throwing it along there um And uh, we're done right? we have um We have this string Sitting here. We now have data written there And we've mapped that there. This is mapped in user space. We're using mmap You know we control that we have I don't know if you can read that from way out back there But uh the pointers inside there so owners null that's okay for a for an fop structure And uh, let's think about some of those other pointers some of those function pointers Maybe ll seek should go to attacker ring zero. Maybe read should go to attacker ring zero We're done, right? Well not so fast In reality it probably looks a little more like that. Um Maybe there's going to be another frame in the way there and now instead of having fop point to this structure We have just some random bogus crap pointing to the structure fop has not been touched We haven't won yet. Okay three controls length content target Contents aren't controlled, but we've predicted them. We've got length and we've got contents handled um Let's hit up the target Let's be buddies um So how are we going to control the relative placement of these frames? We know that we know that we're gonna we the whole idea behind this is the heap spray remember We're talking we talked about that before but we can't allocate that many fds You know we can allocate 16,000 fds But that isn't going to get close to the 128 mega ram In the vm that i'm going to be using today to demo this for you And it's not even getting anywhere near the 4 gig of ram that that a small server nowadays has um So um Heaps praise are hard now. So let's let's um Let's talk a little bit about how how memory gets allocated. I promised you earlier that I was going to talk about this um and um It's this it's physical frames are allocated using this concept called the buddy allocator. Okay Um, the buddy allocator it's called that because it it pairs up frames Um, and it pairs up groups of frames and it calls them buddies and merges them um And this is this is a really really old algorithm. This is from 1963 um According to newt who is the one who wrote about it markowitz was the guy who uh who wrote it down And I think it was actually invented late fifties um So this is a really old algorithm, but it turns out that if we if we use things like slab, okay This goes a lot. This goes really well with slab um Because we're not having all of that fragmentation in memory of different sizes so The implementation of this lives in linux mm page alloc.c um, this is 4 000 lines of really really really well tuned code tuned to the weird cache infrastructures of alpha x86 arm itanic Run in god damn fear You don't want to read it Get a copy of understanding the linux kernel. It's got a good description of it. Um, that book that book is that book is my god now um But but what's important about the buddy allocator anyway, um So with it with an run of the mill frame allocator that's just grabbing frames. There's no real ordering to those frames, okay If it's just grabbing a whole bunch of frames. There's no real ordering to it It so this is going to this is going to inject determinism predictability Into frame allocation that otherwise we'd just be picking frames at random We'd really have no way to determine What frames are going to be next? And the reason why it does this is if we it can allocate groups of frames of different sizes And when it's able it'll try and put a bunch of frames, you know one-off frames together so that it leaves as much memory You know wide open for big groups as possible um, the implementation details Totally beyond the scope of this talk Um, I guess if I hadn't talked about slab earlier I could talk about it But I really think slab is cooler. So You guys can go look up the buddy allocator on your own All right, what are we going to do? What are we going to do? How are we going to make this work? um We're going to try and we're going to try and use this localizing technique here um and In in in brief we're going to go fill up memory And that means that everything that would have caused a discontinuity. It's going to get paged out going to get paged to disk um Every other program on the system page to disk. What are we going to do to generate contiguous chunks? While we're going to free stuff We're going to do this little alloc free alloc dance to uh to get continued contiguous chunks of memory um, and what are we going to do to allocate chunks of memory for our struck files while we're going to free a little bit in there Um, and that's going to happen We're going to allocate our buffer page. Okay allocate our buffer frame. I guess I should say Um, and how are we going to do this? Remember this happens when sysfs opens the file Okay On and the right hasn't happened yet. You can do the open you can do the allocation without causing the smash to happen This is critical All right, we're going to pick up more some memory for struck files here ready aim fire What do we do it starts memory starts off kind of looking like this. It's fragmented. There's there's other people's memory all around. Okay um Luckily we can allocate about as much memory as we want and that's exactly what we're going to do um, all of the systems memory Minus the stuff that the kernel needs goes to us now You know, there's a lightly used machine that nobody's really paying attention to if you root get it So it's not really it's not really using um There's not a whole lot of other stuff using memory So everything gets paged out and we're going to do a uh, we're going to do our little free and allocate dance To make that all contiguous. You couldn't really see a change there But now the frame allocator has those all kind of lined up such that if we free for in a row Then we get four physical free frames in a row So what do we can do next we're going to set up our files our buffer in our files and uh own We're three for three Remember three controls attacker controlled length attacker controlled contents attacker controlled target We made these controlled by us by deterministically permuting memory And what happened we own the machine What went wrong? what went wrong I'm going to leave this up here for you I'll let you read it There's a comment here right after right after we do the read dance Right after the read happens This code works fine with page size return, but it's likely to indicate truncated result or overflow So what do we do? What does the kernel do when there's an overflow? Try to struggle along guys guys demo time Um, I have a vm here I uh can't actually see it So we're gonna have to hope how do I get out of a keynote here? There we go Um here, so I've got gdb attached to my vm here I'm kind of doing this blind because I can't see the screen very well And here's what I'm going to do. I'm going to where's my mouse Um, so here's my vm. It's alive here um And I'm going to um stop the vm and I'm going to break Target ring zero can everybody see that is Okay, well the people in front will be able to see it and they'll narrate otherwise sorry Uh, oh, I can do a little zoom thing. Does that work? Oh look at that Damn it All right, sorry um I'm a little pressed for time. So I'm not going to spend much time playing with that there But all right, so here I am and now the vm is running again. It says continuing there. So um Now I'm going to run my exploit can I type yes And uh, let's go watch that um Can I get these both at the same time? All right, now we've now we've got my screen here and we're stopped in the debugger We're stopped in gdb here and I'm going to do a little back trace for you. What are we looking at in this back trace? um If I had any clue where my pointer was I would um Yeah No I would I would be showing you I would be zooming in for you, but um, oh yeah, there we go Look at that. That looks like a kernel stack. Doesn't it? Uh, how do we know that's a kernel stack that address there? is uh It got called from c10 e something or other. I can't really read it Um, and that's that's that's kernel memory. Okay, let's let's print something else file arrow f op Did that work? What's that file operations? That's in user memory. Okay That address that address is an ascii string. We have now injected stuff into the kernel. Okay And uh, let's uh finish it off here Continue Yeah, well once we get, huh? I've no idea. Oh That's it. What's the conclusion? The conclusion is things that are hard to exploit Can be made easier By thinking about controlling your environment If we think carefully about control, that's what all if this is about controlling execution If we think about it in terms of attacker controlled length attacker controlled contents attacker controlled target these three things Just because it's not easy that doesn't mean that it's impossible. Okay Kind of in this in in this whole thing here We've conjured the world to be the way we want it to be This isn't trivial to do Okay, it requires kind of an intimate understanding of the kernel, but this isn't something that's impossible to do If we if we kind of sit down with a book understanding the Linux kernel if we take a problem focused approach and solve Then we can do it there's another little conclusion here And I guess this kind of brings us back full circle here Dear phone vendors We will win We have physical access Root on these phones will be ours Please Stop your crusade from keeping me That's keeping me from using my own phone Thank you Any questions I allocate he want or you'd like to know how I allocate a lot of pages in the linux kernel again How do I allocate how do I allocate 40 pages is that's the question? Um, so what I what I simply do is I just go through and I mmap over and over and over again I mmap 40 anonymous pages in and I cause them to be backed by the way by doing a right to them You have to you have to write to them in order for them to be backed um But I I allocate I allocate all of these with mmap and then so now I have Memory that's all mine right, but it's not necessarily contiguous So what I do now is I uh deallocate it and reallocate it And this time the kernel will choose each of the frames sequentially Okay, because it's pulling from a contiguous pool. It will choose each of these frames sequentially And then I can grab um That I can deallocate four and I'll hopefully get four sequentially in the middle. Does that make sense? Does that clear it up? I think my time is up, um, and I think Anything else further kind of goes into the q&a room for track five. Thank you very much