 I'm Joel Ericsson from the Bitsek R&D team and these are my colleagues Karl Janmar, Klaus Neuber and Krister Oberg. This talk is about kernel vulnerabilities in general and kernel mode exploitation in particular. We'll begin with a short introduction to the topic followed by several real-world examples and demonstrations of kernel mode exploits that we have developed ourselves. So, why exploit kernel level vulnerabilities? Well, first of all, the real reason, find most things in life and perhaps especially here in Vegas, because it's fun. Also, there's not many people doing it yet, so still plenty of bugs to play with. Exploiting at the kernel level also means that we can bypass most defense mechanisms and any kinds of restrictions such as file permissions, ACLs, secure levels, etc. And since the target operating system itself, we don't rely on how the system is set up and configured. There are also a few reasons not to exploit kernel level vulnerabilities from the exploit developers point of view. Since any failed attempts will generally lead to system crash, the exploits need to be very reliable. Also, kernel debugging can be quite a pain to set up, especially for obscure or embedded operating systems. And of course, in general, we need at least some knowledge about kernel internals. These are some of the common targets for attack in a kernel. For local exploits, there are quite a few attack vectors such as all the system calls, IO control messages, and executable file format loaders to mention a few. For remote exploits, we are generally restricted to drivers for network protocols and protocol handlers. Sometimes it may also be interesting with attacks that require physical access. For example, when we want to do live forensics of a system that potentially uses disk encryption, or when we need to bypass a PIN or a password on an embedded device such as a phone or a PDA. In this case, we also want to look at drivers for hardware interfaces such as USB devices. As for the payload, we often want to do privilege escalation, which for Unix-based systems is usually as simple as altering a user ID field. In Windows, we may steal or duplicate an access token from a privileged process. If a useful end process is restricted somehow, we can use our kernel mode payload to bypass it. For instance, by breaking out of change route directory. The most powerful payload strategy, and especially useful for remote exploits, is to inject the backdoor directly into the kernel, and we will see examples of this later. Some of the things we often need to do in our payload is to make it reliable. It's automatically determining addresses and offsets. This can be done by simply parsing the L4PE headers to resolve the symbols in memory. It may also be done by pattern matching. For instance, by searching for certain instruction sequences. And as a large resort, we may simply hard-code the addresses and offsets for specific kernel releases. For local privilege escalation exploits, there are also some operating system and architecture-specific techniques that can come in handy. Here are some examples of how to determine the address to the process or thread strategy pointer on various systems. And as a golden rule for kernel exploits, we need to clean up NMS we create. If the bug we exploited was an overflow, which is often the case, we need to restore sane values for any important data that was overwritten. For stack-based overflows, we might get away with restoring a stack frame beyond the stack data that were overwritten. And for heap-based overflows, we may need to repair the heap. Now over to our first real-world example, the GDI bug. GDI stands for Graphics Device Interface, as it is used for handling all kinds of GUI objects such as Windows fonts, etc. The data for these objects are stored in the memory section, which is shared between user-mode processes and the kernel. This memory section is mapped read-only into GUI processes by default, but it turns out that the section can be remapped read-write. Crashing the system can be achieved by simply overwriting the entire table with trash, but that's not very interesting, so is there a way to exploit it? As for finding the bug, I didn't. The bug was made public in November last year during the month of kernel bugs project. Microsoft was actually notified it over two years ago, but obviously they didn't take it very seriously at the time, perhaps because they didn't think it could be reliably exploited. When the bug had been public for about a month, and neither an exploit nor a patch had been released, I decided to look into it myself, and after a couple of days I had a working exploit. It was finally patched in the middle of April this year, a couple of weeks after I demonstrated my exploit for it at Black Hat Europe. The first step in the analysis of this vulnerability was finding a reliable way to determine GDI section handle so we can remap it to gain write access to the section. My basic idea was to find it by pattern matching. If you know the size and contents of the GI section, we can easily determine when we found it. This is the first thing we need to know. The GDI section contains an array of struts with these fields, and each entry in the table is 16 bytes large. Combined with the fact that the maximum number of GDI objects in Windows 2000 is 4000 hex, and in Windows XP is 10,000 hex, we can determine the minimum size for a valid GDI section. We may also be interested in knowing how the handle to a GDI object is interpreted. The lower 16 bits of the handle is actually used as the index into the GDI section table, and the upper 16 bits of the handle is used as a sanit check and must match the n upper field for the n through with this index. This is quite useful for us to know when we brute force the handle to the GDI section. My final method is this. We create the GDI object, calculate the index where it's supposed to be at by taking the lower 16 bits of the handle to this object, and we calculate the value that the n upper field should have by taking the upper 16 bits of the handle. And for each memory section that we're able to map, we check the section size. We get the entry in the table where our GDI object should be, and we check the process ID and the n upper fields. And if you're as paranoid as I am, I also check the type field which will have different values depending on what type of GDI object is created. Being able to overwrite pointers are always interesting for us exploit developers, and in GDI section there are two for each GUI object. One is a user mode pointer used in the process which owns the GUI object in question. One is a kernel mode pointer used in kernel context. By manipulating these pointers, we hope to be able to eventually achieve a write an arbitrary memory address. If we decide to target the user mode pointer, we might be able to exploit it through a privileged process, but this would probably be very hard to do generically. And of course, exploiting it in kernel context is much more fun. So, I decided to attack the P kernel info pointer. Since the P kernel info pointer will point to a different type of struct depending on which type of GDI object is being used, I realized I had to try creating different types of objects. It seemed quite likely that somewhere along the line, a call to GDI related sys call would eventually turn up writing to something in this struct. After a lot of test cases and a lot of help from WinDBG and IDEPRO, I came up with this. When brush objects are destroyed with the NT GDI delete object app sys call, the pointer at index nine is written to with the fixed value two. But only if the value at index two is set and the value at index zero is set through the object's own handle. As it turns out, this technique was reliable enough to be used for exploiting all of the vulnerable systems. There are still a couple of problems to solve before we have a full exploit, though. First, we need to find a suitable address to our write, preferably a function pointer. The data that is written to this function pointer will be the fixed value two, which is quite enough for our purposes since we can place the payload on any address in the exploit process. Since we can dereference user data in the kernel. But how do we find a suitable function pointer? To be suitable for us, it must be possible to reliably determine its address. It must also be called in the context of our exploit process. And to avoid the crash, we need to use a function pointer very unlikely to be called by any other process while our exploit is executing. The obvious choice is a rarely used system call, which would be very easy to trigger a call to from within our exploit. There are actually two system call tables in Windows, one for the native NT API and one for the Win32 subsystem. My first choice was overwriting a syscall in the native API table, which was quite convenient because there were already documented methods to determine its address. And it worked great except for under XP Service Pack 1. So, why didn't it work? Well, it turns out that this syscall table is actually stored in a read-only memory section. But the read-only property of memory is not enforced in kernel context except for under XP Service Pack 1 for some reason. I wanted something more reliable. But when I looked at the other syscall table, I noticed that it's actually stored in the writeable data segment of the Win32 module, which is perfect for us. But since there is no documented method to determine its address, I had to come up with a method myself. I had two IDs based on pattern matching, and this one was not entirely reliable. The final method is to search the code for the call to the function that registers the Win32 syscall table and the address from the arguments that are being pushed to the stack. As for the payload, I want to elevate the privileges of my exploit process. And unlike in Unix-based systems, this can be quite complicated. What we do is actually to temporarily steal a so-called access token from a privileged process. And at first I had some reliability issues with this. I solved this by restoring the original access token for the exploit process after I'm done. And the final result is a reliable exploit for all of the vulnerable Windows XP and Windows 2000 systems. Now time for a demonstration. Well, to make it a little bit more interesting, I actually embedded the exploit for the GDI bug in another exploit for an Office XP bug, as we found. And here I have the attacker, here I have the attacker, which is listening to port 8080. And here I have the victim opening an Office document. And if you look here at the attacker, we have a shell. And it's running with system privileges. And we can also see that we were an unprivileged user from the beginning. I also made then a command line version of the exploit. So I can, for instance, change the administrator account password. And the administrator account here is called root. We're fine. And here it doesn't. Okay. Now over to my colleague, Krister. Hi. I'm going to talk about NetBSD bug I found. It's very similar to that NetBSD bug I found and presented on in Amsterdam. I found the bug using a fuzzing tool developed by my colleague here, Klaus. And what I did was I wrote a script to generate sockets using random combinations of the main types and protocols. And then I attempted to bind them using a random socket address. And this, of course, led to a kernel crash. Having already found a very similar bug, it was very easy for me to track it down. I used the ddb debugger. And if we have time for it, I'm going to demonstrate ddb for you. You can also use gdb, of course, analyzing kernel bugs. You can dump a crash file to the file system and debug it offline. Or you can set up a serial connection to machines and do live debugging. The bug is actually a straightforward buffer of vulnerability. What happens is that a call is made to be copied without using a supplied length argument. So what are mbus? It's basically a basic kernel memory unit used throughout the networking code in BSD. It stores things like socket buffers, unpack data, and the data can span several mbus in a linked list. So basically I've exploited mbus in two different ways on BSD. The first technique is an unlinked exploitation technique, basically unlinking an mbus from a wlink list. But the second technique is even better because it's very, very hacker-friendly. It's very easy to exploit. They have something called external storage, or they can contain external storage, and when they do, they can have a function pointer. Pointing to the function they want to be freed by. So if you control the function pointer, you can just point it to your payload and the payload is executed when the buffer is freed. Okay, I don't need to talk about this because we're a bit short on time. So this is the macro that performs the unlinking of an mbuff. What happens here is that if we can control these two pointers in this macro, we can achieve a memory overwrite. So for example, if the next pointer in our mbuff is pointing to the address that beef and previous references to bad coded, it basically comes down to that beef is written to the address of bad coded officer and that way around. So what targets do we have? Well, the obvious choice is obviously return address on the stack, but we don't necessarily know where the return address is. Besides, we need it to return to whoever called us in the first place. There are a lot of function pointers we can use. The problem with them is usually that we don't necessarily know what we're supposed to point to and we should always restore everything overwrite and currently exploit, so that's no good. There is a system call table containing basically it's an array of function pointers to the functions implementing the system calls. And the system calls, we can find the addresses of any given system call using IOCTL. So if we overwrite a function pointer in this table, we can restore it afterwards because we know the original values. What I do is I take a function pointer in this table, point it to my payload, execute the system call and that executes my payload. Right, okay, when you're using the first technique, the unlinked technique, the Mbuff is being put back into a memory pool and the problem with this is that we're actually freeing an arbitrary pointer and not an Mbuff, which means that the MB coding in the kernel is going to be slightly confused in crash unless we do something about it. And the code is a bit tricky and complicated and it changes from release to release, so the best way to do, to clean things up is to just call a function called mbinit, which will reinitialize the entire thing. Okay, moving on to the second technique when you're exploiting this function pointer, you're going down the same execution path as with the previous technique, but you don't want an unlinking to take place, so what you do is you take the next ref pointer and point it to your Mbuff and then take the X3 pointer, point it to your payload and that will execute the payload when M3 is called. Also when you're using this technique, no attempt is made to put the Mbuff back into a memory pool so you don't have to clean anything up. And since this is a local kernel exploit, it's very, very easy to write a payload for it. All I need to do is find my process and escalate my privileges to get a root shell. To do that, I need to find my process proc pointer. You can do it in several ways. I've written a white paper about it and you can read about it there, but essentially when you find your proc structure, you can find your credentials and just modify the user ID. Also since the kernel can reference user space memory, I don't have to actually copy my payload into the kernel because the kernel can read user space memory anyway. So this is my exploit. Okay, so I've got a root shell now. And we can see that it's actually a patched kernel so I'm not cheating, I'm not using an old one but it's a fully patched system. Actually I was just told that I have some time so I can show you that debugging demo. So this is a really good example why you should disable the kernel debugger if you're working with somebody like me. So user logged on to the console and has left the console and tried to log his console with log command. And I'm trying some passwords but I can't get it. So I use a keyboard combination on the console to break into the debugger. And now I'm running the ps command in the debugger just to find the process ID. So I killed the log command and continue execution. But I don't know if you can see it but I'm just a normal user here. So I'm going to write an exploit. So I've compiled my exploit which is just trying to do a setUserID root which is obviously going to fail unless I do some magic in the debugger. So I've executed it. I'm setting a break point at a function that is going to handle my request to change my user ID and I run it. And now the break point here. So I'm going to set another break point, continue. And now I'm just going to change the return value of this particular function. So I'm going to pretend that this function had a successful run. And I continue. And I've got a root shell. Oh, by the way, if somebody wants to see the overrace that I was going to do, just come up and talk to me afterwards. Hello. I'm going to talk about my payload for the OpenBSD IP version 6. Oops. This bug was found and researched by Alfred Rotega at CORE. So he is the guy that should have credits for finding this bug. He released a proof of concept code that only executed a break point until the actual exploit was ever released. This bug is triggered by sending specially crafted fragmented ICMP version 6 packets, which causes an Mbuff structure to be completely overwritten. Christo had already talked about taking control of the execution flow from there, so I won't take that again. ECX, EBX, and ESI all points to the start of the overwritten Mbuff. A jump ESI takes us to the beginning of that Mbuff. From there, we jump 200 bytes back to reach stage one. My payload has three stages. The first stage, which installs a backdoor and a wrapper for the ICMP6 input function. The reason for using this is that we use ICMP6 packets to trigger the vulnerability. So we know that we can reach a target system if the exploit succeeded. The second stage is the backdoor, the code that wraps ICMP6 input and inspects incoming ICMP6 packets for backdoor commands. I implemented four different backdoor commands, which we will talk more about later. The first thing done by stage one is to try to locate stage two. Stage two is sent as the payload in a previously sent ICMP echo request packet. What we need to do is to find the Mbuff chain for that packet and traverse it until the end and fetch the data pointer to get a pointer to our payload. When we trigger the vulnerability from within M3M, there is actually a pointer on the stack at 100 bytes from ESP to the previously sent packet. I do some checks as well in case another packet got... which is not contained in our payload, checking for Mbuff flags to make sure that the pointer on the stack is valid. Stage two contains a symbol resolver, so we use that one to resolve unit 6SV and check the value of the current ICMP6 input function. We checked if the backdoor is already installed. This is done by comparing the first four bytes in the current function since our backdoor starts with a call to get the address of the current location to be able to extract the data that are pre-pended to this code. So it's enough to compare the first four bytes, actually. We then resolve Maloch, allocate kernel memory for stage two and copy the code there. It's enough to simply overwrite the function pointer since we came from a network interrupt, so all the logs are in place. We then clean up the stack in return once the backdoor is installed. The symbol resolver part of stage two is really nice because we get rid of all the hard-coded addresses to all the symbols. We search for... The health header is not mapped at the fixed address and upper BSD, as, for example, free BSD. So we search for the health header from the BSS segment. And then search for hashers of symbol strings in the dunesum section pretty much like you do in any Windows shell code. The resolver code I used here was initially written by Krister for another project, so it was modified a bit to fit into this code. The backdoor, as I said, it listens for ICMP6 packets, which has magic bytes in the beginning of the payload, indicating that this is a backdoor command. Once such a packet is spotted, we simply copy the stage three, the command to memory that we allocate and then wrap assistant code with this memory block. And then call the real ICMP6 input function and return. Using syscalls from within the kernel makes it really easy to write kernel shell code, since it's highly portable. The trick is that the thing is that we need a process context to be able to use system calls. So we wrap a system call, wait for it to be called, and then we fork from that process to create a node process to play with. I took a look at the default installations and the good time of day was called quite frequently, so I picked that one, it works great. The stage three command needs to know which syscall we wrapped, so we simply prepend the index of that system call and the address to the real handler before stage three code found in the payload. I implemented four different commands, the traditional connect back, creating a TCP connection which spawns a shell, so we get a raw shell. We might need to change the secure level to be able to do fun stuff like loading kernel modules, so there is a command for setting the secure level to an arbitrary value. Depending on the system that we are attacking, it might be stuff like firewall rules preventing us to set up a connect back connection. So there is a command to run arbitrary shell commands, just like a system in the C library. The output of this command would obviously be sent to the standard output, an error of the process that we default from, so you better make sure to redirect it to the device now or something when you type the command. The last command is left over since I needed a way to uninstall the back door while developing testing and stuff like that. And you can use the traditional Unix commands to send and receive files. There is no command implemented for that. It's enough with the connect back connection. The state tree commands are all implemented in similar ways. They all use a state tree resolver to resolve symbols. The first thing done is to reset the wrap system call and then calls the real system call and saves the return value. After that, it forks from the calling process to create the process that we own. Since we wrap a system call, any process can call the bad system call with any privileges, so we have to make sure that we really got root. We do this by setting the real user ID to zero before continuing to execute. We will be attacking open VST 4.0, so we resolve the back address of the target system. Another back door is installed in kernel space and we create the connect back connection since there are no firewalls installed in the system. We check the current value of the secure level, which is two the highest possible, and we make a listing in the temp directory. We then exit the connect back shell and set the secure level to minus one. Lowest possible. And then, just to demonstrate the implementation of the arbitrary shell command, we wrap the root in the master password file. This is all done in kernel space. I don't modify any user land process or something like that. Everything is done within the kernel. And we can see that the secure level has changed. Output from the rep command is in the file in the temp directory. Since we are nice people, we uninstall the back door. Thank you. Time for Carl to talk about his FreeBSD stuff. What the fuck? My name is Carl Janmar. I'm going to present a kernel exploit for vulnerability in FreeBSD. This vulnerability is within the wireless subsystem of FreeBSD, so this is a remote kernel exploit. This vulnerability is within an IOCTL, and this IOCTL is used when the station scans for access points in the vicinity. And there is an integer overflow in this IOCTL, which makes it possible for an attacker to overwrite some stack memory. So there is a stack-based buffer overflow here, and I can't go into all the details here because we have pretty limited time here. I don't do the presentation I did at Black Hat. It was a full presentation of the development and on the finding of the vulnerability. Here I'm just going to show the demo and a little bit of an introduction here. So what can we do? This stack-based buffer overflow makes it possible for us to overwrite the saved return address, and thus makes it possible for us to take control of the execution in kernel space. And the IOCTL, which is vulnerable, is used by several applications, for example, VPA-supplicant, and this application is needed in FreeBSD to authenticate to access points providing better encryption than web, for example, VPA-PSK. So I think I just jump into the demonstration here. Okay. So to demonstrate this, I have an access point using VPA-PSK as authentication, and I have a target here running FreeBSD 6.0. It has an external wireless network card here. I have an attacker here running NetBSD, and I'm customized the NetBSD kernel, so it's possible... Can you raise the volume a little bit? Okay. Never mind. So I've customized the NetBSD kernel, so it's possible for me to write and send arbitrary frames. And so now I can construct my own beacon frames, and I can then mount this attack. So we're switching the screen here. And here we have the FreeBSD machine, and we are opening the web browser here, and we will open Firefox and generate some encrypted traffic to the access point. And just to have a little bit of a look of the traffic here, we have wire shark installed on the attacker, so we should be able to see the traffic here. Okay. It's a very difficult password. Okay. So now we have the wire... We have the web browser running, and we refresh this page a couple of times here, and we are going to generate some encrypted traffic here, because this is using TKIP as encryption here. So from the attacker, we can't really see the traffic, or it's supposed to be that way. And if we look at wire shark, here we have a filter which filters out all the traffic sent back and forth to this access point, and we want to locate some data traffic here, and here we are inspecting that frame. It's a little bit limited resolution here. Anyway, you see the TKIP here, and the payload itself is unreadable by us from here, from the attacker's point of view. So what we want to do now is to run this application instead, and this is the exploit, and we're going to search here for access points in a vicinity, and we do that by passively listening at all the beacon frames sent into the air. We see three networks here. Whoops. We chose the wrong one. We want the triple X one, by the way. So we search again, and now... Okay, I have to take it easy this time. Yeah. Now we got it. Okay, so now we are a little bit intrusive here because we are sending the authentication frames from the attacker, so we are de-authenticating all the clients associated to that network because the management frame, management traffic in 802.11 is unauthenticated and unencrypted, and then it makes it possible for us an attacker to do these kind of tricks. So now we have the MAC address of the access point and the client. Now we are mounting the attack, and we switch over to the target, and we will see here that it lost some connectivity here for a while. This is because we need to get the target into a searching state to trigger this IOCTL to be called. And it will be like this for a couple of seconds, 10 or something like that, 10, 20, and then it will have connectivity again. You just have to try again here. Okay, so now it's working again. But now we hopefully got our backdoor installed and we upload a backdoor, a file server, so we are able to browse the target file system here, and this is implemented in the kernel, so it never touched the disk or anything like that. And what we want to do now is to show some traffic here. So what I do now is I open the copyright file from the target machine here, and we switch over to the wire shark here, and we will filter out some special beacon probe responses and probe requests here. So now we are filtering this out, and if we look at the content here of this probe response, we see the file that we were opening here, and this probe response and with the probe request coming back from the target, it is the payload and the copyright file that we were looking at. And this is included in the optional probe request field. So we are communicating with them to the backdoor in the management layer, so we don't send any TCP or IP traffic in any ways. And now we want to do something more here on the target machine here, so we browse to the home directory of the only user at this machine. Okay, and we create a file here. Okay, let's see here. The keyboard is a little bit bad here, but I just want to shut it down here. Okay, we open up the file manager in Gnome here, and we create a folder, and we want to create a file with unknown content here. So we create an empty directory, and we fill it with something. Okay, and on the tacker side here, we refresh the directory. It pops up a new directory here, Secret, and we see the content of this newly created file here. So now we can see that we can browse the target file system. We can also upload files to the target file system. Okay, so there's a new file created here. Okay, and we have a new file here, and we switch over to the target, and we do a reload here. We just want to see the content here. So we can upload file as well, and that's nice, but what we want to do now is probably to just look at the passphrase used to authenticate to this network, so we don't need to install this backdoor again, because it is not very nice to do that. So what we do is to look at the configuration file for VPA's applicant, and now we have the passphrase for this network, so we don't need to install this again. So this is pretty much this. Any quick questions here? Or we move into the questions and answer room here. 108, I think it is. Any questions? Now directly, fast. Thank you.