1 00:00:00,099 --> 00:00:16,000 *34c3 preroll music* Herald Angel: Today we have our speaker 2 00:00:16,000 --> 00:00:21,920 Filippo Valsorda. He is a crypto-engineer and he is specialized in Go. He is some 3 00:00:21,920 --> 00:00:29,030 kind of Go wizard so to say and used to work at CloudFlare. He actually shows now 4 00:00:29,030 --> 00:00:35,469 today in the talk how he made an attack to exploit a bug in the implementation of the 5 00:00:35,469 --> 00:00:41,640 elliptic curve P256 in Go, that's why he's a Go wizard. The reason is actually due to 6 00:00:41,640 --> 00:00:48,210 a misplaced bit on the assembler level, just due to the curves implementation. The 7 00:00:48,210 --> 00:00:53,769 result is that in certain cases you can retrieve the private key in the elliptic 8 00:00:53,769 --> 00:00:58,440 curve Diffie-Hellman encryption scheme. Please welcome Filippo Valsorda to his 9 00:00:58,440 --> 00:01:03,440 talk, give him a round of applause. Thank you very much. 10 00:01:03,440 --> 00:01:05,710 Filippo Valsorda: Thank you. *applause* 11 00:01:05,710 --> 00:01:11,390 Thanks. I love the term crypto-golfer. Tony came up with it and I just want business 12 00:01:11,390 --> 00:01:17,350 cards with that on it. Anyway, okay, I'm Filippo. As you heard I worked on Internet 13 00:01:17,350 --> 00:01:22,340 infrastructure, I work on Go, I work on cryptography. But this is a collaboration 14 00:01:22,340 --> 00:01:28,229 with Sean Devlin, you might know him as one of the authors of the Cryptopals or 15 00:01:28,229 --> 00:01:35,111 the matasano crypto challenges. A few months ago earlier this year a bug.. a 16 00:01:35,111 --> 00:01:46,359 CloudFlare engineer was scanning CT logs. CT logs are big logs of TLS certificates 17 00:01:46,359 --> 00:01:52,090 and he was checking the ECDSA signatures on these certificates and one of the 18 00:01:52,090 --> 00:01:58,509 signatures was not verifying. Which is weird, because CT logs check the 19 00:01:58,509 --> 00:02:04,130 certificates before adding them to the log. It turned out that the bug was in the 20 00:02:04,130 --> 00:02:09,250 code that CloudFlare was using to verify the certificates. And more specifically it 21 00:02:09,250 --> 00:02:17,690 was in the Go standard library. It was in the implementation of the NIST P256 curve, 22 00:02:17,690 --> 00:02:24,360 which is a popular, very hard to implement, elliptic curve that is used for example 23 00:02:24,360 --> 00:02:31,800 for ECDSA TLS certificates. This curve has an assembly implementation in the Go 24 00:02:31,800 --> 00:02:40,670 standard library, of course, to squeeze every bit of performance out of it, and 25 00:02:40,670 --> 00:02:47,420 it's specifically optimized for x86-64 architecture. So that's where the bug was. 26 00:02:47,420 --> 00:02:53,430 There was a carry propagation bug. It was reported upstream and everyone agreed that 27 00:02:53,430 --> 00:03:00,420 this was not obviously exploitable. But Adam Langley also said that it would 28 00:03:00,420 --> 00:03:08,240 be a cool paper though. And well I mean, how do you pass on that? So Sean and I met 29 00:03:08,240 --> 00:03:13,620 in Paris and spend a weekend and then some eating Thai food and staring at this 30 00:03:13,620 --> 00:03:20,440 assembly code to try to understand what is it doing. And one month later we have a 31 00:03:20,440 --> 00:03:30,630 CVE and two Go security releases. We found a way to go from this single carry bit bug 32 00:03:30,630 --> 00:03:36,290 to a full key recovery against protocols that use elliptic curve Diffie-Hellman 33 00:03:36,290 --> 00:03:42,520 within ephemeral static way. If this means nothing to you, it's okay, I will try to 34 00:03:42,520 --> 00:03:51,170 go over it. One of these protocols for example is JWT. Jozy, or however you want 35 00:03:51,170 --> 00:03:58,210 to call it - it has 15 different acronyms. And it's often implemented in Go, so this 36 00:03:58,210 --> 00:04:05,850 was exploitable against real-world services. So, let's start by looking at 37 00:04:05,850 --> 00:04:11,900 the code with the bug. Let's take it from the beginning. This is the short assembly 38 00:04:11,900 --> 00:04:19,760 function that does subtraction. When you do elliptic curve math, you usually work 39 00:04:19,760 --> 00:04:27,980 on a field, you work on math modulo some prime p. So if it was subtraction you do a 40 00:04:27,980 --> 00:04:35,680 minus b modulo p and this is what this assembly snippet does. It sets a to a 41 00:04:35,680 --> 00:04:44,031 minus b. Of course these are numbers way too big to fit into a single register. So 42 00:04:44,031 --> 00:04:49,600 how do you do math, when you can't fit into a single register? You do multi- 43 00:04:49,600 --> 00:04:55,730 precision math. And the thing is, you all know how to do multi-precision math, you 44 00:04:55,730 --> 00:05:01,360 learned that in elementary school. When you would write numbers in columns and you 45 00:05:01,360 --> 00:05:06,620 do math with register size of 10, because for every digit you would subtract two 46 00:05:06,620 --> 00:05:13,110 digits and carry the minus one if it went negative and then subtract with the carry 47 00:05:13,110 --> 00:05:17,500 and then carry the minus one. That's exactly what this is doing, but it's doing 48 00:05:17,500 --> 00:05:23,440 it instead with digits with 64-bit registers, because this is a 64-bit architecture 49 00:05:23,440 --> 00:05:27,680 . So we look at the first lines: the first lines is nothing else 50 00:05:27,680 --> 00:05:32,870 than subtract, subtract, subtract with carry. And then the carry is finally 51 00:05:32,870 --> 00:05:40,830 stored in that mul0 accumulator. But then what do we do if it goes negative? 52 00:05:40,830 --> 00:05:47,550 We said that this is modulo p so we can't just let it wrap around modulo 2^256, 53 00:05:47,550 --> 00:05:53,270 because that's how wide, you know, 4 registers are. But since we're doing 54 00:05:53,270 --> 00:05:57,680 arithmetic modulo a number, we can just add that number and the result is the 55 00:05:57,680 --> 00:06:03,720 same, right? Adding p modulo p is a no-op in the result. So that's what this code 56 00:06:03,720 --> 00:06:11,310 does: It does a equal a minus b, it takes a copy of the result and it adds p. And 57 00:06:11,310 --> 00:06:17,620 then in constant time, it uses that final carry to check, if it went negative or not 58 00:06:17,620 --> 00:06:23,340 to decide in constant time, which one to use. The one with b , so a minus b plus p 59 00:06:23,340 --> 00:06:30,169 or a minus B - and that's subtraction. Straightforward enough. Now the problem 60 00:06:30,169 --> 00:06:35,760 with this code is that if you look closely you can see something that might be weird 61 00:06:35,760 --> 00:06:40,860 if you're not familiar with assembly. It still trips me over. To use a condition 62 00:06:40,860 --> 00:06:45,150 like these constant time conditionals there. Which have to be constant time, 63 00:06:45,150 --> 00:06:50,190 because you don't want to leak timings based on the size of number. You have to 64 00:06:50,190 --> 00:06:56,540 first operate on mul0, so that you set the flags, the zero flag. So normally what you 65 00:06:56,540 --> 00:07:06,921 do is either add 0 and 1 to your mul0 to check if to set the flags. But that's 66 00:07:06,921 --> 00:07:13,240 not that's not an add, that's an add with carry. It means that it's adding zero to 67 00:07:13,240 --> 00:07:20,920 mul0 and the carry bit from this addition here, which has nothing to do with it, 68 00:07:20,920 --> 00:07:25,930 it's not supposed to be there. Like this is adding p, but it doesn't matter, if it 69 00:07:25,930 --> 00:07:31,570 overflows, because if it does, it wasn't going to be picked here anyway. So it's 70 00:07:31,570 --> 00:07:35,640 adding another bit into the operation that wasn't supposed to be there. So it's 71 00:07:35,640 --> 00:07:41,401 flipping the result, but then also the conditions here are flipped, so 72 00:07:41,401 --> 00:07:50,990 essentially it evens itself out. Except: when that carry bit happens not to be set, 73 00:07:50,990 --> 00:07:54,520 because the number a minus b is small enough, that if you add P, you don't wrap 74 00:07:54,520 --> 00:08:00,840 around. That happens once every 2^32 times, which is why it's so rare that 75 00:08:00,840 --> 00:08:06,540 nobody had noticed so far. So the code went in and nobody noticed for 76 00:08:06,540 --> 00:08:09,949 a long time, until CloudFlare first started scanning CT logs and had this 77 00:08:09,949 --> 00:08:16,120 weird one signature that wasn't verifying and they were lucky enough to actually 78 00:08:16,120 --> 00:08:21,140 have it in the logs because you know if it happens transiently you might just think.. 79 00:08:21,140 --> 00:08:27,970 I don't know, the connection broke, right? So this is what we call a carry 80 00:08:27,970 --> 00:08:32,828 propagation bug. Carry propagation is the activity of making sure that you carry the 81 00:08:32,828 --> 00:08:43,458 1. And here it's a bit weird, we didn't forget to carry it, but we carried a bit 82 00:08:43,458 --> 00:08:49,119 that we weren't supposed to carry into a result. Most of the times that goes well, 83 00:08:49,119 --> 00:08:55,490 sometimes that breaks. When that breaks: wrong result! Wrong result, wrong point 84 00:08:55,490 --> 00:09:02,889 computation and wrong point computation, so what? Like how does forgetting to carry 85 00:09:02,889 --> 00:09:09,209 the one lead to a full key recovery? This is not one of those bugs, where like 86 00:09:09,209 --> 00:09:13,480 buffer overflow you know what you're trying to do even if you might have to 87 00:09:13,480 --> 00:09:18,680 jump through so many hoops, because there might be all these protections, you know 88 00:09:18,680 --> 00:09:23,459 what your capabilities are, you can overwrite some memory. Here instead it's 89 00:09:23,459 --> 00:09:29,540 not clear what your capability is. So today I'm going to try to explain that. 90 00:09:29,540 --> 00:09:36,009 How we turn this very rare failed computation into a complete key recovery 91 00:09:36,009 --> 00:09:44,399 attack. But first I apologize that I have to give a elliptic curve cryptography 92 00:09:44,399 --> 00:09:55,449 crash course here at CCC. So we've seen the field is nothing else than operations 93 00:09:55,449 --> 00:10:03,269 modulo p, then there are the points: the points are x and y, the coordinates. They 94 00:10:03,269 --> 00:10:07,970 fit an equation, which we don't care about, they just fit an equation. They are 95 00:10:07,970 --> 00:10:13,499 integers, so we can work with them, and we can use them to build a group. A group is 96 00:10:13,499 --> 00:10:21,389 one of the core structures in modern cryptography. To build a group we need a 97 00:10:21,389 --> 00:10:26,929 zero point, a generator point, and an addition over the group, over the 98 00:10:26,929 --> 00:10:29,929 points. So we define an addition, 99 00:10:29,929 --> 00:10:34,649 again, we don't care about how addition works. It's just: you take two points, you 100 00:10:34,649 --> 00:10:38,120 add them together, you get a result. It has all the properties that you 101 00:10:38,120 --> 00:10:45,259 remember from elementary school addition: it's commutative, it's associative. And 102 00:10:45,259 --> 00:10:50,240 then you have multiplication: You don't actually define how to multiply a point, 103 00:10:50,240 --> 00:10:55,399 but if I tell you that you have an addition operation and I want five times 104 00:10:55,399 --> 00:11:00,689 this point, what do you do? You take the point and you add the point and you add 105 00:11:00,689 --> 00:11:06,790 the point and you add the point,... so this is called scalar multiplication: 106 00:11:06,790 --> 00:11:11,999 doing multiplication by adding repeatedly a certain point. 107 00:11:11,999 --> 00:11:19,139 So now we have a group, which is given by multiplying the point, a generator point, a 108 00:11:19,139 --> 00:11:25,110 certain number of times and we have a multiplication operation. So how do we 109 00:11:25,110 --> 00:11:31,189 build cryptography out of it? This is all awfully abstract so far? So we build 110 00:11:31,189 --> 00:11:35,180 elliptic curve Diffie-Hellman. If you're familiar with normal Diffie-Hellman, you 111 00:11:35,180 --> 00:11:41,149 will see something snap at some point. The private key is a giant number, this is 112 00:11:41,149 --> 00:11:50,470 important. The private key in ECDH is just a random giant 256 bit number. And then we 113 00:11:50,470 --> 00:11:56,250 have a public key. A public key is that giant number multiplied, the scalar 114 00:11:56,250 --> 00:12:03,319 multiplication we just talked about, by a generator point. If you know normal 115 00:12:03,319 --> 00:12:08,879 Diffie-Hellman, this is like doing g to the a. If you don't, it's okay, this is 116 00:12:08,879 --> 00:12:17,320 just multiplying private key by a point. And then, when I have my private key and 117 00:12:17,320 --> 00:12:23,230 my public key, you send me your public key. We need to agree on a shared secret, 118 00:12:23,230 --> 00:12:29,680 how we do that, is that I take your public key, which is a point. I take this and I 119 00:12:29,680 --> 00:12:36,300 multiply it by my private key, here, so again: it's my giant number private key 120 00:12:36,300 --> 00:12:41,749 multiplied by your point. That comes together: The two results are the same, 121 00:12:41,749 --> 00:12:48,680 because if we do my private key times your private key times g it's the same as your 122 00:12:48,680 --> 00:12:54,570 private key times my private key times g, because that's commutative. And we land on 123 00:12:54,570 --> 00:13:03,009 a shared secret. And that's all we need to know about elliptic curve cartography to 124 00:13:03,009 --> 00:13:10,629 exploit this. However, there's one thing that I glossed over: It's easy to multiply 125 00:13:10,629 --> 00:13:18,000 by five, you add five times. But if I'm asking you to multiply by a 256 126 00:13:18,000 --> 00:13:26,750 bit number, you can't add 2 to the 256 times a point, right? So what do we do 127 00:13:26,750 --> 00:13:31,399 there? Remember that here, what we're trying to do is the multiplication: The 128 00:13:31,399 --> 00:13:38,079 private key times the public key, the point. We do something called double and 129 00:13:38,079 --> 00:13:44,489 add: We take our private key and we string it out like bits. We start from the most 130 00:13:44,489 --> 00:13:49,939 significant bit. This is little endian, because I have gotten this slide wrong the 131 00:13:49,939 --> 00:13:54,850 first time. But, you know, you just claim that you meant it to be the opposite 132 00:13:54,850 --> 00:14:00,509 endianness. Anyway, that's the most significant bit, the one that is two to 133 00:14:00,509 --> 00:14:08,299 the 256, no, two to the 255. If you flip it, you're adding or removing two to the 134 00:14:08,299 --> 00:14:14,449 255. So you start with 0, that's zed, 0, nothing, and you check the first bit, the 135 00:14:14,449 --> 00:14:20,970 most important bit: Is that set, yes or no? Yes, so you add the point Q, which is 136 00:14:20,970 --> 00:14:26,129 the point we're trying to multiply by this giant e. So we add the point and then we 137 00:14:26,129 --> 00:14:33,029 move down one by doubling. Can you imagine how we double something? Remember we only 138 00:14:33,029 --> 00:14:39,709 have addition. We add it to itself, of course. So we use addition to double the 139 00:14:39,709 --> 00:14:45,800 point. And you might see, where we're going with this. We double every time we 140 00:14:45,800 --> 00:14:50,399 slide down one bit. By the time we arrive at the end, how many 141 00:14:50,399 --> 00:14:56,559 times did we double that first point that we added, because the first bit was one? 142 00:14:56,559 --> 00:15:04,319 255 times! That bit was worth 2 to the 255, so at the end that will have the 143 00:15:04,319 --> 00:15:10,559 value it was supposed to have. And we keep going, we check if this bit is 1: Is it 1? 144 00:15:10,559 --> 00:15:16,129 No. So we do nothing, we double again to move down one. We check if this bit is 145 00:15:16,129 --> 00:15:23,829 one. This bit is 1: so we add the point. So we did add the point, double, double, 146 00:15:23,829 --> 00:15:30,829 add the point, double, moving down one and we keep going like this. We keep going 147 00:15:30,829 --> 00:15:38,290 like this, until we reach the least significant bit. At the least significant 148 00:15:38,290 --> 00:15:42,899 bit, if it's one, we add the point, if it's not, we don't add the point. And at 149 00:15:42,899 --> 00:15:49,079 the end we have the correct result and the result comes from this sequence of 150 00:15:49,079 --> 00:15:56,320 operations which at most are twice 255 operations, which is something that we can 151 00:15:56,320 --> 00:16:07,399 do concretely. Now why did I explain this very specific algorithm to you. Because to 152 00:16:07,399 --> 00:16:12,199 understand this attack, you have to recognize that each key, so each string of 153 00:16:12,199 --> 00:16:19,840 bits here, converts into a very specific sequence of operations. Okay, if you 154 00:16:19,840 --> 00:16:26,959 change one bit, there will be an one more addition one less addition and each key 155 00:16:26,959 --> 00:16:33,260 has a very specific sequence. In this case it's add, double, double, add, double, 156 00:16:33,260 --> 00:16:44,230 add, double, double, and it keeps going. So back to our bug. If you spaced out, 157 00:16:44,230 --> 00:16:53,290 because we took a lot of crypto, I saw you! But the two things you should take 158 00:16:53,290 --> 00:16:59,300 away are: There's a giant number, it's the private key, we want to multiply the giant 159 00:16:59,300 --> 00:17:06,589 number by a point and we do that by doing additions and doubles in an order that is 160 00:17:06,589 --> 00:17:12,501 specified by the bits of the giant number. That's what you need to have clear, the 161 00:17:12,501 --> 00:17:20,299 only thing. So let's go back to see how we use that to turn our very small carry bug 162 00:17:20,299 --> 00:17:26,520 into a complete key recovery attack. First thing we do is we bubble it up. That 163 00:17:26,520 --> 00:17:30,820 function that breaks is called P256 subinternal. That's the function I showed 164 00:17:30,820 --> 00:17:39,769 you earlier. P256 subinternal is used by P256 point add, which is what we spoke about 165 00:17:39,769 --> 00:17:45,929 adding two points, the only important operation. And adding two points, we've 166 00:17:45,929 --> 00:17:51,950 seen, we use when we're multiplying, when we're doing that scalar multiplication, 167 00:17:51,950 --> 00:17:59,269 which is d times q, d times the point. And how is scalar mult used? Here we finally 168 00:17:59,269 --> 00:18:04,309 surfaced to a level that if you work with cryptographic protocols you might start 169 00:18:04,309 --> 00:18:09,840 recognizing pieces of. Scalar multiplication is the operation that the 170 00:18:09,840 --> 00:18:15,450 peer does in elliptic curve Diffie- Hellman. There's a scalar, which is the 171 00:18:15,450 --> 00:18:20,019 secret, which is the private key. There's a point, which is the public key of the 172 00:18:20,019 --> 00:18:26,000 other person, which might be the attacker. So the scalar multiplication here, 173 00:18:26,000 --> 00:18:34,090 speaking in InfoSec terms, has an attacker supplied point and a secret scalar and the 174 00:18:34,090 --> 00:18:41,350 result, the shared secret, is the session key. For example: TLS, when you open a 175 00:18:41,350 --> 00:18:47,019 connection with TLS and you're using elliptic curve Diffie-Hellman, then you 176 00:18:47,019 --> 00:18:53,360 will do this dance to agree on a session key. If the session key is correct, the 177 00:18:53,360 --> 00:18:59,320 connection will open and you will be able to, I don't know, get send HTTP request. 178 00:18:59,320 --> 00:19:06,110 If the bug is hit and the result is wrong, so the result bubbles up into a wrong 179 00:19:06,110 --> 00:19:14,370 shared secret, the session key is wrong. And the session key is wrong you notice, 180 00:19:14,370 --> 00:19:21,860 how do you notice? The connection breaks. So this is what in cryptography we call an 181 00:19:21,860 --> 00:19:25,230 oracle. You have an oracle that you can call and 182 00:19:25,230 --> 00:19:33,059 send a point, because that's your public key, you're the attacker, and you send 183 00:19:33,059 --> 00:19:39,929 that point and it gets multiplied by the private key. And it gives you one bit of 184 00:19:39,929 --> 00:19:46,220 information, did the bug trigger or did it not? Most of the times it won't, because 185 00:19:46,220 --> 00:19:54,159 remember, this is an extremely rare bug. So you have an oracle that tells you: Bug 186 00:19:54,159 --> 00:19:58,899 happen, bug didn't happen, based on the point you sent. And let's assume that the 187 00:19:58,899 --> 00:20:04,919 key stays the same, we'll talk about that. Can you imagine how we use that to start 188 00:20:04,919 --> 00:20:13,470 learning things about the key? Well, let's say, that we can magically conjure a point 189 00:20:13,470 --> 00:20:17,221 that in that sequence of operation, that's why I told you the sequence of operation 190 00:20:17,221 --> 00:20:25,380 was important, the bug happens very specifically at that addition and we find 191 00:20:25,380 --> 00:20:32,950 another point where the bug happens very specifically at that double. If we know 192 00:20:32,950 --> 00:20:39,210 already these bits of the key, and we aren't sure about this one, what can we do 193 00:20:39,210 --> 00:20:48,820 with these two points? We send them both, one of them will break the TLS connection, 194 00:20:48,820 --> 00:20:55,690 the other one will succeed. That means that the one that broke triggered the bug, 195 00:20:55,690 --> 00:21:01,679 the one that didn't break, didn't trigger the bug. And we know which one corresponds 196 00:21:01,679 --> 00:21:08,080 to which key. Because we magically made special points that only break very 197 00:21:08,080 --> 00:21:13,820 precisely at that point of the computation. Okay, so we learned a bit of 198 00:21:13,820 --> 00:21:19,240 the key. In cryptography as soon as you learn one bit of the key, there's probably 199 00:21:19,240 --> 00:21:28,140 a way all the way down. So we build what's called an adaptive attack. Let's say we 200 00:21:28,140 --> 00:21:34,070 have these bits, but we want to learn these, too. We compute two points, one 201 00:21:34,070 --> 00:21:40,110 that breaks, when the addition happens exactly at that point in the double and 202 00:21:40,110 --> 00:21:46,990 add a procedure, and one that triggers only when the add doesn't happen at the 203 00:21:46,990 --> 00:21:52,929 specific point in the double and add sequence. We send them both, only one of 204 00:21:52,929 --> 00:22:00,950 them breaks the TLS connection, well, then we know a bit! We go back to our magic 205 00:22:00,950 --> 00:22:05,669 point generator and we generate two new points. 206 00:22:05,669 --> 00:22:10,519 This time we don't look for things that break here, we look for things that break 207 00:22:10,519 --> 00:22:17,100 here. We make two points, we send them both. One of them breaks the connection, 208 00:22:17,100 --> 00:22:21,070 the other doesn't break the connection. We learned one more bit of the key. We go 209 00:22:21,070 --> 00:22:26,940 back, we make two points, we send them both: One breaks the connection, one 210 00:22:26,940 --> 00:22:31,410 doesn't. We keep going like that, once for each bit. Every time we go back and we 211 00:22:31,410 --> 00:22:36,110 adapt to what we learned so far. That's why it's called an adaptive attack, we 212 00:22:36,110 --> 00:22:41,269 can't pre-compute all these points. We have to come up with them while we learn 213 00:22:41,269 --> 00:22:47,940 the key. And the beautiful thing about adaptive attacks is that they look exactly 214 00:22:47,940 --> 00:22:53,919 like Hollywood, it's beautiful! Because you see them flipping and going through 215 00:22:53,919 --> 00:22:58,540 values, getting it right and moving to the next one, which you all told it was fake, 216 00:22:58,540 --> 00:23:16,010 it was not! Everything else is fake. Okay, so, this attack we came up with that, we 217 00:23:16,010 --> 00:23:21,730 told we had something extremely novel, we went to the literature and everyone that 218 00:23:21,730 --> 00:23:27,860 had picked an academic career in the audience knows exactly what happened: We 219 00:23:27,860 --> 00:23:33,659 found a paper that was doing exactly this. However, you know, it was a little 220 00:23:33,659 --> 00:23:44,109 different. It was still P256 and it was still ECDH and, hmm.. okay it's really 221 00:23:44,109 --> 00:23:50,740 similar. But it's an attack that depends a lot on the implementation details, how you 222 00:23:50,740 --> 00:23:55,629 pull it off. You can't suddenly just repurpose the code, but the idea so far: 223 00:23:55,629 --> 00:23:59,679 an adaptive attack where you send two points and you check which one breaks is 224 00:23:59,679 --> 00:24:05,580 the same as a BBB paper from a few years ago when it worked against open SSL 225 00:24:05,580 --> 00:24:13,530 instead. Instead of against this bug in the Go standard library. So instead from 226 00:24:13,530 --> 00:24:20,789 now on we're going to talk about how exactly we implemented this against Go, 227 00:24:20,789 --> 00:24:26,190 because this changes a lot based on the implementation details of the library 228 00:24:26,190 --> 00:24:31,450 you're working with. So this was the general idea of how the attack works. All 229 00:24:31,450 --> 00:24:35,920 that: You find points that break at the right time, you send them both, and that 230 00:24:35,920 --> 00:24:40,389 way you learn a bit of the key, except I lied to you. 231 00:24:40,389 --> 00:24:46,050 I lied to you, because I lied to you on a lot of things: The first one is that Go 232 00:24:46,050 --> 00:24:51,571 doesn't do double and add one bit at a time, it does it five bits at a time! It's 233 00:24:51,571 --> 00:24:57,730 called Booth multiplication, it took us forever to figure it out. It's an 1980s 234 00:24:57,730 --> 00:25:13,570 paper. Instead of adding one point or zero points and then doubling, it adds between 235 00:25:13,570 --> 00:25:20,059 minus 16 and plus 16 points and then doubles five times moving down. It just 236 00:25:20,059 --> 00:25:27,149 does it in blocks of five. So it splits up the key and then looks at each block of 237 00:25:27,149 --> 00:25:33,470 bits, picks a value from a pre-computed table, which is just all the values from 238 00:25:33,470 --> 00:25:40,620 one times the point to 16 times the point and in the loop it doubles five times, 239 00:25:40,620 --> 00:25:47,899 because it moved five bits down. And then it chooses, which point between zero and 240 00:25:47,899 --> 00:25:55,590 16 to use from the table and it adds that to the rolling result, instead of adding 1 241 00:25:55,590 --> 00:26:02,340 or 0. There's also a bit of constant time arithmetic there, because the other thing 242 00:26:02,340 --> 00:26:08,260 I lied to you on is that there's no such thing as at 0 point. It's an imaginary 243 00:26:08,260 --> 00:26:12,799 point that we add to make the math work, but when you try to tell the code to 244 00:26:12,799 --> 00:26:17,279 actually add the zero point it's like asking you to divide by 0. It just won't 245 00:26:17,279 --> 00:26:25,539 do it! But you know how you add 0, right? You do nothing! So there's some constant 246 00:26:25,539 --> 00:26:30,820 time code here that looks at it and if it's 0, it does nothing. If it's not 0, it 247 00:26:30,820 --> 00:26:39,669 adds the value. So the first thing we had to do to adapt 248 00:26:39,669 --> 00:26:46,690 to this format is that we worked in limbs. When you hear me say limb, it just means 249 00:26:46,690 --> 00:26:53,850 that we will look at each five bit block on its own as it is zero to sixteen and a 250 00:26:53,850 --> 00:27:01,019 sign value. That's much easier, because it's actually kind of weird how the five 251 00:27:01,019 --> 00:27:05,570 bits are extracted and I don't want to bore you with it. So let's just consider 252 00:27:05,570 --> 00:27:12,120 that we look at each group of five bits converted into a value from zero to 253 00:27:12,120 --> 00:27:18,850 sixteen and a one and a sign or plus minus sixteen. So when you hear me talk about 254 00:27:18,850 --> 00:27:24,529 limbs you just know that it means the five bit value from the key. This is still the 255 00:27:24,529 --> 00:27:34,730 giant d key that's the multiplier. So how does the attack change? Not that much! 256 00:27:34,730 --> 00:27:39,299 Instead of attacking one bit at a time, you know two points - one that breaks for 257 00:27:39,299 --> 00:27:45,179 zero, one that breaks for one - we attack one limb at a time, one that breaks for 258 00:27:45,179 --> 00:27:49,020 one, one that breaks for two, one that breaks for three, sixteen, minus one, 259 00:27:49,020 --> 00:27:57,720 minus two, minus 16. So, to recover five bits of the key, we'll need on average 260 00:27:57,720 --> 00:28:04,429 half the space: seventeen points, which is a little less efficient than the bit-by- 261 00:28:04,429 --> 00:28:15,950 bit one, because that would be five points for five bits. So, however, how the attack 262 00:28:15,950 --> 00:28:23,059 triggers is the same: We're looking for a bug that happens in the five doubles at 263 00:28:23,059 --> 00:28:33,700 the very right time or that happens at the addition at the very right time. Now 264 00:28:33,700 --> 00:28:38,649 that's still the high level of how we're going to do it, but in practice I didn't 265 00:28:38,649 --> 00:28:43,870 tell you how we're going to magically generate these magic points that break 266 00:28:43,870 --> 00:28:51,379 just at the right time. And I didn't tell you because it's fuzzing. There is there's 267 00:28:51,379 --> 00:28:58,830 no specific way to generate them algebraically, so instead we just hooked 268 00:28:58,830 --> 00:29:03,500 the assembly code with something that would just set a boolean, you know, true, 269 00:29:03,500 --> 00:29:08,590 false, if the conditions for the bug are met. And then we run through a lot of 270 00:29:08,590 --> 00:29:14,929 points. And if for each point we run it through the limbs we already know, 271 00:29:14,929 --> 00:29:19,519 remember this is an adaptive attack, so we want to learn the next limb. 272 00:29:19,519 --> 00:29:24,240 We learned a few limbs, we want to learn the next one. We run through the ones we 273 00:29:24,240 --> 00:29:30,631 know and then we try all the possible values for ones that we don't know. If one 274 00:29:30,631 --> 00:29:36,610 of them and only one of them breaks, that's a useful point. Because if we send 275 00:29:36,610 --> 00:29:46,390 that point and it breaks, we know exactly what the value of the next limb is. Okay, 276 00:29:46,390 --> 00:29:53,679 so this is going even more low-level. If you're interested in optimizations, we had 277 00:29:53,679 --> 00:29:57,860 to run through a lot of candidate points and for each point we needed to know the d 278 00:29:57,860 --> 00:30:02,850 value. Because we can find a magic point, but if we don't know the private key, we 279 00:30:02,850 --> 00:30:10,049 don't know if the entire protocol works and our oracle doesn't work anymore. So to 280 00:30:10,049 --> 00:30:15,080 work with that instead of multiplying a new random private key every time we just 281 00:30:15,080 --> 00:30:23,789 add that one to the private key and added the point to the public key, this is just 282 00:30:23,789 --> 00:30:32,769 an optimization. We called into the various assembly of the standard library. 283 00:30:32,769 --> 00:30:37,840 Don't do this, but it's beautiful. You can go call all the unexported functions in 284 00:30:37,840 --> 00:30:45,000 the standard library. I will never approve it on code review, but I love it. And then 285 00:30:45,000 --> 00:30:51,210 there's some post-processing to make sure that the bug is actually there, because 286 00:30:51,210 --> 00:30:55,970 sometimes there are false positives. So we just run it through the broken code, the 287 00:30:55,970 --> 00:30:59,740 fixed code, is the result the same? Well, false positive, is it 288 00:30:59,740 --> 00:31:10,690 different, good. Okay, so we have a way to move through the attack. The only thing we 289 00:31:10,690 --> 00:31:15,090 don't have yet is: How we figure out the first limb. The first one, the most 290 00:31:15,090 --> 00:31:19,100 important, the most significant one, when we still don't know anything about the 291 00:31:19,100 --> 00:31:27,210 key. The problem with this one is: It's like this, so let's pick three, it's an 292 00:31:27,210 --> 00:31:32,830 example okay, let's pretend that the limb is three. So we do our usual thing, we do 293 00:31:32,830 --> 00:31:40,330 our fuzzing and we find something that breaks at the fifth doubling and we send 294 00:31:40,330 --> 00:31:47,020 it and it breaks. It means that the first limb is three, right? Wrong. Sadly, it 295 00:31:47,020 --> 00:31:55,059 might mean that the limb is also 6 or 12. Because how six is selected for example is 296 00:31:55,059 --> 00:32:01,769 that three is taken, it's doubled and saved in the precomputation table as six, 297 00:32:01,769 --> 00:32:06,080 then it's taken out of the table, doubled five times, but what happens after you 298 00:32:06,080 --> 00:32:13,029 double six four times? What's the value? The exact same as doubling three five 299 00:32:13,029 --> 00:32:19,390 times, and the sequence is the exact same! So we don't know, which one it is, because 300 00:32:19,390 --> 00:32:23,850 we only know that that's the sequence but that doesn't tell us anything. And the 301 00:32:23,850 --> 00:32:29,740 same happens for 12, 12 is nothing else than 3 double double. So if we double it 302 00:32:29,740 --> 00:32:36,779 five times, at the third double it breaks and we only know if it breaks or not. So 303 00:32:36,779 --> 00:32:42,679 we can't move, so instead what we do is that we find three points: one that breaks 304 00:32:42,679 --> 00:32:48,350 after doubling three five times, one that breaks doubling it six times, and one that 305 00:32:48,350 --> 00:32:54,020 breaks after doubling it seven times. We send them all and we look at which ones 306 00:32:54,020 --> 00:33:01,110 break. Only this one? It's a three! The first and the second but not the third 307 00:33:01,110 --> 00:33:07,669 point? It's a six! All three? It's a 12! This took me forever to wrap my head 308 00:33:07,669 --> 00:33:17,250 around, this is like pure shaman insight. Okay now I can feel that you're getting 309 00:33:17,250 --> 00:33:25,870 bit tired, this is intensive, it's a lot of math, so let's go for a change of pace 310 00:33:25,870 --> 00:33:32,659 and let's talk about kangaroos instead. I'm gonna tell you something that I 311 00:33:32,659 --> 00:33:40,909 learned from a cryptographic paper, I swear. And it's about how kangaroos jump. 312 00:33:40,909 --> 00:33:48,729 Apparently kangaroos jump depending on how the terrain on which they are jumping from 313 00:33:48,729 --> 00:33:54,370 is. Depending on that terrain, if you put two kangaroos on the exact same spot, they 314 00:33:54,370 --> 00:33:59,770 will jump the same distance and approximately the same direction. I don't 315 00:33:59,770 --> 00:34:05,470 know, if this is true, but Pollard said so in a paper and I am NOT arguing with 316 00:34:05,470 --> 00:34:13,541 Pollard. So now, why is this useful? Well, this makes for an extremely cool way to 317 00:34:13,541 --> 00:34:22,311 catch kangaroos! I mean, did you expect some math or crypto? I know, we're 318 00:34:22,311 --> 00:34:27,920 catching kangaroos here! So you take a kangaroo that you have on hand, because 319 00:34:27,920 --> 00:34:34,219 you all have a kangaroo on hand. And you put a GPS tracker on it and you let it 320 00:34:34,219 --> 00:34:43,250 loose. This kangaroo jumps and it roams it enjoys a brief stint of freedom and it 321 00:34:43,250 --> 00:34:48,440 runs and at some point you go pick it up and because you know where it is and you 322 00:34:48,440 --> 00:34:54,679 place a trap there exactly where you find it. What happens to the kangaroo that is 323 00:34:54,679 --> 00:35:04,630 just passing by? If it steps at any point on one of the points, where the other 324 00:35:04,630 --> 00:35:10,820 kangaroo jumped from there on it will follow the same path. Because each jump 325 00:35:10,820 --> 00:35:20,750 depends on the ground. So this way if the wild kangaroo lands on any of the prints 326 00:35:20,750 --> 00:35:25,650 of the previous kangaroo you're catching it because eventually it will end up in 327 00:35:25,650 --> 00:35:30,940 the trap. Okay, this had nothing to do with the talk, I just wanted to share 328 00:35:30,940 --> 00:35:38,350 this! Now, okay, so here is how this converts to 329 00:35:38,350 --> 00:35:44,950 crypto. We can make elliptic curve points jump like kangaroos, we just have to make 330 00:35:44,950 --> 00:35:53,670 the jump deterministic based on the input, based on the starting point. For example 331 00:35:53,670 --> 00:35:59,770 we can take a hash, any hash, you design the hash. Apparently that's popular in 332 00:35:59,770 --> 00:36:01,740 cryptocurrencies to design your own hash .. 333 00:36:01,740 --> 00:36:13,090 *laughter* And you hash a point to another point and 334 00:36:13,090 --> 00:36:19,870 when you want to do a jump you take the point and you add it to its own hash, so 335 00:36:19,870 --> 00:36:27,630 Q_N+1 depends only on QN, and this is just like the kangaroo jump. How do you use 336 00:36:27,630 --> 00:36:35,810 this for what we're doing? We want to recover d, right? We want to recover the 337 00:36:35,810 --> 00:36:43,930 multiplier, the discrete log it's often called, of the public key. How we work 338 00:36:43,930 --> 00:36:50,810 with this is that we take a tame kangaroo, a point that we know the d off, and we 339 00:36:50,810 --> 00:36:58,660 make it jump a lot. It keeps jumping and we remember what the value is at the end. 340 00:36:58,660 --> 00:37:02,900 We take that value at the end and we save it. No need to keep all the points in 341 00:37:02,900 --> 00:37:09,810 between, so we don't need some giant memory construction and then we take the 342 00:37:09,810 --> 00:37:16,740 point that we don't know the d of and we make it jump a lot. What happens is that 343 00:37:16,740 --> 00:37:23,170 it has much higher probability to intersect one of the various prints of the 344 00:37:23,170 --> 00:37:28,570 previous point. When it does, it will eventually end up in our trap, it will end 345 00:37:28,570 --> 00:37:36,950 up having the same value as the one we calculated earlier. When that happens, we 346 00:37:36,950 --> 00:37:43,700 know how far the wild point traveled, because we were the ones making it jump. 347 00:37:43,700 --> 00:37:49,490 So we can just walk backwards to the starting point. It turns out that this is 348 00:37:49,490 --> 00:37:55,880 extremely efficient to find the d value when you know the interval of the d value. 349 00:37:55,880 --> 00:38:01,880 The intuition there is that if the kangaroo starts in a small area: You know 350 00:38:01,880 --> 00:38:07,190 when it's been too much time that it probably travelled past your trap. So you 351 00:38:07,190 --> 00:38:14,680 have to rewind time, which in crypto you can, and try again, because it went past 352 00:38:14,680 --> 00:38:18,360 your trap. So the smaller the interval, the more precise you can be, the more 353 00:38:18,360 --> 00:38:26,410 efficient attack. This is called the Pollard-kangaroo attack. It's described in 354 00:38:26,410 --> 00:38:30,791 original paper from the 1980s, it was described on Diffie-Hellman first, but it 355 00:38:30,791 --> 00:38:34,680 works on any group, so it works on elliptic curves. And the elliptic curve 356 00:38:34,680 --> 00:38:44,430 version is then improved by a few papers later and there is a chapter in the 357 00:38:44,430 --> 00:38:50,310 elliptic and hyperelliptic handbook that describes it. 358 00:38:50,310 --> 00:38:55,610 So we have it all, we have how to start, we have how to run through the attack and 359 00:38:55,610 --> 00:39:03,940 we have a how to end. So now let's get concrete, let's pick a target, as I said 360 00:39:03,940 --> 00:39:15,660 this attack works against JWT. JWT made ... a lot of questionable choices. One of 361 00:39:15,660 --> 00:39:21,021 them is to include as one of the public key algorithms elliptic curve Diffie- 362 00:39:21,021 --> 00:39:25,031 Hellman but not the version of Diffie- Hellman you and I are familiar with. The 363 00:39:25,031 --> 00:39:30,900 one where we both generate a new private key every time, which makes this attack 364 00:39:30,900 --> 00:39:35,160 impossible. Remember that this is an adaptive attack. We need to query the 365 00:39:35,160 --> 00:39:40,730 orcale for the same private key over and over and over again. Instead there's a 366 00:39:40,730 --> 00:39:48,450 variant called ephemeral static Diffie- Hellman, where one of the two sides is 367 00:39:48,450 --> 00:39:54,690 always the same. This is sometimes done as an optimization, don't do that. OpenSSL 368 00:39:54,690 --> 00:40:02,020 was doing that and it stopped doing that after a bunch of attacks came from that. 369 00:40:02,020 --> 00:40:06,960 So in TLS that usually doesn't happen and the Go TLS stack thankfully never did 370 00:40:06,960 --> 00:40:14,000 that, so the attack doesn't work against TLS. But JWT is encoded it straight into 371 00:40:14,000 --> 00:40:20,800 the standard, because if your public key is fixed, so is your private key, always 372 00:40:20,800 --> 00:40:30,610 the same. So if we have a service that accepts things encrypted with a ECDHES 373 00:40:30,610 --> 00:40:36,740 algorithm, we can use this attack. For example against the popular implementation 374 00:40:36,740 --> 00:40:46,370 Go-Jose, it's not Go-Jose's fault and Go 1.8.1.1, the latest vulnerable version, 375 00:40:46,370 --> 00:40:52,840 and we can just check if the service can decrypt what we're sending it. It can, 376 00:40:52,840 --> 00:40:58,430 because it throws HTTP error when it can't, because of different timings. This 377 00:40:58,430 --> 00:41:03,300 changes in any case, but what you need is the Oracle that tells you: did it work did 378 00:41:03,300 --> 00:41:08,280 it not work? Did the bug trigger, so are you right about your prediction of the 379 00:41:08,280 --> 00:41:13,370 limb or are you not? Then of course we need to do a lot of 380 00:41:13,370 --> 00:41:22,430 work. If you don't have the resources of a big corporation of where to spin up 381 00:41:22,430 --> 00:41:27,940 things, you can just use EC2 spot instances. How we architected that, is 382 00:41:27,940 --> 00:41:33,940 that there will be a small piece of code that do nothing intensive on your laptop 383 00:41:33,940 --> 00:41:43,540 or anything. It would accept HTTP requests from the workers. The beautiful thing 384 00:41:43,540 --> 00:41:48,360 about this infrastructure is that you can horizontally scale the workers, spin up as 385 00:41:48,360 --> 00:41:58,840 many as you want on node.js platforms, because the only thing that they need to 386 00:41:58,840 --> 00:42:04,040 be able to do: they don't need to have ports open, you don't have to worry about 387 00:42:04,040 --> 00:42:07,990 NAT, you can even run it on your botnet, because the only thing they have to do is 388 00:42:07,990 --> 00:42:14,230 connect back and ask for work and then after 30 cycles or when they find the 389 00:42:14,230 --> 00:42:18,180 point, connect back and say I found something, I didn't find anything, give me 390 00:42:18,180 --> 00:42:26,500 some more work and send the result. This was also useful, because if you get the 391 00:42:26,500 --> 00:42:31,210 worker code wrong or if you want to change the deployment, you can just redeploy the 392 00:42:31,210 --> 00:42:36,620 workers without losing state on the dispatcher. Because the dispatcher just 393 00:42:36,620 --> 00:42:44,930 keeps running and it will just wait for workers to come and ask. Specifically we 394 00:42:44,930 --> 00:42:51,800 built this just with the small script that you can start an EC2 machine with, because 395 00:42:51,800 --> 00:42:59,370 we didn't even need to make a custom image. So a few figures, a few numbers. 396 00:42:59,370 --> 00:43:05,260 Each Key has 52 limbs, it will take a bit less than that, because we have kangaroos. 397 00:43:05,260 --> 00:43:14,100 But let's say approximately 52. Each limb is 16 points on average. It would be 17, 398 00:43:14,100 --> 00:43:18,750 but two of the points are faster to find, so let's say 16. Each point takes 399 00:43:18,750 --> 00:43:30,570 approximately 2 to the 26 candidate points, before we find one that triggers 400 00:43:30,570 --> 00:43:41,010 the bug at the right point. Since we need 16 candidate points and each takes 2 to 401 00:43:41,010 --> 00:43:49,740 the 26 candidate points, that takes approximately 85 CPU hours. That's like 402 00:43:49,740 --> 00:43:57,520 one CPU running for an hour, 1 core. Turns out that you can get 85 CPU hours from 403 00:43:57,520 --> 00:44:04,440 spot instances for about a dollar and a quarter, which makes the total cost of the 404 00:44:04,440 --> 00:44:10,580 attack something like 60 bucks. Which was a relief, because I had done the 405 00:44:10,580 --> 00:44:16,780 math wrong first and the it came out as at 1000 and I run the demo tonight and I 406 00:44:16,780 --> 00:44:26,420 didn't check the bill, yeah.. Anyway, it's cheap. Now, I am not brave enough to run 407 00:44:26,420 --> 00:44:31,810 the attack live, because, yes, it's a nice infrastructure, but no, I don't trust it 408 00:44:31,810 --> 00:44:38,390 that much. But also, because it takes a while. If you don't want to spin up 409 00:44:38,390 --> 00:44:46,620 infinite number of EC2 machines, you have to accept that it would take about, I 410 00:44:46,620 --> 00:44:53,520 think, our attack run in 12 hours. So we're gonna look at a sped-up version of a 411 00:44:53,520 --> 00:44:58,180 one-hour video in the next 45 minutes, you have time, right? 412 00:44:58,180 --> 00:45:02,650 *laughter* No, it's a couple of minutes. So this is 413 00:45:02,650 --> 00:45:09,810 the UI. It shouldn't be too confusing and if anyone works at Hollywood and wants to 414 00:45:09,810 --> 00:45:17,100 license it, we can talk. What you're seeing is that the red values are the ones 415 00:45:17,100 --> 00:45:23,060 that we found a point for from the workers and we submitted. And when we submitted 416 00:45:23,060 --> 00:45:28,990 that it resulted not to be the right limb and the green ones are the ones that 417 00:45:28,990 --> 00:45:35,520 instead broke, so they're the right limb. Remember that here the target is a JWT 418 00:45:35,520 --> 00:45:42,860 receiving application. And then you can see the key slowly flipping from the 419 00:45:42,860 --> 00:45:51,650 bottom and it's exactly like Hollywood, I love that. So you can see the limbs 420 00:45:51,650 --> 00:45:57,080 filling up as we find them and that approximately there's 30 bits, so 2 to the 421 00:45:57,080 --> 00:46:07,000 30 rounds, so 30 candidates work for each round for each limb that we find. It 422 00:46:07,000 --> 00:46:16,930 obviously depends on luck and yes the the thing will probably keep running for a 423 00:46:16,930 --> 00:46:23,790 little while, but this is already at limb nine, it has to get to 52 and you don't 424 00:46:23,790 --> 00:46:34,510 have that patience. So this was the attack the code will be open-source soon. Leave 425 00:46:34,510 --> 00:46:40,120 the limbs you lost, they belong to us now. And: any questions? 426 00:46:40,120 --> 00:46:56,330 *applause* Herald: Valsorda, thank you very much for 427 00:46:56,330 --> 00:47:02,420 a lovely talk and the kangaroos. So, we have a question from the signal angel, go 428 00:47:02,420 --> 00:47:05,350 ahead, please. Signal Angel: Actually the internet wants 429 00:47:05,350 --> 00:47:10,060 to know: Did you compare this bug to implementation in other libraries. 430 00:47:10,060 --> 00:47:14,560 Filippo: So I guess that means, if I looked for similar bugs in other 431 00:47:14,560 --> 00:47:21,290 implementations. We did not, because each implementation is a bit different. Hanno 432 00:47:21,290 --> 00:47:27,520 works on a lot of fuzzing of bigint implementations and at one point he asked 433 00:47:27,520 --> 00:47:33,300 me, like on Twitter just today, if I tried fuzzing the Go implementation for example. 434 00:47:33,300 --> 00:47:41,190 And sadly this is constant time code that is specific to P256, so the answer is, 435 00:47:41,190 --> 00:47:45,780 there's a lot of them and the bug can be small and anywhere. It's not like you will 436 00:47:45,780 --> 00:47:52,590 be looking for another bug in P256 subtraction, it can be anywhere in the 437 00:47:52,590 --> 00:47:57,190 underlying math and we can turn that into the same attack. So, no, we didn't look 438 00:47:57,190 --> 00:48:05,431 for this specific one, but I think that four CVEs in 2017 on open SSL have 439 00:48:05,431 --> 00:48:11,590 descriptions that are very similar, but they're about finite field Diffie-Hellman, 440 00:48:11,590 --> 00:48:21,920 like normal DH. If you look for something that says about it's barely doable, 441 00:48:21,920 --> 00:48:27,560 because all the computation can be done offline. That's this kind of attacks on 442 00:48:27,560 --> 00:48:32,890 open SSL. Next? Herald: Are there any other questions from 443 00:48:32,890 --> 00:48:39,200 the Signal Angel? So please line up at the microphone. Microphone one please. 444 00:48:39,200 --> 00:48:44,550 Mic1: So why can't you determine the points algebraically? 445 00:48:44,550 --> 00:48:52,300 Filippo: Laziness? No, so it's entirely assembly and there's a lot of points where 446 00:48:52,300 --> 00:49:01,260 the value is then thrown out or it might get corrected by .. it's essentially we 447 00:49:01,260 --> 00:49:07,500 didn't see a clear path to this, and it's $65 on ec2, so it doesn't really change 448 00:49:07,500 --> 00:49:14,740 the feasibility to just fuzz them, so we just went for the fastest path to the 449 00:49:14,740 --> 00:49:19,000 entrance. Herald: Are there any other questions? 450 00:49:19,000 --> 00:49:21,830 Filippo: No one is asking about kangaroos, people, I mean.. 451 00:49:21,830 --> 00:49:26,090 Herald: Yes, ask about kangaroos, lovely. have you been to Australia? 452 00:49:26,090 --> 00:49:28,530 Filippo: I haven't. Herald: Okay, you have to. 453 00:49:28,530 --> 00:49:31,230 Filippo: Yep, definitely. Herald: I think, there aren't any other 454 00:49:31,230 --> 00:49:36,560 questions. So Filippo Valsorda, big round of applause for you. Thank you! 455 00:49:36,560 --> 00:49:40,398 *applause* 456 00:49:40,398 --> 00:49:45,509 *34c3 outro* 457 00:49:45,509 --> 00:50:02,000 subtitles created by c3subtitles.de in the year 2019. Join, and help us!