34c3 preroll music Herald Angel: And now I want to introduce our first speaker and the topic he's talking about. iOS kernel exploitation archaeology. A kernel exploit from late 2013 early 2014 will be digged out and analyzed proper archaeology all the digging... digging and analysis is done by argp here to my left on the stage and give him a big round of applause. And the stage is yours, thanks. Applause argp: Thanks for the introduction. First of all, thank you all for being here. As the person that did the introduction told you this is going to be an archeology talk so I apologize in advance if it's not that interesting for you. So we'll talk about a bit older stuff rather than new things. Okay so a bit a few things about myself. Actually, I think from all these things, the most important are the the Phrack papers, right? So, yeah. Let's ignore all the other stuff okay? So, what I'm going to talk about. I'm going to talk about the evasi0n7 kernel exploit. Now evasi0n7 was a jailbreak it was released by the evad3rs on the 22nd of December 2013. It supported iOS7 to iOS7.1 beta 3. That's not the 7.1 stable release, right? So that's a beta. And this supported all devices at that time including the iPhone 5s which was the first 64-bit device except the Apple TV. So, I decided to reverse engineer the kernel exploit of the jailbreak focused just on that. Because I was really interested, not so much in the bug itself, which was as we will see not very complicated. But I was really interested to understand the exploitation techniques that the evad3rs used. So, I started reversing it, and I understanding it, and at some point I just said I'm just gonna do a reimplementation of the kernel exploit. So, this talk is basically my notes on this whole process. And, of course, it's not a jailbreak walkthrough, right? And I'm going to specifically focus on the various problems I encountered during this task and how I overcame them. And hopefully it's going to give you some helpful takeways for if you do iOS kernel research nowadays. Okay, so, the general outline is I'm going to say a few things about the version 7 to setup the stage. And then I'm going to explain the kernel bug itself. And, then I'm going to talk in length about my debugging setup. And, I think that's a very important step that usually phone or embedded talks exploitation talks don't analyze that much, and I think it's a really important part. Because usually having a working the debugging set up is, basically, maybe half the job of doing a reliable exploit. Then I'm going to do to talk about my reimplementation of the exploit, and hopefully, at the end, we're gonna have some things to take away or maybe not. We will see. Okay so it was the evasi0n7 jailbreak was released about 4 years ago. And that's the archaeology in the title. That's ancient history right? And if you were following the jailbreak community, you might remember this huge drama around this jailbreak, initially, with geohot and if he was planning or not to release it before the evad3rs. And who he was planning to sell it to, and some leaked discussion that he had with some of that he was offering money to buy. And geohot, his jailbreak supposedly using some of the bugs the evad3rs were using so this is a huge drama. And then after the evasi0n7 jailbreak released, like maybe a few hours ago, people realize that if your phone had a Chinese locale then the jailbreak was installing a piracy app. So, that was basically a third-party app that was taking you to an app store not operated by Apple but by TaiG that had some pirated versions of the real applications on the App Store. And, of course, that also create like a huge drama, this practice. Okay, so a lot of things were said about the jailbreak at that time and about the TaiG pirate App Store. But what I really set apart was this tweet. And the really important thing that I like about this tweet is, that it doesn't really make sense. So he says that we have to decide to remotely disable the default installation of TaiG in China for further investigations of the piracy. So that whole thing doesn't make sense. So you mean, you didn't know what was happening? You didn't bundle it with a jailbreak? Are you going to disable it for new installations? And then, what does remotely then mean exactly? So what about the people that already had the apps, the piracy app. How are you going to disable that? Is that what remotely refers to? So that's an excellent tweet I think. Okay, so some point after the evasi0n7 jailbreak was released geohot did a writeup on the userland part of it. So, he analyzed how the userland part worked and he stopped at the point of gaining root and basically, he mentioned in his writeup that the evasi0n7 untethered binary, which basically what was good doing the kernel exploit, was obfuscated. And as we will see this was indeed the case and as far as I know that's the first jailbreak that used the deliberate obfuscation. I don't know the reason, I assume it's partly to hide the the piracy app store that was bundled with it and maybe partly to hide the bug, the kernel bug, but I'm not sure about the reason. Now p0sixninja who found as far as I know the bug, the kernel bug did a writeup on the kernel bug, it's on the iPhone wiki, and he basically describes the bug and he stops at the point where he gets a crash log from gdb. So he doesn't say anything about how to exploit it. Okay, so after all these things happened then I decided to reverse engineer the untethered binary and understand the exploitation techniques and I was really interested to reverse engineer the obfuscation that the evad3rs were using, it seemed like an interesting challenge, and... but as I also mentioned earlier I was really interested to understand the exploitation techniques that they were using that was more important for me at that time. And, okay, so the jailbreak was released December 2013 and I started doing that around February 2014, and I did that while having an actual day job, right, so I was spending at most two days per week on that. So what was my setup? I had an iPhone 4, and if you know about iPhone 4s they have a boot ROM bug called limera1n which basically allows you to load arbitrary kernels, unsigned kernels, on the device and run them and that basically means that you can very easily set up kernel debugging. So initially I had an iPhone 4 device with iOS 7.0.6. I want to remind you that iPhone 4 is ARM32, right. I also had an iPhone 5s with the same version of iOS and I had that in order to verify all my findings and all my tests on - to redo my tests on an ARM64 device and as I told you - the iPhone 5s at that time was the only ARM64 device. Actually, I think on the market, I don't think there was another consumer device with ARM64 at that time. So that's the exact version of version 7 I was analyzing and of course IDA, gdb, lldb. Now the lols in this slide they don't actually refer to something funny they actually mean something very painful and that caused a lot of like sleepless nights, but I'll get onto that. Okay, a few things about the obfuscation. So, not all the functions of the entire binary were obfuscated, but some of the important ones were, and those were the ones that were triggering the bug and they were actually doing heap manipulation and all the other important things. Now I have been told, I haven't checked that, but I have been told that later versions remove the obfuscation but I'm not sure about that, I haven't verified it and I already had my implementation done at that point so I wasn't that interested to look at that. So as I mentioned the kernel bug that the evasi0n7 untethered binary was based on was found by p0sixninja, and basically as far as he says on that iPhone wiki page he used that six line bash script fuzzer to find it. So as you can see he basically creates device nodes and, with controlled arguments here like minor and major numbers. Now in order to get to the point to create device nodes you basically need to be outside of the application sandbox that exists on iOS and you also need root privileges and that's what I refer to as the userland part of the evasi0n7 binary and I'm not going to cover that at all. So I'm gonna start my analysis from the point on that we have escaped the sandbox, we have obtained root and now we go to exploit the kernel bug. Now that's code from that version of the XNU kernel that had the bug. Now this ptsd_open function is called everytime userland code opens a /dev/ptmx device and then this ptmx_get_ioctl function is called. Now the important thing here is that dev here is completely user controlled and then it's passed to this ptmx_get_ioctl function with no checks at all, right, and then this ptmx_get_ioctl function uses this to index an array without any checks. So basically the bug's an invalid indexing bug, right, so since we can control that you can put here whatever. I have here the ptmx_ioctl struct that, okay, this array here is, so this state struct here is global to the kernel and this pis_ioctl_list array here is on the kernel heap and it is an array of ptmx_ioctl structs and that's the PTMX ioctl struct and the important thing here is, that I'm going to refer to again and again during the talk, is that it has a pointer to a tty struct as the first element of the structure. Okay, so we control the index to the array, so what can we do with that? So here as you can see it return the ptmx_get_ioctl function returns whatever it indexes, right. So, as you can see here is it assigns this pti variable and then does all kinds of interesting things, so pti is controllable, tp is controllable here as well after this dereference here to some controllable value and, I mean in other code parts of the kernel this is called again and so there are there are a lot of things to consider when you know the bug and then you try to think how to exploit it. Okay, one important thing here that I wanted to mention is that this ptmx, this function here ptmx_get_ioctl also does the allocation of this struct here, of this tty struct here and that's important because I'm going to use further on. Okay, another important thing is that you basically, this bug what allows you to do is you can control the size of this array here, so by, can you see that? Okay, so by repeatedly open the ptmx device you can grow this array and you can grow it as you see here by this grow vector that's 16, but it doesn't matter. What matters is that the size of this array in bytes is controllable by you, the person who are trying to exploit this bug. Now, for example these are notes from my exploit so if I did one allocation, if I did one open of this ptmx device then this array was going into kalloc_64. If I was doing 17 it was going to kalloc_128, if I was doing 33 opens here it was going to kalloc_192 and so on and so forth. So I could decide in which kalloc zone I could place the array. If you don't know kalloc zones, they are basically, you can think them as container, you can think kalloc zones as containers for heap objects on the kernel heap. All of them can be of different type but they're, all of them are of the same size, right, so kalloc_64 can have different structures of size 64 bytes, but all of them are our size 64 bytes. Okay so I started debugging the untethered binary in userland, that's how I started. So initially I was using gdb and I found out that nothing worked with gdb. It was at that point Apple was starting to move from gdb to lldb, so I don't, maybe that was the reason gdb wasn't tested at all. So when I say nothing worked I mean that I was placing break points and they weren't hitting and I was trying like stepping and it was continuing execution and stuff like that. Sometimes I couldn't even attach the binary. So then I moved to lldb, on lldb set up with debugserver and things were much better. Now, while I was experimenting stealing from, just with userland debugging my iPhone 4 device went to into a recovery loop and I wasn't able to get out of it, so I was forced to do a clean restore of the device. The problem was that at that time only iOS 7.1 was signed by Apple, so I couldn't install a version of files that hit the kernel that hit the bug that I was interested to look at, but on the other hand I couldn't not restore my device because that was the only device I had at the point I could do kernel debugging with. So I updated my device to 7.1. As I said just told you 7.1 didn't have a vulnerable kernel to this bug, so what I wanted to do was basically to boot an iOS 7.1 device with a 7.0.6 kernel, and in order to do that I could use the limera1n bug that allowed me to boot arbitrary kernels and the utility to do that was redsn0w, right. The problem was that redsn0w only supported up to iOS 6 and it wasn't, it didn't have support for iOS 7 so I left all the other things I was doing and I started reversing redsn0w to understand how it worked. Redsn0w, if you don't know it's, it was back then and still is closed source, right, so I started reversing that to understand how it worked in order to support, for me to hot patch it, to binary patch it to add support for iOS 7 and I spent like I don't know maybe a month on that and then I realized that it was, it wasn't leading me anywhere, I couldn't understand a lot of things about how redsn0w was implemented, so I I stopped doing that, and at that point I found opensn0w which was an effort by winocm to implement redsn0w as open source. So, it seemed to have support for iOS 7 and that was good, I tested that and it was working. Now my problem was that I couldn't have an arbitrary length of boot-args. Boot-args are the arguments that you pass to the kernel when it boots and they are really important in iOS because by passing certain boot-args to the kernel you can disable sign checks, you can enable kernel debugging, so it's really important to be able to pass arbitrary length boot-args. And iOS 7.1 was using absurd 9 character so that was the reason opensn0w couldn't support more So what I ended up doing was I patched iBEC, which is basically the loader of the kernel, right, that passes boot- args to the kernel when it boots and, basically I changed the pointer to the boot-args to some other place that had much more space. So at that point I was able to pass arbitrary-length boot-args to my kernel. So where we are at last? So I had an iPhone 4 device with iOS 7.1 and I was using opensn0w to boot the 7.0.6 kernel that had the bug that I was interested to exploit. Now, one side note here is that as I was doing that and I was trying to add to open snow all the patches to the kernel to enable kernel debugging, I was reversing the evasi0n7 binary as well. Now, the evasi0n7 binary was trying also to, after it exploited the kernel it was patching it to enable kernel debugging, but, so I was just copying their patches, right, and adding them to opensn0w, but I realized at some point that they missed some check for the debug- enabled variable and KDP wasn't really working, so the session was established and it seemed like it was working, but if you tried to actually use the kernel, the KDP, the kernel debugging setup for to do actual, like to attach debugger to the kernel and do whatever, like place a breakpoint or step then KDP just froze. So I added another part that was required on that. Ok, so kernel debugging at last, but that's not really what happened, because you know breakpoints didn't always work so you were placing a breakpoint and it wasn't hitting when execution was reaching there and you were trying to step instructions and the execution just continues, so you were stepping one instruction it was just like you would type in continue and if you were taking too long to type an lldb command then KDP froze and then you had to restart your device, re-establish the kernel debugging session and start from zero. And if you issue commands too fast then KDB froze again, so you have to reboot again. It was amazing, it was great time. And now I did similar stuff with iOS 6 and I distinctly remember that was much easier and kernel debugging worked much better. And... I mean the issue that comes to everyone's mind that does that is: do Apple engineers really use KDP for debugging the iOS kernel or do they use something else? Okay, so now I could debug the evasi0n7 untethered binary both from the userland side and from the kernel side, and that was good because I was analyzing at run time and at the same time I was reversing it in IDA, so the obfuscation who... I could do it much faster since I was taking hints from runtime. So I... at that point things started moving fast and I quickly found that it was abusing the data by structure to obtain read/write access to physical memory. I mean that was interesting to me, but I was expecting something else. I was expecting something like what they did in iOS in the evasi0n6 jailbreak, that they did like a lot of heap manipulation and that's my interest actually, heap exploitation. So at that point I decided to stop reversing it and reimplement the exploit the way that I wanted to do it. So obviously that wasn't work from scratch, it was from everything that I understood up to that point, and what I really wanted to use was the vm_map_copy structures technique by Dowd and Mandt and I'm going to explain that in the following slides, how it works. Okay, so at that point I had the clear understanding of the bug, what it was and I had the general idea like about how to exploit it and I mean if you've done that you know then it takes a lot of pen and paper like ideas you develop on paper, then you go test them and they don't work and then you design them again and then again and you fail and you despair and then you suddenly have an idea and you spend like I don't know like two nights stay up until 5:00 in the morning testing things and they don't work and then you despair again and ad nauseam. But eventually you get somewhere so let's talk about exploitation now. Now, a few things to refresh your memory about the bug. So as I said it was an invalid indexing bug. This pis_ioctl_list array was on the heap and I could control in which kalloc zone it can go. I can grow it, but once I grow it I cannot shrink it back. Now, that's code from that ptmx_get_ioctl function, so what... basically what it does it allocates a new ptmx_ioctl structure and then it uses the index that you provide... that you control to store the address on the array. Now, this allocation here... this struct here goes into kalloc.88 and that's useful for the next parts. Okay, a few things about the technique I wanted to use... about the exploitation technique I wanted to use. So it's the vm_map_copy technique, it was proposed by Dowd and Mandt and basically they were spraying the heap with these structs here, the vm_map_copy structs, and assuming you have like some way to corrupt this struct that you've sprayed on the heap if you can overwrite this kdata element here, then basically what you have is a leak of kernel memory other adjacent like next to the kdata, whatever is below or above the kdata pointer or arbitrary if you put whatever address you want in there. By overwriting the kalloc_size element here and then freeing the struct on the heap, you put it on a wrong zone and basically when you allocate it back, since you put it on on a different size zone, you can have a heap overflow. So that's a general overview of this technique. So but you corrupt this struct and you get primitive exploitation primitives. Okay, so what was the idea I had at that point? The idea was to use the... this pis_ioctl_list index bug to corrupt this kdata pointer here and to have arbitrarily... Sorry, we have a relative leak of kernel heap memory, and that would be my first step towards exploiting the bug. Of course the end goal is to have arbitrary read/write, right, and of course it was just a fuzzy idea at that point and you know that's always the goal, but when you study the bug and you see the different code paths and how the things you affect are used, then you have some maybe not completely concrete things in your mind, but you know that interesting things can happen, so that's what I had at that point. Okay, so let's talk about the exploitation strategies now. So at stage one I sprayed the kernel heap with vm_map_copy structs and I decided to work on the kalloc.256 zone, and the reason for that was completely arbitrary... was because of all the kernel debugging I have done up to this point of this entire binary I saw that this kalloc zone was not really used that much, either by the kernel or by whatever the exploit was doing. So... that's good because it means that you can... you as an exploiter can have much better control over the kernel heap if there aren't other things placing allocations on the zone you work. So I decided to use the kalloc.256 zone and I avoided of course kalloc.384 because the tty structs were going there and that would really mess up my heap arrangements. So the first... let me actually... ok. So what I wanted to do was to do this. So initially you spray the heap with vm_map_copy structs and you control both their size and their contents, the content don't matter at this point. So it... just the size matters. So I spray with 256 bytes vm_map_copy structs and then I free every other second one and I create this kind of pattern like a vm_map_copy and a free slot and a vm_map_copy and a free slot and then I grow the pis_ioctl_list array to 256 bytes and then it goes into one of these free slots here. Now, the code for doing that looks something like that, so what this basically does it sends... it creates this... so if you see here the out of line mach messages as basically these vm_map_copy structs and... Their size is 256, their buffer doesn't matter at this point and you just send them like machs and methods. And then after you've sprayed with them then you free every second one here... with this loop here. So in order to make this free slot you just receive this mach out of line messages that correspond to the vm_map_copy structs. And after you've created the holes you basically grow the array to 256 bytes. How do you do that? As I mentioned earlier you open the dev ptmx device a number of times. How many times doesn't matter, like a specific number of times that I mentioned earlier, that I have noticed grows it 256 bytes. So that's the arrangement you have at that first stage. Okay, so the second stage is done on the kalloc.88 zone. So I spray again with vm_map_copy structs and this time I make them 88 bytes to go to the kalloc.88 zone and then I create again holes. And then I trigger the bug with an invalid index value and remember that when you trigger the bug a ptmx_ioctl struct is allocated and this goes to kalloc.88. But because on kalloc.88 I have created this pattern of used free used free it goes into one of the free slots. So now I have a ptmx_ioctl struct in one of my free slots. I don't know where that is but I know that it falls into the pattern, right, so I trigger the bug and remember that basically you control this index, right, so since I control the index I point it to the vm_map... to the kdata element of the vm_map_copy struct that I know is below the free slot that the array went into. I don't know the address, right, I can't put like an address there, but I can... I know the relatives... the relative distance in bytes because I created the pattern... the heap pattern. So let's go to... okay. So it looks like that. So that's my first stage, right, free, vm_map_copy, ... and this is the same pattern on the kalloc.88 zone. When you trigger the bug, this ptmx_ioctl structure is allocated. It goes into one of the free slots, right, and then the bug itself, which is what we see here is... remember you control the index, so this is the new allocation that went here, and then it goes and stores the address where the index tells it to store it. But remember that this is controlled, we control that, so what I do I point this here relatively to the neighboring vm_map_copy struct at the kdata field, right. So in this kdata field here of the vm_map_copy struct I have now this address, right. So that's how the heap looks like. I have here the code, it's very similar to the first stage that you spray with vm_map_copy structs of size 88, machs and methods, right, and then you receive every second one, you create the holes on the 88 zone and then you trigger the bug here, right. This invalid pis index number here is basically what points relatively here, right. So I have now the address of this ptmx_ioctl struct which is an address on the kalloc.88 zone. I have it on the kdata field of this vm_map_copy struct here. So what I do... I can simply receive these methods and in its content I can see the address of that slot on the kalloc.88 zone. So that's the code to do that, I simply receive all the messages and that's my address. Okay, so at this point I only... what I only have is this address here, right? I have the address of this heap slot. So, at that point I started looking at other code paths that this invalid index... what other variables this invalid index was influencing and I found the code path that was actually giving... was giving me a write and... But in order to reach that I needed to survive several dereferences, and what I only knew was just the kalloc.88 address, right? Nothing else. So I will now walk you through everything that gave me this write. So I clean up the kalloc.256 zone and I spray it again with vm_map_copy structs and create holes exactly like the previous step... the first stage. Again, next to the pis_ioctl_list array I have a vm_map_copy struct, but at this time I... in all the the vm_map_copy structs I put a payload of the... of this fake ptmx_ioctl address I have. And remember that the first element of the ptmx_ioctl struct is a pointer to tty struct and I can use the leaked address I have for this pointer that I don't know... I didn't know where to point it to. So, the next step was to clean up the kalloc.88 zone and spray it again, and again I sprayed with vm_map_copy structs, but at this time at their payload I can put now the fake tty struct that the ptmx_ioctl struct is pointing to. The problem at that point was that the tty struct with 256 bytes and kalloc.88 has... the slots are only 88 bytes, so I couldn't just with the elements of the... just with the first 88 byte elements, I couldn't get to the path that was giving the write, so I needed to find some other way to host my fake tty struct. So remember that I couldn't work on any other kalloc zone or anywhere else because what I only knew was the address of that kalloc.88 zone, I had nothing else to build on. So at that point I started doing a much more complicated heap arrangement. So instead of spraying just one thing I was spraying... I was trying to create a pattern of two controlled things. Now, I couldn't use vm_map_copy structs for both these slots because the vm_map_copy structs has a header, right? So it would mess up my fake tty struct. So by reading i0n1c's kernel heap exploitation slides, I realized that I could spray the heap with XML properties of length 88 from that AppleJPEGDriver and I could place as a second controlled object after the vm_map_copy struct these XML properties which are completely controlled in content, and I could host the second part of the tty struct there. I mean, it's still not 256 bytes, but what it gives me is the ability to survive all dereferences to reach the write that I was interested in. Okay. So, a few things about the tty struct. So that's what I got... I wanted to create on the kalloc.88 zone, right, so that's the tty struct that the ptmx_ioctl struct is pointing to. Now, what basically I wanted to do here is I wanted to point... the final thing was to use this clist struct to control this element here, c_cs, as a start of the ring buffer for the tty, to give me an arbitrary write... Sorry, to give me a controlled write. I started playing a bit with to use it to do arbitrary write, but I found that I wasn't able to do it because at later stage some other parts of the tty struct were needed that I wasn't able to control, so I only had two 88-slots to host my fake tty struct. So that wasn't stable. So I was only using that to do a relative write. So we'll see the code later on, let's go to the heap layout. So that's the third stage. Again, remember I sprayed the kalloc.256 zone with vm_map_copy structs/ frees, just place my pis_ioctl_list array next to vm_map_copy struct. Remember that I control the contents of vm_map_copy, right, so I placed in the buffer of vm_map_copy this ptmx_ioctl address that I know and I point the invalid index that I control to this ptmx_ioctl... this address that I put here. And what is this address? It's that leaked address that I got in the previous stage which points to the kalloc.88 zone. And what's the arrangement of that kalloc.88 zone? It's as I told you a vm_map_copy followed by an XML properties. vm_map_copy, XML properties... And all this hosts this fake tty struct, right? All these are the same, I just explained here how it looks like. So this points to the kdata element here and the rest of it holds the rest of the... all this is basically the fake tty struct, like the buffer of the vm_map_copy and then following the XML contents of this heap allocation. And where do I... this c_cs pointer that I told you that I wanted to control, where do I point it? I point it relatively again, I don't know any addresses but I can put it relatively since I know the... since I created this heap arrangement, I can put it relatively to the size of the kalloc size of the neighboring vm_map_copy struct. And why do I need this? Because I want to use the vm_map_copy technique by Mandt and Dowd that I mentioned earlier, so that's the end goal. So what's the code looks like? Okay, that's the spray of 256, we've seen that a lot of times, then we have the freeze... wait, no, that's not the freeze. So that's the allocations of the 256... that's... yeah, I don't have the freeze here because they don't matter, because we have seen them before. So what I have here is the spray of the kalloc.88 zone and the important thing here is that... what I wanted to show you that is that at every step I took two allocations. One is the vm_map_copy struct here with the machs and methods, and the second part is the XML properties, which are sprayed on the heap when you open the device driver, the AppleJPEGDriver. And what are the contents of that XML properties? They're basically that fake... the second part of the fake tty struct that you have the controlled c_cs pointer that will give me the relative write. So if you see here, I have this function setup_fake_tty that basically creates the structs so I don't have to type all the time, and we are at second stage here, and basically what you can see here is the creation of the fake tty struct, right? So that's the different elements of the fake tty as we saw it from the code. And that's the write offset I wanted to... that I pointed to the kdata field of the neighboring vm_map_copy struct. So, again, that's how it looks like in the heap. Okay, so after that, after we have arranged the... we have arranged it this way, we trigger again the invalid index array bug, but at this time on the slave ptmx device. I was only doing that on a master ptmx device, but in order to reach that write code path that I mentioned, you need to get on a slave ptmx device. So that's what happens here. And then you simply write to the corresponding descriptor and it just dereferences this c_cs that you controlled and your end... and it writes with whatever you want to write. And what do I want to write? I want to write a new size for the vm_map_copy struct... for the kalloc size field of the vm... of the neighboring vm_map_copy struct, so I can use the Dowd and Mandt technique. So, putting everything together. So at that point I have a controlled corruption of a vm_map_copy struct and I can use the primitives to get arbitrary... an arbitrary leak, so I can leak for example the KSLR-slide and I can do a heap overflow. Again these are how you can use the primitives that Mandt and Dowd gave us. Now I also know my location on the kernel heap, and remember that... that's basically... we found that on the stage... on the first... on the first of stages and we only... we use only that, like where that ptmx_ioctl struct was stored on the kernel heap, that's the only thing we knew, that address, in order to successively build on it, in order to reach like a much more useful primitive. And the important... the interesting thing here is that everything up to this point is data only, right? So you haven't injected any code, you haven't done anything at all that you could be caught somehow by a kernel self-protection mechanism or these kind of things, everything's data only. So once you reach that point, how do you get PC control? So since you can use Dowd's and and Mandt's technique, you can basically do a heap overflow, so you can again do a heap arrangement, you can place IOKit objects next to vm_map_copy structs where you can overflow from, and you can corrupt IOKit objects and from there you can have... also you can do an arbitrary write... read/write, so you can... by the arbitrary read you can read the vtables of the IOKit objects so you know the KSLR-slide and you can corrupt it in order to get PC control. Of course getting to a whole jailbreak from that point is out of the scope of this talk, and... but is not that hard actually from that point on. And okay, so after doing all that how close was that exploit to the evasi0n... to the real evasi0n7 kernel exploiter? I'd say it was pretty far off, but I mean it wasn't my point to recreate it like completely, but it was my point to play with the heap and to try to do complex heap arrangements and to see how much I understand the iOS kernel heap, that was the point of this whole exercise for me. Okay, so some lessons learned. So the real surprising thing for me at that point was that I couldn't believe that Apple does kernel debugging by KDB. It was very flaky, it was very unstable as I told you. If you type commands too fast it froze, if you type commands very slowly it had like a go-stop timer and froze, I think. there was a claim of something like that and it's unbeliev... I couldn't believe that the Apple engineers were using this interface to do kernel debugging. So it was really hard to do anything on the kernel side of idevices. But of course I don't really mean that you shouldn't mess with these things, right? I mean, these devices are really interesting and it's really becoming harder to hack them, but I think it's much more fun and I think the only takeaway may be that you shouldn't report bugs to Apple at all and if you need street cred you should just report white elephant bugs now. I mean that's always good. And I mean this very... this is getting very esoteric, right, there are not a lot of information and Apple keeps changing stuff and everything is closed source, I mean, all the important parts are closed source... and I mean, I really think people that work on that things should share notes as much as possible. Okay, so these are some of the people I was talking to while doing all this and I want to mention them, and basically that's all of the material I have and I'm open to any questions you might have. applause Herald: Thank you, argp, for the talk. So we have prepared microphones 1, 2, 3 and 4 in the room and we have a Signal Angel, I think. You... when you have questions, you can give me a hand sign, but I think we start with microphone 2 here in the front. And please ask questions and no comments, there's time after the talk. Okay, go ahead. Q: Thanks for the awesome talk. argp: Thanks. Q: I have a question about heap spraying. Was your heap spraying really stable? If it is not successful, did it crash the device? argp: Yeah. So I haven't mentioned it here, but it was pretty stable I think. It was something like... because I did a lot of tests for that because it was really interesting for me to know. It was maybe something like 90%, so 9 out of 10 times it worked, but if it didn't work - yeah, then... yes it crashed the kernel and crashed the device, yeah. Q: And did you try to return heap into some kind of initial state to start your exploit from scratch? argp: Yeah, that's true I haven't included that, but you're right. So the initial step on every spray that I mentioned here was to spray a lot of objects of the specific size you were targeting in order to get basically a new page of the kalloc zone, right? So you... so even if as I told you the kalloc 256 zone wasn't that busy, it's still... there were still allocations going on it, right? So if you did a lot of initial spraying, you were making sure that when you're... the allocations that mattered to you we're made, were on a new page that weren't... wasn't too much noise from other allocations from the kernel. So yeah, you're right I haven't included that, but yeah, that happened. Q: Thanks, great. argp: Thanks. Herald: Then microphone 1, please. Q: Also thank you for your awesome talk again. argp: Thanks. Q: My question was nowadays it's way harder to use vm_copy I think Apple truly deprecated it, it's not possible anymore that due to security. Do you see hope in reconstructing some function that does the same or is it totally dead now? argp: Oh, you mean the vm_map_copy technique? Q: Yes. argp: No, I think it's completely dead now. Q: All right. And I recently saw on the iOS logs vulnerabilities that again a vulnerability in AppleJPEGDriver was found. Do you think... have you looked into it or... argp: Well, Apple... the AppleJPEGDriver is one of the 4, I think, IOkit drivers that you can reach from the container sandbox, right? So that means it's very fast by everyone, Apple included, and very audited. So I'm not saying that there aren't many... there aren't things there, like interesting findings, but if there are they're not going to live much longer, I think. Q: Okay, thank you. Herald: Thanks for your question and now from the Signal Angel a question from the Internet. Signal Angel: Yes, I have a question from the internet. How long did this research take you? You said two weeks in the beginning, but from begin to end, how many hours about? Because you also said it was during work? argp: No, it didn't it didn't take two weeks, no. It took like maybe close to three months or two months and something like that. So I spent... as I mentioned I spent like a complete month, I think, like - maybe three weeks, maybe not a complete month just on reversing redsn0w and trying to get redsn0w to play with iOS7. So I wouldn't count this month in the exploit part of it, right? So if you're interested just in the kernel exploit part I would say something like maybe seven weeks, something like that. But just with 2 maybe 3 days per week right, not complete weeks. Herald: Okay, then microphone 1, please. Q: Congratulations on your talk which was really interesting, I liked it a lot and my question is if the technique you used to exploit the bug was in FreeBSD or any other BSD as well? argp: Oh no, no. I mean, the vm_map_copy struct doesn't exist anywhere else except the XNU kernel. But I think the interesting takeaway is that you can do complex heap arrangements if you understand the kernel heep allocator, right? So this process I described by creating holes and maybe controlling 2 allocations in order to host fake structures that you are able then to use to get exploitation primitives then that's applicable everywhere, right? Herald: Okay, then we go to microphone 2 again, please. Q: So I saw one sentence, just not report or... just don't report the bugs. I would like to understand your thinking behind, because I think this is really important for companies to know the bugs that they made and yeah, make the products better and this is really beneficial for researcher because for example Apple they pay a lot of money for the bugs. What... argp: Okay, yeah, I don't have much to say on that. I mean, apart from: if all the bugs are fixed then you won't be able to do this kind of work and it's no fun. Sorry, I don't have anything else to say on that. Sorry, I don't have anything else, no comment. Herald: Okay. Signal Angel, do we have another question from the internet? Okay, then please a big round of applause for our speaker! argp: Thanks. applause postroll music subtitles created by c3subtitles.de in the year 2020. Join, and help us!