1 00:00:00,000 --> 00:00:19,960 *36c3 preroll music* 2 00:00:19,960 --> 00:00:25,420 Herald: So, Samuel is working at Google Project Zero on especially vulnerabilities 3 00:00:25,420 --> 00:00:30,200 in Web browsers and mobile devices. He was part of the team that discovered some of 4 00:00:30,200 --> 00:00:33,960 the vulnerabilities that he will be presenting in this talk today in detail 5 00:00:33,960 --> 00:00:41,370 about the no user interaction vulnerability that will be able to 6 00:00:41,370 --> 00:00:48,660 remotely exploit and compromise iPhones through iMessage. Please give Samuel a 7 00:00:48,660 --> 00:00:55,890 warm round of applause. *Applause* 8 00:00:55,890 --> 00:01:00,880 Samuel: OK. Thanks, everyone. Welcome to my talk. One note before I start, 9 00:01:00,880 --> 00:01:05,900 unfortunately, I only have one hour. So I had to omit quite a lot of details. But 10 00:01:05,900 --> 00:01:09,760 there will be a blog post coming out hopefully very soon that has a lot more 11 00:01:09,760 --> 00:01:14,729 details. But for this talk, I wanted to get everything in there and leave out some 12 00:01:14,729 --> 00:01:21,840 details. OK. So this is about iMessage in theory some of it applies, or quite a lot 13 00:01:21,840 --> 00:01:26,050 actually applies to other messengers, but we'll focus on iMessage. So what is 14 00:01:26,050 --> 00:01:31,290 iMessage? Yeah, it's a messaging service by Apple. We've heard about it in the 15 00:01:31,290 --> 00:01:37,700 previous talk a bit. As far as I know, it is enabled by default. As soon as someone 16 00:01:37,700 --> 00:01:42,759 signs into an iPhone with their account, which I guess most people do, because 17 00:01:42,759 --> 00:01:48,540 otherwise you can't download apps. Interestingly, anyone can send messages to 18 00:01:48,540 --> 00:01:55,211 anyone else. So it's like SMS or phone calling. And then if you do this, then it 19 00:01:55,211 --> 00:02:01,390 pops up some notifications, which you can see that here on the right screenshot, 20 00:02:01,390 --> 00:02:06,879 which means that there must be some kind of processing happening. And so, yeah, 21 00:02:06,879 --> 00:02:11,080 this is like default enabled, zero click attack surface without the user doing 22 00:02:11,080 --> 00:02:15,780 anything, there's stuff happening. And then on the very right screenshot, you can 23 00:02:15,780 --> 00:02:23,700 see that you can receive messages from unknown senders. It just like says there. 24 00:02:23,700 --> 00:02:29,829 This sender is not in your contact list, but all the processing still happens. In 25 00:02:29,829 --> 00:02:36,920 terms of architecture, this is roughly how iMessage is structured, not very, yeah, 26 00:02:36,920 --> 00:02:42,760 anything too interesting, I guess. You have Apple cloud servers and then sender 27 00:02:42,760 --> 00:02:48,240 and receiver are connected to these servers. That's pretty much it. Content is 28 00:02:48,240 --> 00:02:53,830 end to end encrypted, which is very good. We heard this before, also. Interestingly, 29 00:02:53,830 --> 00:02:58,320 this also means that Apple can hardly detect or block these exploits though, 30 00:02:58,320 --> 00:03:06,130 because, well, they are encrypted, right? So that's an interesting thing to note. So 31 00:03:06,130 --> 00:03:11,920 what does an iMessage exploit look like? So in terms of prerequisites, really the 32 00:03:11,920 --> 00:03:16,120 attacker only needs to know the phone number or the email address, which is the 33 00:03:16,120 --> 00:03:22,160 Apple account. The iPhone has to be in default configuration so you can disable 34 00:03:22,160 --> 00:03:26,910 iMessage. But that's not done by default. And the iPhone has to be connected to the 35 00:03:26,910 --> 00:03:31,980 Internet. And in terms of prerequisites, that's pretty much all you need for this 36 00:03:31,980 --> 00:03:38,169 exploit to work. So that's quite a lot of iPhones. The outcome is the attacker has 37 00:03:38,169 --> 00:03:43,410 full control over the iPhone. After a few minutes, I think it takes like five to 38 00:03:43,410 --> 00:03:48,970 six, seven minutes maybe. And it is also possible without any visual indicator. So 39 00:03:48,970 --> 00:03:53,880 there's no... you can make it so there are no notifications during this entire 40 00:03:53,880 --> 00:03:59,981 exploit. OK. But before we get to exploiting, of course, we need a 41 00:03:59,981 --> 00:04:04,460 vulnerability and for that we need to do some reverse engineering. So I want to 42 00:04:04,460 --> 00:04:09,060 highlight a bit how we started this or how we approached this. And I guess the first 43 00:04:09,060 --> 00:04:14,450 question, you might be interested in, is what daemon or what service is handling 44 00:04:14,450 --> 00:04:20,989 iMessages. And one easy way to figure this out is you can just make a guess. You 45 00:04:20,989 --> 00:04:26,429 look at your process list on your Mac, the Mac can also receive iMessages. You, like, 46 00:04:26,429 --> 00:04:30,890 stop one of these processes and then you see if iMessages are still delivered. And 47 00:04:30,890 --> 00:04:36,140 if not, then probably you found a process that's somewhat related to 48 00:04:36,140 --> 00:04:43,680 iMessages. If you do this, you'll find "imagent", already sounds kind of related. 49 00:04:43,680 --> 00:04:47,510 If you look at it, it also has an iMessage library that it's loading. Ok, so this 50 00:04:47,510 --> 00:04:55,170 seems very relevant. And then you can load this library in IDA. You see a screenshot 51 00:04:55,170 --> 00:05:00,010 top right. And you find a lot of handlers. So for example, this 52 00:05:00,010 --> 00:05:03,840 "MessageServiceSession handler: incomingMessage:", and then you can set a 53 00:05:03,840 --> 00:05:07,170 breakpoint there. And then at that point you can see these messages as they come 54 00:05:07,170 --> 00:05:13,230 in. You can dump them, display them, look at them, change them. And so this is a 55 00:05:13,230 --> 00:05:17,040 good way to get started. Of course, from there, you want to figure out how these 56 00:05:17,040 --> 00:05:22,460 messages look like. So, yeah, you can dump them in there when they come in in the 57 00:05:22,460 --> 00:05:30,000 handler, on the right side you see how these iMessages look like more or less on 58 00:05:30,000 --> 00:05:37,460 the wire. They are encoded as a PList, which is an Apple proprietary format. 59 00:05:37,460 --> 00:05:45,140 Yeah, think of it like JSON or XML. And I guess some fields are self-explanatory. 60 00:05:45,140 --> 00:05:50,160 So, "p", that's the participants in this case this is me sending a message to 61 00:05:50,160 --> 00:05:57,270 another account I own. You have "T" which is the text content of the message. So 62 00:05:57,270 --> 00:06:04,530 "Hello 36C3!". You have a version, for some reason you also have an XML or HTML- 63 00:06:04,530 --> 00:06:11,190 ish field, which is probably some legacy stuff. It's being parsed, this XML. But 64 00:06:11,190 --> 00:06:14,170 yeah, the whole thing looks kind of complex already. I mean maybe you would 65 00:06:14,170 --> 00:06:20,200 expect a simple string message to just be a string. In reality, it's sending this 66 00:06:20,200 --> 00:06:29,340 dictionary over the wire. So let's do some more attack service enumeration. If you 67 00:06:29,340 --> 00:06:34,980 then do more reverse engineering, read the code of the handler, you find two 68 00:06:34,980 --> 00:06:41,250 interesting keys that can be present, which is ATI and BP, and they can contain 69 00:06:41,250 --> 00:06:49,270 NSKeyedUnarchiver data, which is another Apple proprietary serialization format. 70 00:06:49,270 --> 00:06:55,340 It's quite complex, it has had quite a few bugs in the past. On the left side you see 71 00:06:55,340 --> 00:07:01,930 an example for such an archive. It's yeah, it's being encoded in a plist and then 72 00:07:01,930 --> 00:07:08,360 it's pretty much one big array that has, like, every object has an index in this 73 00:07:08,360 --> 00:07:15,360 array. And here you can see, for example, number 7 is some object, is the class 74 00:07:15,360 --> 00:07:24,500 NSSharedKeyDictionary. And I think key one is an instance of that class and so on. So 75 00:07:24,500 --> 00:07:30,590 it's quite powerful. But really what this means is that this serializer is now zero 76 00:07:30,590 --> 00:07:35,430 click attack surface because it's being passed on this path without any user 77 00:07:35,430 --> 00:07:42,850 interaction. So I said it's quite complex. It even supports things like cyclic 78 00:07:42,850 --> 00:07:47,889 references. So you can send an object graph where A points to B and B points 79 00:07:47,889 --> 00:07:55,540 back to A for whatever reason you might want that. Natalie wrote a great blog post 80 00:07:55,540 --> 00:08:00,040 where she describes this in more detail. What I have here is just an example for 81 00:08:00,040 --> 00:08:06,200 the API, how you use it. This is Objective C at the bottom. If you're not familiar 82 00:08:06,200 --> 00:08:12,190 with Objective C, you can think of these brackets as just being method calls. So 83 00:08:12,190 --> 00:08:17,360 this is doing, in the last line, it's calling the unarchivedObjectOfClasses 84 00:08:17,360 --> 00:08:25,170 method for this NSKeyedUnarchiver. You can see you can pass a whitelist of classes. 85 00:08:25,170 --> 00:08:31,880 So in this case, it will only decode dictionary, strings, data, etc. So looks 86 00:08:31,880 --> 00:08:38,750 quite okay. Interestingly, if you dig deeper into this, this is not quite true 87 00:08:38,750 --> 00:08:44,470 because it also allows all the subclasses to be decoded. So if you have an NS- 88 00:08:44,470 --> 00:08:49,089 something-something dictionary that inherits from NSDictionary, then that can 89 00:08:49,089 --> 00:08:55,280 also be decoded here, which is quite unintuitive I think. And this really blows 90 00:08:55,280 --> 00:09:01,760 up the attack surface because now you have not only these 7 or so classes, but you 91 00:09:01,760 --> 00:09:09,650 have like 50. Okay. So this is what we focused on when me and Natalie were 92 00:09:09,650 --> 00:09:17,230 looking for vulnerabilities. It seemed like the most complex thing we found. We 93 00:09:17,230 --> 00:09:22,390 reported quite a few vulnerabilities here, you can see it maybe a bit on the left. 94 00:09:22,390 --> 00:09:31,420 The one I decided to write an exploit for is this 1917, reported on July 29th and 95 00:09:31,420 --> 00:09:38,400 then exploits sent on August 9th. Yeah, mostly I decided to use this one because 96 00:09:38,400 --> 00:09:42,900 it seemed the most convenient. I do think many of the other ones could be exploited 97 00:09:42,900 --> 00:09:47,610 in a similar way, but not quite as nice, so would maybe take some more heap 98 00:09:47,610 --> 00:09:55,700 manipulation, etc. So then Apple first pushed the mitigation quite quickly, which 99 00:09:55,700 --> 00:10:01,180 basically blocks this code from being reached over iMessage. In particular, what 100 00:10:01,180 --> 00:10:08,430 they did is, they exactly no longer allow subclasses to be decoded in iMessage. So 101 00:10:08,430 --> 00:10:12,760 that's quite a good mitigation, it blocks off maybe 90 percent of the attack surface 102 00:10:12,760 --> 00:10:22,589 here. Yeah. So then they fully fixed it in iOS 13.2. But again, after August 26th 103 00:10:22,589 --> 00:10:32,840 this was only just local attack surface. OK, so what is the bug? It's some 104 00:10:32,840 --> 00:10:37,390 initialization problem during decoding, the vulnerable class is 105 00:10:37,390 --> 00:10:42,000 SharedKeyDictionary, which again, it's a subclass of NSDictionary, so it's allowed 106 00:10:42,000 --> 00:10:50,260 to be decoded. So let's take a look at that. So, yeah. SharedKeyDictionary. 107 00:10:50,260 --> 00:10:56,000 Here's some pseudocode in Python. It's a dictionary. So its purpose is to, well, 108 00:10:56,000 --> 00:11:01,880 look up keys to values or map keys to values. The lookup method is really 109 00:11:01,880 --> 00:11:08,120 simple. It just looks up an index in a key set. So every key dictionary has a shared 110 00:11:08,120 --> 00:11:13,760 key set and then that index is used to index into some area. OK, so that's quite 111 00:11:13,760 --> 00:11:21,060 simple so most of the magic happens in the SharedKeySet. And so what that does is 112 00:11:21,060 --> 00:11:27,690 something like compute a hash of the key. Use that hash to index into something 113 00:11:27,690 --> 00:11:35,350 called a rankTable, which is an array of indices. And then if that index is valid, 114 00:11:35,350 --> 00:11:41,530 so it's being bounced, checked against the number of keys. Then it has found the the 115 00:11:41,530 --> 00:11:47,260 correct index and if not, it can recurse to another SharedKeySet. So every 116 00:11:47,260 --> 00:11:53,260 SharedKeySet, can have a sub-SharedKeySet, and then it repeats the same procedure. So 117 00:11:53,260 --> 00:11:57,980 it already looks kind of complex. Why does it have... why does it need this 118 00:11:57,980 --> 00:12:03,160 recursion? I'm not quite sure, but it's there. And so now we look at how this goes 119 00:12:03,160 --> 00:12:11,060 wrong. So this is the initWithCoder, which is the SharedKeySet constructor used 120 00:12:11,060 --> 00:12:18,289 during decoding with the keyedUnarchiver. And it looks pretty solid at first, it's 121 00:12:18,289 --> 00:12:26,070 really just taking the values out of the archive and then storing them as the 122 00:12:26,070 --> 00:12:32,370 fields of this SharedKeySet. I have a, I'm gonna go through the code here in, like, 123 00:12:32,370 --> 00:12:36,650 single step to highlight where it goes wrong or what goes wrong here, what's 124 00:12:36,650 --> 00:12:43,339 wrong with this code. So we start with SharedKeySet1 which implies there's gonna 125 00:12:43,339 --> 00:12:48,800 be another one. And at the start it's all zero initialized. It's basically being 126 00:12:48,800 --> 00:12:54,220 allocated through ?calloc?. So everything is zero. Then we execute the first line. 127 00:12:54,220 --> 00:13:02,020 Okay. So numKey, you see some interesting values coming. So far this is all fine. 128 00:13:02,020 --> 00:13:06,600 Note, that you can set numKey, at this point numkey can be anything because it's 129 00:13:06,600 --> 00:13:12,550 only being validated three lines further down, right? Where it's making sure that 130 00:13:12,550 --> 00:13:20,670 numKey matches the the real length of this array. So this is fine, but here it's now 131 00:13:20,670 --> 00:13:25,260 recursing and it's decoding another SharedKeySet. So we start again. We have 132 00:13:25,260 --> 00:13:32,680 another SharedKeySet, all filled with zeros and we start from the top. Again, 133 00:13:32,680 --> 00:13:39,740 numKey is one, so this is this is a legitimate SharedKeySet, decoding a 134 00:13:39,740 --> 00:13:47,620 rankTable. And here we are making a circle. So for SharedKeySet2 we pretend 135 00:13:47,620 --> 00:13:53,979 that its sub-KeySet is SharedKeySet1. And this actually works. So the 136 00:13:53,979 --> 00:13:59,730 NSKeyedUnarchiver has special handling to handle this correctly. So it does not 137 00:13:59,730 --> 00:14:06,410 create a third object and it makes the cycle. And we're good to go. Okay. Next to 138 00:14:06,410 --> 00:14:13,950 decode the keys area. So this is fine. SharedKeySet2 seems legitimate so far. And 139 00:14:13,950 --> 00:14:19,490 now it's doing some sanity checking. Where it's trying, where it's making sure that 140 00:14:19,490 --> 00:14:25,941 this SharedKeySet can look up every key. And so it does this for the only key it 141 00:14:25,941 --> 00:14:32,910 has, key one. Now, at this point, it's again, remember, it's hashing the key 142 00:14:32,910 --> 00:14:39,120 going into rank table, takes out 42, which is bigger than numKey. So in this case, 143 00:14:39,120 --> 00:14:44,819 this look up here has failed. And now it's recursing to SharedKeySet1. Right? This 144 00:14:44,819 --> 00:14:53,530 was the logic. And at this point it's taking out this hex41414141 as index, 145 00:14:53,530 --> 00:15:00,380 compares it against hexffffffff and that's fine, and now it's accessing, null 146 00:15:00,380 --> 00:15:07,560 pointer, which is.. the keys area is still null pointer plus, well, 41 41 41 41 times 147 00:15:07,560 --> 00:15:13,910 8. So at this point it's crashing. It's accessing invalid memory, precisely 148 00:15:13,910 --> 00:15:21,140 because in this situation the SharedKeySet1 hasn't been validated yet. 149 00:15:21,140 --> 00:15:30,500 OK, so that's the bug we're going to exploit. I have these checkpoints just to 150 00:15:30,500 --> 00:15:35,490 think where we are, so we now have a vulnerability in this NSUnarchiver API. We 151 00:15:35,490 --> 00:15:41,990 can trigger it through iMessage. So what Exploit Primitive do we have? Let's take a 152 00:15:41,990 --> 00:15:50,240 look again at the lookup function, which we saw before. So here where it's bold, 153 00:15:50,240 --> 00:15:54,770 this is where we crash. keys is null pointer, index is fully controlled. So we 154 00:15:54,770 --> 00:16:00,959 can access null pointer plus offset. And then what happens is the result of this 155 00:16:00,959 --> 00:16:06,220 memory access is going to be used as some Object-C Object. So this is all 156 00:16:06,220 --> 00:16:09,660 Objective-C in reality, it's doing some comparison, which means it does something 157 00:16:09,660 --> 00:16:16,940 like it called some method called isNSString, for example. And then also 158 00:16:16,940 --> 00:16:24,529 eventually it calls dealloc, which is the destructor. So yeah, we have... the thing 159 00:16:24,529 --> 00:16:29,209 it reads from whatever, it will treat it as an objectif C-Object calls a 160 00:16:29,209 --> 00:16:36,410 message on it. And that's our Exploitation Primitive. Okay, so here we are. How do we 161 00:16:36,410 --> 00:16:44,030 exploit this? So the rough idea for exploiting such vulnerabilities looks like 162 00:16:44,030 --> 00:16:49,850 this. You want to have some fake Objective-C object somewhere in memory 163 00:16:49,850 --> 00:16:55,079 that you're referencing. So again, we have an we can access an arbitrary absolute 164 00:16:55,079 --> 00:17:00,150 address. We want some fake Objective-C object there. Every Objective-C object has 165 00:17:00,150 --> 00:17:06,509 a pointer to its class. And then the class has something called a method table, which 166 00:17:06,509 --> 00:17:10,940 basically has function pointers to these methods. Right. And so if we fake this 167 00:17:10,940 --> 00:17:17,309 entire data structure thing, the fake object and the fake class, then as soon as 168 00:17:17,309 --> 00:17:22,379 the process calls some method on our fake thing, we get code execution. So we get 169 00:17:22,379 --> 00:17:28,459 control over the instruction pointer and then it's game over. So that's going to be 170 00:17:28,459 --> 00:17:37,770 our goal for this exploit. So here we have two different types of addresses: On the 171 00:17:37,770 --> 00:17:43,159 left side we have heap addresses or data, really. And on the right side, in this 172 00:17:43,159 --> 00:17:49,929 NSString-thing we need library addresses or code addresses, simply because on iOS 173 00:17:49,929 --> 00:17:57,200 you can't have writeable code regions. So we have to necessarily reuse existing 174 00:17:57,200 --> 00:18:00,919 code, do so to something like ROP also. So we need to know where libraries are 175 00:18:00,919 --> 00:18:07,290 mapped for this. And this is exactly the problem we are gonna face now because 176 00:18:07,290 --> 00:18:12,310 there is something called ASLR, Address Space Layout Randomization. And what it 177 00:18:12,310 --> 00:18:17,269 does is it will randomize this entire address space. So on the left side, you 178 00:18:17,269 --> 00:18:23,419 can see how a process looks like, how the virtual memory of a process looks like 179 00:18:23,419 --> 00:18:28,529 before ASLR. And there everything is always mapped at the same address. So if 180 00:18:28,529 --> 00:18:33,069 you start the same address twice on different phones, maybe even without ASLR 181 00:18:33,069 --> 00:18:37,200 the same library is at the same address, the heap is always at the same address 182 00:18:37,200 --> 00:18:41,559 stack. Everything is the same. And so this would be really simple to exploit now 183 00:18:41,559 --> 00:18:47,539 because, well, everything is the same. With ASLR everything is shifted and now 184 00:18:47,539 --> 00:18:53,000 all the addresses are randomized and we don't really know where anything is. And 185 00:18:53,000 --> 00:19:00,220 so that makes it harder to exploit this. So we need an ASLR bypass is what this 186 00:19:00,220 --> 00:19:07,309 means. We're gonna divide it into two parts. So the heap addresses we get them 187 00:19:07,309 --> 00:19:11,519 from in a different way than the library addresses. So let's see how we get heap 188 00:19:11,519 --> 00:19:18,100 addresses. It's really simple honestly, what you can do is heap spraying, which is 189 00:19:18,100 --> 00:19:24,749 an old technique. I think 15 years old maybe. And it does still work today. The 190 00:19:24,749 --> 00:19:29,789 idea is that you simply allocate lots of memory. So if you look at this code there 191 00:19:29,789 --> 00:19:35,069 put on the right, which you can use to test that, what it does is that it allocates 192 00:19:35,069 --> 00:19:40,999 256 megabytes of memory on the heap with malloc. And then afterwards there's one 193 00:19:40,999 --> 00:19:47,629 address or there's many addresses. But in this case, I'm using this hex110000000 194 00:19:47,629 --> 00:19:54,059 where you will find your data at. Okay. So just spraying 256 megabytes lets you put 195 00:19:54,059 --> 00:19:59,659 controlled data at a controlled address, which is enough for this first part of the 196 00:19:59,659 --> 00:20:05,330 exploit. The remaining question is how can you heap spray over a iMessage. That's a 197 00:20:05,330 --> 00:20:10,830 bit more complicated. But it is possible because NSKeyedUnarchiver is great and it 198 00:20:10,830 --> 00:20:18,260 lets you do all sorts of weird stuff which you can abuse for heap spraying. So, yeah. 199 00:20:18,260 --> 00:20:24,299 Blog posts will have more details. Okay. So we have these, the heap addresses. We 200 00:20:24,299 --> 00:20:32,340 have them. We need the library addresses. Let's go back to the virtual memory space. 201 00:20:32,340 --> 00:20:38,149 On iOS and also on macOS the libraries - so maybe in this case all three libraries, 202 00:20:38,149 --> 00:20:42,919 but in reality, it's like hundreds of system libraries - they are all prelinked 203 00:20:42,919 --> 00:20:48,849 into one gigantic binary blob, which is called a dyld_shared_cache. The idea is 204 00:20:48,849 --> 00:20:53,539 that this speeds up like loading times because all the interdependencies between 205 00:20:53,539 --> 00:20:59,270 libraries are resolved pretty much at compile time. But yeah, so we have this 206 00:20:59,270 --> 00:21:04,981 gigantic binary blob and it has everything we need. So it has all the code, it has 207 00:21:04,981 --> 00:21:10,769 all the ROP gadgets and it has all the Objective-C classes. So we have to know 208 00:21:10,769 --> 00:21:18,980 where this dyld_shared_cache is mapped. If you dig into that a bit or if you look at 209 00:21:18,980 --> 00:21:25,499 the documentation or the the binaries, you can find out that it is going to be mapped 210 00:21:25,499 --> 00:21:32,380 always between these two addresses. So between 0x180000000 and 0x280000000, which 211 00:21:32,380 --> 00:21:37,429 leaves only a 4 gigabyte region, so it's only being mapped in these 4 gigabytes. 212 00:21:37,429 --> 00:21:43,409 And then the randomization granularity is also 0x4000 because iOS uses large pages 213 00:21:43,409 --> 00:21:49,759 so it can only randomize with page granularity, and that page granularity is 214 00:21:49,759 --> 00:21:57,760 0x4000. But really what's most interesting is that on the same device, the 215 00:21:57,760 --> 00:22:03,570 dyld_shared_cache is only randomized once per boot. So if if you have two different 216 00:22:03,570 --> 00:22:08,270 processes on the same device, the shared cache is at the same virtual address. And 217 00:22:08,270 --> 00:22:12,259 if you have one process, then it crashes and you have another one. And so on, like 218 00:22:12,259 --> 00:22:17,590 the shared cache is always going to be at the same address. And that makes it really 219 00:22:17,590 --> 00:22:24,249 interesting. And also, it's one gigabyte in size. It's gigantic. So it's not too 220 00:22:24,249 --> 00:22:31,650 hard to find in this four gigabyte region. Right. So this is what our our task has 221 00:22:31,650 --> 00:22:37,340 boiled down to at this point. We have this address range, we have the shared cache. 222 00:22:37,340 --> 00:22:44,649 And all we need to know now is what is this offset? So let's make a thought 223 00:22:44,649 --> 00:22:51,039 experiment. Let's say we had an oracle which would tell us... which we could give 224 00:22:51,039 --> 00:22:55,729 an address. And it would tell us if this address is mapped in the remote process. 225 00:22:55,729 --> 00:23:03,480 OK, if we have this, it suddenly becomes really easy to solve this problem, because 226 00:23:03,480 --> 00:23:08,500 then all you have to do is you go in 1 gigabyte steps the the size of the shared 227 00:23:08,500 --> 00:23:16,250 cache between these two addresses and then at some point you find a valid address. So 228 00:23:16,250 --> 00:23:20,750 maybe here after 3 steps, you find a valid address, and then from there you just do a 229 00:23:20,750 --> 00:23:26,210 binary search. Right. Because you know that somewhere between the green and the 230 00:23:26,210 --> 00:23:31,100 second red arrow, the shared cache starts. So you can do a binary search and you find 231 00:23:31,100 --> 00:23:39,740 the the start address in logarithmic time in a few seconds, minutes, whatever. So 232 00:23:39,740 --> 00:23:43,650 obviously the question is what? How? Where would we get this oracle from? This seems 233 00:23:43,650 --> 00:23:51,399 kind of weird. So let's look at receipts, message receipts. So iMessage like many 234 00:23:51,399 --> 00:23:57,859 other messengers - I think pretty much all of them that I know - send receipts for 235 00:23:57,859 --> 00:24:04,779 different things. iMessage in particular has delivery receipts and read receipts. 236 00:24:04,779 --> 00:24:11,230 Delivery received means the device received the message, read receipt means 237 00:24:11,230 --> 00:24:15,929 the user actually looked - opened the app, looked at the message. You can turn off 238 00:24:15,929 --> 00:24:21,469 read receipts, but as far as I know, you cannot turn off delivery receipts. And so 239 00:24:21,469 --> 00:24:27,769 here on the left you see a screenshot. Three different messages were sent and 240 00:24:27,769 --> 00:24:31,810 they have three different states. The first message was marked as read, which 241 00:24:31,810 --> 00:24:37,020 means it got a delivery receipt and a read receipt. The second message is marked as 242 00:24:37,020 --> 00:24:41,899 delivered. So it only got a delivery receipt and the third message doesn't have 243 00:24:41,899 --> 00:24:51,049 anything. So it hasn't received any receipt. OK. So why is it useful? Here on 244 00:24:51,049 --> 00:24:58,000 the left is some pseudocode of imagent's handling of how it handles messages and 245 00:24:58,000 --> 00:25:04,369 when it sends these receipts. And so you can see that it first parses the plist 246 00:25:04,369 --> 00:25:10,319 that's coming in and it's then doing this nsUnarchive at some later time. And this 247 00:25:10,319 --> 00:25:14,769 is this is exactly why all but would trigger during nsUnarchive. And only then 248 00:25:14,769 --> 00:25:22,970 does it send a delivery receipt. Right. So what that means is if during our during 249 00:25:22,970 --> 00:25:27,580 our nsUnarchive, if we can trigger the bug and cause a crash, then we have somewhat 250 00:25:27,580 --> 00:25:33,750 of a one bit sidechannel. Right. Because if we cause a crash, then we won't see a 251 00:25:33,750 --> 00:25:38,690 delivery receipt. And if we don't cause a crash, then we see a delivery receipt. So 252 00:25:38,690 --> 00:25:47,670 it's a one bit of information. And this is going to be our oracle. All right. So 253 00:25:47,670 --> 00:25:53,080 ideally, you have a vulnerability that gives you this perfect oracle of is an 254 00:25:53,080 --> 00:25:59,249 address mapped or not? So crash, if it is not mapped, don't crash if it mapped. In 255 00:25:59,249 --> 00:26:04,110 reality, you probably will not get this perfect oracle from your bug. On the left 256 00:26:04,110 --> 00:26:10,040 side, you see the real Oracle function for this vulnerability, which is, well it has 257 00:26:10,040 --> 00:26:18,159 to be mapped. OK. But then it's also using the value that it's reading. And so it 258 00:26:18,159 --> 00:26:24,039 will only not crash if the value is either 0 or if it has the most significant bit 259 00:26:24,039 --> 00:26:29,340 set, that is some like pointer taking stuff or if it's a real legitimate pointer 260 00:26:29,340 --> 00:26:34,899 to an Objective-C object. So this Oracle function is a bit more complex, but the 261 00:26:34,899 --> 00:26:41,059 similar idea still works. So you can still do something like a binary search, and 262 00:26:41,059 --> 00:26:48,439 then infer the shared cache start address in logarithmic time. Right. And so it only 263 00:26:48,439 --> 00:26:54,049 takes maybe five minutes or so to do this. But for this for this part, again, I have 264 00:26:54,049 --> 00:27:01,519 to refer to the blog post which will cover how this works. OK. So this is the summary 265 00:27:01,519 --> 00:27:07,710 of the remote ASLR bypass. Two phases, there's linear scan where it's just 266 00:27:07,710 --> 00:27:13,289 scanning, sending these payloads and checking if it gets the receipt back, and 267 00:27:13,289 --> 00:27:17,459 the first time it gets a receipt back, it knows. OK. This address is valid. I now 268 00:27:17,459 --> 00:27:22,090 found an address that is within the shared cache. And at that point it starts this 269 00:27:22,090 --> 00:27:28,429 searching phase, which in logarithmic time figures out the exact, precise starting 270 00:27:28,429 --> 00:27:36,940 address. So there's a few common questions about this that I want to briefly go into. 271 00:27:36,940 --> 00:27:42,169 The first maybe obvious question is, can you really just crash this agent like 20 272 00:27:42,169 --> 00:27:49,799 plus times? And the answer is yes. There's no indicator or anything that the user 273 00:27:49,799 --> 00:27:55,759 would would see that this demon crashes. The only thing you can do is you can go 274 00:27:55,759 --> 00:27:59,899 into like settings, privacy, something something, crash log something, and then 275 00:27:59,899 --> 00:28:07,129 you can see these crash logs. Second question is you can I think by default, 276 00:28:07,129 --> 00:28:11,820 the iPhone is configured to send crash logs to the vendor, to Apple. So isn't 277 00:28:11,820 --> 00:28:17,499 that a problem? So I think I looked at this briefly. What I stumbled across was 278 00:28:17,499 --> 00:28:25,499 that it seems that iOS collects at most 25 crash logs per service. This is not 279 00:28:25,499 --> 00:28:30,659 designed to be like a security feature. Right. So this makes sense. But what that 280 00:28:30,659 --> 00:28:37,610 means is that an attacker can use some kind of, well, resource exhaustion bug to 281 00:28:37,610 --> 00:28:44,599 crash this daemon maybe 25 times first, and then only start to exploit and then no 282 00:28:44,599 --> 00:28:52,129 trace of the exploit will be sent over. Third question is whether this can be 283 00:28:52,129 --> 00:28:56,879 fixed by simply sending the delivery receipt very early on. I think this is... 284 00:28:56,879 --> 00:29:01,909 this was my first suggestion to Apple to just send this delivery receipt right at 285 00:29:01,909 --> 00:29:06,659 the start. Eventually I figured out it doesn't really work because you can still 286 00:29:06,659 --> 00:29:12,459 make some kind of timing side channel, because when when a demon crashes multiple 287 00:29:12,459 --> 00:29:17,789 times, it's subject to some penalty and it will only restart like a few seconds or 288 00:29:17,789 --> 00:29:24,369 even minutes later. So from the timing of getting a delivery receipt, you can then 289 00:29:24,369 --> 00:29:30,269 still basically get this oracle. Right. So it doesn't really work by just sending it 290 00:29:30,269 --> 00:29:38,289 earlier. I'll go into some other ideas that might work later. Okay. So at this 291 00:29:38,289 --> 00:29:47,929 point I'm starting the demo. The demo is two parts. Let's see where it is. Right. 292 00:29:47,929 --> 00:29:54,059 So I have this iPhone here and you can with QuickTime... the screen is mirrored 293 00:29:54,059 --> 00:30:05,799 to the projector. So this iPhone is it's a 10S, so it's from last year. It's on 12.4, 294 00:30:05,799 --> 00:30:10,879 which is the last vulnerable version. So that's like half a year old at this point. 295 00:30:10,879 --> 00:30:23,199 And what else? So there is no existing chats open. Okay. And let's see. So I hope 296 00:30:23,199 --> 00:30:27,889 the Wi-Fi works. What you can see here is the way the exploit works that it's 297 00:30:27,889 --> 00:30:35,259 hooking with Frida into... Do we get delivery receipt? Uh, do we? Yeah. Okay, 298 00:30:35,259 --> 00:30:41,179 cool. It works. So, yeah, it's popping up these messages. The way the exploit works 299 00:30:41,179 --> 00:30:46,330 that it's hooking the messages app on macOS with Frida and then it's sending 300 00:30:46,330 --> 00:30:54,289 these specific marker messages like INJECT_ATI, and then the Frida hook 301 00:30:54,289 --> 00:30:58,259 replaces this message with like the current payload. Right. And now it's 302 00:30:58,259 --> 00:31:09,039 testing these addresses. It's not too slow I guess. Yeah. And it's popping up some 303 00:31:09,039 --> 00:31:13,110 nice messages. Okay. It already found. Okay. So this is already the end of the 304 00:31:13,110 --> 00:31:18,619 first stage. So that was quite fast. It found a valid address in this like first 305 00:31:18,619 --> 00:31:25,409 probing step and now it has 21,000 candidates for the shared cache base. I 306 00:31:25,409 --> 00:31:31,139 know it's doing this kind of binary search thing to half that in every step. Okay. 307 00:31:31,139 --> 00:31:38,580 Now it only has 10,000 left and so it's quite fast and quite efficient. Okay. 308 00:31:38,580 --> 00:31:49,869 While this runs, um, let's continue. So this is where we are. We can now create 309 00:31:49,869 --> 00:31:55,831 fake objects. We have all the addresses we need. It's like this 1170 is where we can 310 00:31:55,831 --> 00:32:02,379 place our stuff and then we will gain control over the program counter. And from 311 00:32:02,379 --> 00:32:07,009 there it's standard stuff, right? It's what you would do in all of these exploits 312 00:32:07,009 --> 00:32:11,820 you pivot maybe to the stack, you do return oriented programing and then you 313 00:32:11,820 --> 00:32:17,070 can run your code and you've succeeded. Now, at this point, there is another thing 314 00:32:17,070 --> 00:32:23,649 coming in. Pointer authentication is a new security feature that Apple designed and 315 00:32:23,649 --> 00:32:32,279 implemented first in the 10S, so this device from 2018. And the idea is that you 316 00:32:32,279 --> 00:32:37,190 can now - for this you need CPU support - the idea that you can now store a 317 00:32:37,190 --> 00:32:43,269 cryptographic signature in the top bits of a pointer. OK, so here on the very left 318 00:32:43,269 --> 00:32:47,879 side, you have a raw pointer. So the top bits are zero because the way the address 319 00:32:47,879 --> 00:32:57,330 space works. Now there's a set of instructions that sign a pointer and they 320 00:32:57,330 --> 00:33:02,299 will maybe take a context on it, but they use some key that's not in memory - that's 321 00:33:02,299 --> 00:33:07,769 in a register, compute a signature of this pointer and store the signature in the top 322 00:33:07,769 --> 00:33:12,319 bits. And that's what you see on the right side. The green things. That's the 323 00:33:12,319 --> 00:33:20,499 signature. And now before using this pointer, the code will now authenticate by 324 00:33:20,499 --> 00:33:24,999 running another instruction. And this instruction, if the verification fails, it 325 00:33:24,999 --> 00:33:28,899 will basically clobber this pointer, make it invalid. And then the following 326 00:33:28,899 --> 00:33:34,360 instructions will just crash. Right. So here this is the function called the BL, 327 00:33:34,360 --> 00:33:38,879 branch and link instruction. This is doing a function call to a function pointer. But 328 00:33:38,879 --> 00:33:43,259 first it's authenticating this pointer. And if this authentication step fails, 329 00:33:43,259 --> 00:33:49,820 then the process will crash right there. What this means for an attacker is that 330 00:33:49,820 --> 00:33:55,509 more or less, ROP is dead, because ROP involves faking a bunch of function 331 00:33:55,509 --> 00:33:59,839 point... or like, well, code pointers really, that point in the middle of 332 00:33:59,839 --> 00:34:05,210 existing code. So this is no longer possible because an attacker cannot 333 00:34:05,210 --> 00:34:13,109 generate these signatures. So this is where our exploit breaks, right, the red 334 00:34:13,109 --> 00:34:20,240 thing. Well, we have a fake objective C class with our own function pointer. This 335 00:34:20,240 --> 00:34:25,550 does no longer work because we cannot compute these signatures. So what do we 336 00:34:25,550 --> 00:34:32,510 do? One thing that's still possible and it's even documented in the documentation 337 00:34:32,510 --> 00:34:37,870 is that this class pointer in the object - what's also called the ISA pointer - 338 00:34:37,870 --> 00:34:44,970 it's not protected by PAC in any way. Which means we can fake instances of 339 00:34:44,970 --> 00:34:51,510 legitimate existing classes. Right. So in this case here we can have a fake object 340 00:34:51,510 --> 00:34:58,770 that points to a real class that has real, legitimately signed method pointers. So 341 00:34:58,770 --> 00:35:05,640 this tool works. And with this, we can now get existing methods called, out of place 342 00:35:05,640 --> 00:35:10,070 and kind of manipulate the control flow. And these existing methods are basically 343 00:35:10,070 --> 00:35:20,120 now gadgets. So if you want to think about it that way. So what can we do with this? 344 00:35:20,120 --> 00:35:24,860 One very interesting method we can get called is dealloc, the destructor. So I 345 00:35:24,860 --> 00:35:30,110 think in quite a few, maybe most of the Objective-C exploitation scenarios, you 346 00:35:30,110 --> 00:35:36,220 can probably get a dealloc method called. Now what you do is you just enumerate all 347 00:35:36,220 --> 00:35:41,390 the destructors in the shared cache. There's tons of them, I think 50,000, and 348 00:35:41,390 --> 00:35:46,610 you can get any of those called. And then one of them or a few of them are really 349 00:35:46,610 --> 00:35:52,500 interesting because they call this invoke method, which is part of the NSInvocation 350 00:35:52,500 --> 00:35:59,200 object, or class. And an NCInvocation is basically a bound function. So it has a 351 00:35:59,200 --> 00:36:05,240 target object, the method to be called and all the arguments. And as soon as you call 352 00:36:05,240 --> 00:36:09,660 invoke on this NCInvocation, it does this method call with fully control arguments. 353 00:36:09,660 --> 00:36:15,310 Right. So what that means is with this destructor, we can now make a fake object 354 00:36:15,310 --> 00:36:20,840 with a fake NSInvocation that has any method call we would like to perform, and 355 00:36:20,840 --> 00:36:28,060 then it's going to do that because it's running this invoke here. Again, you see 356 00:36:28,060 --> 00:36:33,510 this shield here, which I put in place for things that Apple has hardened since we 357 00:36:33,510 --> 00:36:39,210 sent them the exploit. So what they did so far is they hardened NSInvocation and it's 358 00:36:39,210 --> 00:36:46,730 now no longer easily possible to abuse it in this way. But yeah. So for us, we can 359 00:36:46,730 --> 00:36:52,910 now run arbitrary Objective-C methods with controlled arguments. What about 360 00:36:52,910 --> 00:36:58,860 sandboxing? If you do some more reverse engineering and figure out what services 361 00:36:58,860 --> 00:37:03,970 play into iMessage, this is what you end up with. On the right side. So you have a 362 00:37:03,970 --> 00:37:08,750 number of services. Most of them are sandboxed. If it has the red border, it 363 00:37:08,750 --> 00:37:15,320 means there's a sandbox. Interestingly, Springboard also does some NSUnarchiver 364 00:37:15,320 --> 00:37:22,510 stuff. So it's decoding the BP key. So it could also trigger our vulnerability and 365 00:37:22,510 --> 00:37:26,520 Springboard is not sandboxed. So it's the main UI process. It's basically what's 366 00:37:26,520 --> 00:37:34,900 handling showing the the welcome screen. And so on. And so what that means is, 367 00:37:34,900 --> 00:37:38,690 well, we can just target Springboard and then we get code execution outside of the 368 00:37:38,690 --> 00:37:43,740 sandbox so we don't actually need to worry too much about the sandbox. As of iOS 13, 369 00:37:43,740 --> 00:37:51,310 this is fixed and this key is now decoded in the sandbox. Cool, so we can execute 370 00:37:51,310 --> 00:37:56,370 Objective-C methods outside of the sandbox. We can with that access user 371 00:37:56,370 --> 00:38:00,980 data, activate camera, microphone, etc. This is all possible through Objective-C 372 00:38:00,980 --> 00:38:06,250 quite easily. But of course we don't care about that. What we want is a calculator 373 00:38:06,250 --> 00:38:10,960 and this is also quite easy, with one Objective-C call - UIApplication 374 00:38:10,960 --> 00:38:17,180 launchApplication blah blah blah. And so let's see if this works. Go back to the 375 00:38:17,180 --> 00:38:26,260 demo. So where are we at? So the, uh, the ASLR bypass ran through. You can nicely 376 00:38:26,260 --> 00:38:30,680 see that it roughly halved the candidates in every round, or with every message 377 00:38:30,680 --> 00:38:35,900 it had to send. It ended up with just one message. Yeah, well with just one 378 00:38:35,900 --> 00:38:40,920 candidate at the end. And that is the shared cache base in this case 379 00:38:40,920 --> 00:38:50,900 0x18a608000. Now it's preparing the heap spray. This is all kind of hacked 380 00:38:50,900 --> 00:38:59,160 together. I think if you wanted to do this properly, for one, you can send the whole 381 00:38:59,160 --> 00:39:06,680 heap spray in one message. I'm just lazy. It's also probably way too big. Another 382 00:39:06,680 --> 00:39:11,760 thing is, I think you would probably not target springboard in reality just because 383 00:39:11,760 --> 00:39:15,450 spring board is very sensitive. So if you crash, did you get this re-spring and the 384 00:39:15,450 --> 00:39:20,360 UI restarts. So I think in reality you would probably target IM agent and then 385 00:39:20,360 --> 00:39:26,250 chain the sandbox escape. Because while this bug would also get you out of the 386 00:39:26,250 --> 00:39:32,390 sandbox. So looks should be doable. Okay. So I think the last message arrived. It's 387 00:39:32,390 --> 00:39:35,850 freezing here for a couple of seconds. I don't actually know why I never bothered, 388 00:39:35,850 --> 00:39:44,760 but it does work. *Applause* 389 00:39:44,760 --> 00:39:52,460 Thank you. Yeah. So that was a demo. It's it's kind of naturally reliable, this 390 00:39:52,460 --> 00:39:59,270 exploit, because there is not much of heap manipulation involved except this one 391 00:39:59,270 --> 00:40:09,490 heaps spray, which is controllable. Okay. Um, so what's left? I think one more thing 392 00:40:09,490 --> 00:40:14,740 you can do is you can attack the kernel if you want that. You have to deal with two 393 00:40:14,740 --> 00:40:19,970 problems here. One is code signing. You cannot execute unsigned code on iOS. And 394 00:40:19,970 --> 00:40:24,960 then the standard workaround for that is you abuse JIT pages in safari. But we are 395 00:40:24,960 --> 00:40:29,770 not in safari or we are not in web content, so we don't have JIT pages. What 396 00:40:29,770 --> 00:40:36,130 I did here is I basically pivoted into JavaScript core, which is the the JS 397 00:40:36,130 --> 00:40:42,300 library. You can use it from from any app also. And then I'm just bridging syscalls 398 00:40:42,300 --> 00:40:48,120 into JavaScript and then implementing the kernel exploit in JavaScript. This does 399 00:40:48,120 --> 00:40:53,170 not require any more vulnerabilities. So you do not need a JavaScript core bug to 400 00:40:53,170 --> 00:40:58,870 do this. And the idea is very similar to pwn.js. Maybe some of you know about that. 401 00:40:58,870 --> 00:41:03,300 It's a library. I think initially developed for Edge because they did 402 00:41:03,300 --> 00:41:10,580 something similar was like JIT page hardnings. So what I decided to do is take 403 00:41:10,580 --> 00:41:18,750 SockPuppet from Ned or CVE-2019-8605, which works on this version, it works on 404 00:41:18,750 --> 00:41:26,870 12.4. This is the trigger for it. And I only ported the trigger. I didn't bother 405 00:41:26,870 --> 00:41:31,100 re -implementing the entire exploit. So yeah, this is the trigger. It will cause a 406 00:41:31,100 --> 00:41:36,560 kernel panic. It's quite short. Which is nice. So if you want to run this from 407 00:41:36,560 --> 00:41:41,750 JavaScript, really, there's only three things you care about, right? So the first 408 00:41:41,750 --> 00:41:48,020 one is you need the syscalls. So highlighted here, there is like four or so 409 00:41:48,020 --> 00:41:52,360 different syscalls here. Not a lot. And you just have to be able to call them from 410 00:41:52,360 --> 00:41:58,360 JavaScript. The other thing is you need constants, right? So I have AF_INET6, 411 00:41:58,360 --> 00:42:01,730 SOCK_STREAM. These are all integer constants. So this is really easy, right? 412 00:42:01,730 --> 00:42:07,020 You just need to look up what these values end up being. And then the last thing is 413 00:42:07,020 --> 00:42:13,520 you need some data structures. So in this case, I need this so_np_extension thing. 414 00:42:13,520 --> 00:42:21,500 It needs some integer value to pass pointers to and so on. Yeah. And then this 415 00:42:21,500 --> 00:42:28,370 is kind of the the magic that happens. You take sock_puppet.c extract the syscalls 416 00:42:28,370 --> 00:42:34,161 etc. There is one Objective C message you can call which is very convenient, which 417 00:42:34,161 --> 00:42:42,030 gives you a dlsym. What this lets you do is, it lets you get native C function 418 00:42:42,030 --> 00:42:46,680 pointers that are signed, right. Because so far we can only call Objective C 419 00:42:46,680 --> 00:42:51,270 methods, but we need to be able to call syscalls or at least the C wrapper 420 00:42:51,270 --> 00:42:59,720 functions. So with this dlsym method thing we can get signed pointers to C functions. 421 00:42:59,720 --> 00:43:03,190 Then we need to be able to pivot into JavaScript code, which is also really easy 422 00:43:03,190 --> 00:43:08,830 with one method call, the JSContext evaluateScript. We need to mess around 423 00:43:08,830 --> 00:43:12,840 with memory a bit like corrupt some objects from outside, corrupt some area 424 00:43:12,840 --> 00:43:18,810 buffers in javascript, get read, write. Kind of standard browser exploitation 425 00:43:18,810 --> 00:43:23,220 tricks I guess. But yeah. So if you do this what you end up with is 426 00:43:23,220 --> 00:43:30,920 sock_puppet.js. It looks very similar. You can see a bit of my javascript API that 427 00:43:30,920 --> 00:43:36,920 lets you allocate memory buffers. I read and write memory, have some integer 428 00:43:36,920 --> 00:43:42,050 constants and yeah, apart from that, it doesn't really look much different from 429 00:43:42,050 --> 00:43:49,370 the initial trigger. And so this can now be served over, well, staged onto the 430 00:43:49,370 --> 00:43:55,350 iMessage exploit building on top of this object a C method called primitive. And I 431 00:43:55,350 --> 00:43:59,740 guess at least in theory I didn't fully implement it. This should be able to just 432 00:43:59,740 --> 00:44:08,390 run a kernel exploit and fully compromise the device without any interaction in 433 00:44:08,390 --> 00:44:13,990 probably less than 10 minutes. Okay, so this was the first part. How does how does 434 00:44:13,990 --> 00:44:19,260 this exploit work. What I have now is a number of suggestions how to make this 435 00:44:19,260 --> 00:44:25,910 harder and how to improve things. So one of the first things that is really 436 00:44:25,910 --> 00:44:30,420 critical for this exploit is the ASLR bypass, which relies on a couple of 437 00:44:30,420 --> 00:44:36,620 things. And I think a lot of this ALSR bypass also works on other platforms. So 438 00:44:36,620 --> 00:44:41,960 Android has a very similar problem with like mappings being at the same address 439 00:44:41,960 --> 00:44:47,350 across processes. And other messengers have these like receipts and so on. So I 440 00:44:47,350 --> 00:44:51,640 think a lot of this applies not just to Apple but to Android and to other 441 00:44:51,640 --> 00:44:57,490 messengers. But okay. What is the first point? So weak ALSR, this is basically the 442 00:44:57,490 --> 00:45:03,530 heap spraying, which is just too easy. This shouldn't be so easy. In terms of 443 00:45:03,530 --> 00:45:07,890 theoretical ASLR, you can see it maybe sketched here on the right. In theory, 444 00:45:07,890 --> 00:45:12,660 ASLR could be much stronger, much more randomized. In reality, it's just like the 445 00:45:12,660 --> 00:45:18,800 small red bar. So it really it should just have much more entropy to make heap 446 00:45:18,800 --> 00:45:30,180 springing not viable anymore. The next problem with ASLR is per-boot stuff. At 447 00:45:30,180 --> 00:45:33,240 the bottom you can see it, right? So you have three different processes, the shared 448 00:45:33,240 --> 00:45:37,330 cache is always at the same address, similar problems on other platforms, I 449 00:45:37,330 --> 00:45:44,270 mentioned that. This is probably hard to fix because by this point a lot of, quite 450 00:45:44,270 --> 00:45:50,040 a lot relies on this. And it would be a big performance hit to change this. But 451 00:45:50,040 --> 00:45:55,960 maybe some clever engineers can figure out how to do it better. The third part here 452 00:45:55,960 --> 00:46:01,280 is the delivery receipts, which, interestingly, they can give this side 453 00:46:01,280 --> 00:46:06,370 channel, this one bit information side channel and this can be enough to break 454 00:46:06,370 --> 00:46:11,250 ASLR. And as I've mentioned before, I think a lot of other messengers have this 455 00:46:11,250 --> 00:46:21,270 same problem. What might work is to either, well, remove these receipts. Sure. 456 00:46:21,270 --> 00:46:25,270 Or maybe send them from a different process so you can't do this timing thing 457 00:46:25,270 --> 00:46:29,520 or even from the server. I think if you send them, if the server already sends the 458 00:46:29,520 --> 00:46:37,760 delivery receipt, it's a bit of cheating. But at least this attack doesn't work. 459 00:46:37,760 --> 00:46:43,020 Sandboxing, another thing, it's probably obvious, right? So the everything that's 460 00:46:43,020 --> 00:46:50,100 on zero click attack surface should be sandboxed as much as possible. Of course, 461 00:46:50,100 --> 00:46:55,770 to, you know, to require the attacker to do another full exploit after getting code 462 00:46:55,770 --> 00:47:02,270 execution. But Sandboxing can also complicate information leaks. So not only 463 00:47:02,270 --> 00:47:07,660 had this other iMessage bug CVE-2019-8646, there's a blog post about 464 00:47:07,660 --> 00:47:15,160 this one. It basically lets you. She was able to send to cause a Springboard to 465 00:47:15,160 --> 00:47:20,480 send HTTP requests to some server and those would contain pictures, data, 466 00:47:20,480 --> 00:47:27,320 whatever. If Springboard would've been sandbox to not allow network activities, 467 00:47:27,320 --> 00:47:31,190 this would have been much harder. So sandboxing is not necessarily just about 468 00:47:31,190 --> 00:47:36,550 this second breakout. What I do want to say about sandboxing, ithat it shouldn't 469 00:47:36,550 --> 00:47:41,510 be relied on. So I think that this remote attack surface is pretty hard. And it's 470 00:47:41,510 --> 00:47:46,480 not unlikely that it's actually harder than the sandboxing attack surface. And 471 00:47:46,480 --> 00:47:50,770 also on top of that, this bug, the NSKeyedUnarchiver bug, it would also get 472 00:47:50,770 --> 00:47:56,460 you out of the sandbox because the same API is used locally for IPC. So there's 473 00:47:56,460 --> 00:48:03,160 that. Yeah. This would be nice if the zero click attack surface code would be open 474 00:48:03,160 --> 00:48:08,530 source. Would have been nice for us. It would have been easier to audit. Maybe 475 00:48:08,530 --> 00:48:17,160 someday. Another feature that I would like to see or another theme is reduced zero 476 00:48:17,160 --> 00:48:21,780 attack surface. Make it one click at least one click attack surface. Right. So before 477 00:48:21,780 --> 00:48:28,070 and here you could see that an unknown sender can send any messages. It would be 478 00:48:28,070 --> 00:48:32,300 nice if there would be some pop up that's like, well, do you actually want to accept 479 00:48:32,300 --> 00:48:37,390 messages? Threema lets you block unknown senders. I think that's a cool feature. So 480 00:48:37,390 --> 00:48:44,791 yeah, there's more work to be done here. Also, this restarting service problem, I 481 00:48:44,791 --> 00:48:51,740 think it could get bigger even. So, here we have pretty much unlimited tries for 482 00:48:51,740 --> 00:48:56,840 the ASLR bypass. It's probably going to become even more relevant with memory 483 00:48:56,840 --> 00:49:03,680 tagging, which we can also be defeated if you have many tries. So yeah, I guess if 484 00:49:03,680 --> 00:49:08,330 there's some process or some critical demon crashes ten times, maybe not restart 485 00:49:08,330 --> 00:49:15,280 it. I don't know. It's gonna need some more thinking, right? You don't want to 486 00:49:15,280 --> 00:49:20,660 denial-of-service the user by just not restarting this demon that crashed for 487 00:49:20,660 --> 00:49:26,080 some unrelated reason. But yeah, this would be a very good idea to have some 488 00:49:26,080 --> 00:49:33,210 kind of limit here. Okay. Conclusion. So yeah, zero click exploit, they are thing. 489 00:49:33,210 --> 00:49:39,310 They do exist. It is possible to exploit single memory corruption bugs on this 490 00:49:39,310 --> 00:49:45,490 surface with, you know, without separate info leaks. Despite all the mitigations we 491 00:49:45,490 --> 00:49:51,240 have. However, I do think by turning the right knobs, this could be made much 492 00:49:51,240 --> 00:49:57,180 harder. So I gave some suggestions here. And yeah, we need more atack surface 493 00:49:57,180 --> 00:50:01,650 reduction, especially on the zero click surface. But I think there is progress 494 00:50:01,650 --> 00:50:06,500 being made. And with that thanks for your attention. And I think we have time for 495 00:50:06,500 --> 00:50:08,910 questions. Thank you. 496 00:50:08,910 --> 00:50:16,270 *applause* 497 00:50:16,270 --> 00:50:21,080 Herald: We do have time for questions. And if you're in the room, you should line up 498 00:50:21,080 --> 00:50:25,790 at the microphones and then we might also have questions from the Internet. One 499 00:50:25,790 --> 00:50:32,960 quick reminder is that all fun things that what they work with explicit consent that 500 00:50:32,960 --> 00:50:38,890 includes photos. So the photo policy of the CCC is that if you take a photo, you 501 00:50:38,890 --> 00:50:43,490 need to have explicit consent by the people in the frame. So remember, don't do 502 00:50:43,490 --> 00:50:47,880 any long shots into the crowd because you want to have the consent of everybody 503 00:50:47,880 --> 00:50:53,300 there. Good. We have the first question from the Internet. 504 00:50:53,300 --> 00:50:57,110 Question: The Internet wants to know. Did Apple give you some kind of a reward? And 505 00:50:57,110 --> 00:51:01,750 was it in your iPhone? Answer: No, we did not get any kind of 506 00:51:01,750 --> 00:51:11,520 reward. But we also didn't ask for it. No, I didn't get a new iPhone, but I'm still 507 00:51:11,520 --> 00:51:20,590 using mine. Which is it? Yeah. I mean, this is a Xs, right? Current hardware 508 00:51:20,590 --> 00:51:28,920 models can be defeated with this, if that is the question. 509 00:51:28,920 --> 00:51:31,870 Herald: Good. We have a question for microphone number 3. 510 00:51:31,870 --> 00:51:41,480 Q: Hello. Uh, just a question. I did not truly understand how the fix with the 511 00:51:41,480 --> 00:51:47,620 server or having another process, uh, sending that there every message will fix 512 00:51:47,620 --> 00:51:53,800 the problem because if it does work, if you are in the right addresses, the thing 513 00:51:53,800 --> 00:52:02,100 just will work. Make the server or the process, send the delivery message and if 514 00:52:02,100 --> 00:52:10,820 it crashes, it doesn't do anything so... A: So the idea would be in this case, I'm 515 00:52:10,820 --> 00:52:15,020 like sending this one method that would crash and then either I get a delivery 516 00:52:15,020 --> 00:52:20,030 received or I don't. If the server already sends the delivery receipt before it 517 00:52:20,030 --> 00:52:26,260 actually gives the message to the client or to the receiver, then I would always 518 00:52:26,260 --> 00:52:30,310 see a delivery receipt and I wouldn't be able to figure out if my message caused 519 00:52:30,310 --> 00:52:36,150 the crash or not. So that's the idea behind maybe sending it on the server 520 00:52:36,150 --> 00:52:38,890 side, if that makes sense. Follow-up question: Yeah. But in this 521 00:52:38,890 --> 00:52:47,180 case, if legit people send a message and it doesn't reach the people because... 522 00:52:47,180 --> 00:52:52,660 A: Yeah. Yeah. It's a hack. Right. So it's not perfect. I mean the server could only 523 00:52:52,660 --> 00:52:58,960 send to find this delivery receipt once it like send it out over TCP and maybe got a 524 00:52:58,960 --> 00:53:05,900 TCP ACK or whatever happens in the kernel. But it's a hack in any case. Yeah. Like 525 00:53:05,900 --> 00:53:08,130 it's a tradeoff. Herald: We have a question for microphone 526 00:53:08,130 --> 00:53:14,210 number two. Q: Hello. Okay. Thanks for the talk. Two 527 00:53:14,210 --> 00:53:20,530 questions. First: Is OS X also a potential candidate for this bug. And 528 00:53:20,530 --> 00:53:26,270 second: Can you distinguish multiple devices with your address based 529 00:53:26,270 --> 00:53:31,440 randomization detection? A: Mm hmm. So yes: OS X or MacOS is 530 00:53:31,440 --> 00:53:36,940 affected just the same. I think this specific exploit wouldn't directly work 531 00:53:36,940 --> 00:53:40,290 because address space looks a bit different, but I think you could make it 532 00:53:40,290 --> 00:53:45,280 work and it's affected. In terms of multiple devices, so I haven't played 533 00:53:45,280 --> 00:53:51,270 around with that. I could imagine that it is possible to somehow figure out that 534 00:53:51,270 --> 00:53:56,920 there are multiple devices or that you know which device just crashed. But I 535 00:53:56,920 --> 00:54:01,010 haven't investigated. That's the answer. Follow-up: Thanks. 536 00:54:01,010 --> 00:54:03,770 Herald: We still have time for more questions. There was a question from 537 00:54:03,770 --> 00:54:08,490 microphone number 1. Q: Hi. Thanks for the talk. Quick 538 00:54:08,490 --> 00:54:15,520 question. You said that exploitation could be made without having any notification. 539 00:54:15,520 --> 00:54:21,040 How would that be made? A: Yeah, I briefly looked into how it 540 00:54:21,040 --> 00:54:29,120 could work. Well. So for one, you can take out parts of the message so that it fails 541 00:54:29,120 --> 00:54:34,480 parsing later on in the processing and then it will just be like thrown away 542 00:54:34,480 --> 00:54:39,490 because it says, well, this is garbage. The other thing is, of course, once you 543 00:54:39,490 --> 00:54:45,160 get with the like very last message where you get code execution, you cannot prevent 544 00:54:45,160 --> 00:54:48,620 it from showing a message like a notification, because that happens 545 00:54:48,620 --> 00:54:52,720 afterwards. Follow-up Q: But until you get the code 546 00:54:52,720 --> 00:54:56,690 execution, you can't remove it. So you see the first message? 547 00:54:56,690 --> 00:55:01,140 A: So but you can do the other. The other thing, like make it make the message look 548 00:55:01,140 --> 00:55:05,690 bad - bad enough that like later parsing stages will throw them away. 549 00:55:05,690 --> 00:55:08,510 Follow-up: Thanks. Herald: Good. We have a couple of more 550 00:55:08,510 --> 00:55:11,130 questions. Remember, if you don't feel comfortable lining up behind the 551 00:55:11,130 --> 00:55:15,180 microphones, you can ask through the signal angel through the Internet. 552 00:55:15,180 --> 00:55:19,720 Microphone number 4, please. Q: Yes. Hi. Hi Samuel. Um, I was curious 553 00:55:19,720 --> 00:55:24,340 you have some suggestions about reducing the attack surface. Are there any 554 00:55:24,340 --> 00:55:28,400 suggestions that you'd make to save, like Apple or Google? You know, in terms of 555 00:55:28,400 --> 00:55:31,830 what they can see. You mentioned logging a little bit earlier. 556 00:55:31,830 --> 00:55:39,590 A: Yeah. So I sent pretty much this list with the exploit I sent to Apple. And I 557 00:55:39,590 --> 00:55:47,280 think the blog post will have a bit more. But yeah, I told them the same thing. 558 00:55:47,280 --> 00:55:50,190 Yeah, if that's your question, did I get it right? 559 00:55:50,190 --> 00:55:53,770 Follow-up Q: Yes. I mean, maybe I misunderstood a little bit, but I suppose 560 00:55:53,770 --> 00:55:57,400 that some of these reductions in the attack surface seem to be in terms of like what's 561 00:55:57,400 --> 00:56:01,710 happening on the device. Yeah. Whereas I'm wondering in terms of monitoring. So being 562 00:56:01,710 --> 00:56:03,560 able to catch something like this in progress. 563 00:56:03,560 --> 00:56:07,600 A: Right. Right. So this is gonna be really hard because of end-to-end 564 00:56:07,600 --> 00:56:13,210 encryption. So the server just sees like encrypted garbage and has no way of 565 00:56:13,210 --> 00:56:18,570 knowing is this an image? Is that the text? This is an exploit? So on the 566 00:56:18,570 --> 00:56:25,619 server, I don't think you can do much there. I think it's gonna have to be on 567 00:56:25,619 --> 00:56:29,050 the device. Herald: We have a question from the 568 00:56:29,050 --> 00:56:33,500 Internet. Q: How do you approach a attack surface 569 00:56:33,500 --> 00:56:41,430 mapping? A: Um, well, reverse engineering, playing 570 00:56:41,430 --> 00:56:47,760 around, looking at this message format. In this case, what was somewhat obvious what 571 00:56:47,760 --> 00:56:51,590 an attack surface was. Right. So figure out which key is off this message are 572 00:56:51,590 --> 00:56:57,770 being processed in some way. Make a note. Decide which one looks most complex. Go 573 00:56:57,770 --> 00:57:03,090 for that first. That's what we did. Herald: We have a question from microphone 574 00:57:03,090 --> 00:57:07,020 number 2, please. Q: Hi. How long did you and your colleague 575 00:57:07,020 --> 00:57:14,590 research to get the export running? A: So the the vulnerability finding thing 576 00:57:14,590 --> 00:57:21,510 was not only I think we spend maybe three months finding the exploit. So I had a 577 00:57:21,510 --> 00:57:26,710 rough idea how I wanted to how how I would approach this exploit. So I think at the 578 00:57:26,710 --> 00:57:33,990 end it took me maybe a week to finish it. But I had thought about doing that for 579 00:57:33,990 --> 00:57:38,790 like, while a looking while looking for vulnerabilities and those two to three 580 00:57:38,790 --> 00:57:42,190 months. Herad: We have another question from 581 00:57:42,190 --> 00:57:48,550 microphone number three. Q: Um, is there the, uh, threat that the 582 00:57:48,550 --> 00:57:54,500 attacked iPhone would itself turn into a tack up by the exploit? 583 00:57:54,500 --> 00:57:59,270 A: Sure. Yeah, you can do that. I mean, you have full control, right? So you have 584 00:57:59,270 --> 00:58:05,000 access to the contacts list and you can send out iMessages. The question is if 585 00:58:05,000 --> 00:58:09,260 it's necessary. Right. I mean, you can also send messages from you don't really 586 00:58:09,260 --> 00:58:15,860 need them, the iPhone to send the messages. But I think in theory: Yes, 587 00:58:15,860 --> 00:58:19,000 that's possible. Herald: Do we have more questions from the 588 00:58:19,000 --> 00:58:25,440 Internet? Q: Does the phone stay compromised after 589 00:58:25,440 --> 00:58:28,740 restart? A: So there is no persistence exploit 590 00:58:28,740 --> 00:58:34,410 here. No. You will need another exploit a littlelailo did a talk. I think just an 591 00:58:34,410 --> 00:58:40,130 hour ago about persistence. So you would need to change this with what, for 592 00:58:40,130 --> 00:58:45,040 example, to exploit that he showed. Herald: And if you have questions in the 593 00:58:45,040 --> 00:58:47,800 room, please line up behind the microphones. Do we have more questions 594 00:58:47,800 --> 00:58:55,150 from the Internet. Q: Yes. So you've achieved the most novel 595 00:58:55,150 --> 00:59:02,330 buck ever found to be fine in iOS. What's the next big thing you'll be looking at? 596 00:59:02,330 --> 00:59:06,480 A: Good question. I don't really know myself, but I'm going to stay probably 597 00:59:06,480 --> 00:59:12,520 around for zero click attack surface reduction for a bit more. 598 00:59:12,520 --> 00:59:16,100 Herald: Looks like we don't have any brave people asking questions in the room. Does 599 00:59:16,100 --> 00:59:21,080 the Internet have more courage? Q: How long does discovery and 600 00:59:21,080 --> 00:59:26,750 exploitation and development take and how much does the team work to improve the 601 00:59:26,750 --> 00:59:33,710 process and development time? A: Okay, so how much how long does this 602 00:59:33,710 --> 00:59:39,530 exploitation process work? That's the first question. Yes. Yeah. I mean, this is 603 00:59:39,530 --> 00:59:45,020 generally a hard thing to answer. Right. There's like years of hacking around and 604 00:59:45,020 --> 00:59:50,670 learning how to do this stuff, etc. that you have to take into account. But as I 605 00:59:50,670 --> 00:59:54,500 said, I had a rough idea how this exploit would look like. So then really 606 00:59:54,500 --> 01:00:00,600 implementing it was like one or two weeks. The initial part of reverse engineering 607 01:00:00,600 --> 01:00:04,811 iMessage reverse engineering this NSUnarchiver thing. I kind of I think this 608 01:00:04,811 --> 01:00:10,650 took forever. This took many months and it was also very necessary for exploit 609 01:00:10,650 --> 01:00:17,030 writing. Right. So a lot of the expert primitives I use, they also abuse the 610 01:00:17,030 --> 01:00:21,760 NSKeyUnarchiver thing. Herald: We have time for perhaps two quick 611 01:00:21,760 --> 01:00:27,480 questions. Mike number 4, please. Q: Super. Uh, I'm not super familiar with 612 01:00:27,480 --> 01:00:32,980 iOS virtual memory address space but you should two heap regions when you showed the 613 01:00:32,980 --> 01:00:37,360 picture of it. And I'm wondering why are there two heap regions? 614 01:00:37,360 --> 01:00:42,510 A: OK, because there is only a minor detail, but I think there is one region 615 01:00:42,510 --> 01:00:48,700 initially like below the shared cache and one state is full. It just makes another 616 01:00:48,700 --> 01:00:56,150 one above it. So it's really just like if the one gets used or gets gets used up, it 617 01:00:56,150 --> 01:00:59,340 makes another one. And that's going to be like above the shared cache. I think 618 01:00:59,340 --> 01:01:03,300 that's the picture you're referring to. Follow-up: Yeah, thank you. 619 01:01:03,300 --> 01:01:06,910 Heralds: And unfortunately, we are out of time. So the person that might have some 620 01:01:06,910 --> 01:01:10,690 number one, please come up to the stage afterwards and perhaps you can grab a talk. 621 01:01:10,690 --> 01:01:17,287 So please give a warm. I can't say this exactly. *applause* Thanks. 622 01:01:17,287 --> 01:01:22,797 *applause* 623 01:01:22,797 --> 01:01:26,942 *Postroll music* 624 01:01:26,942 --> 01:01:50,000 Subtitles created by c3subtitles.de in the year 2020. Join, and help us!