1 00:00:00,000 --> 00:00:04,680 Someone's got to come up with a hacker handle for him before the end of the session. So think 2 00:00:04,680 --> 00:00:11,460 on that while he talks. All right. Thanks. Can you hear me? Cool. All right. Let's stop 3 00:00:11,460 --> 00:00:16,500 moving. All right. Welcome. So this talk describes the vulnerability in Azure V2C as the 4 00:00:16,500 --> 00:00:23,100 title sort of implies. It lets you impersonate basically any user and any tenant that uses 5 00:00:23,100 --> 00:00:27,980 Azure V2C. It has been fixed in a couple different ways. There's some lingering 6 00:00:27,980 --> 00:00:33,680 remediations that I'll get to talk about in a little bit. So my name is John Novak, as he was 7 00:00:33,680 --> 00:00:38,240 saying. I'm a technical director at Pretorian. Most of the time I do security assessments for 8 00:00:38,240 --> 00:00:46,220 IoT, mobile, cloud, product security assessments. I do have a background in math and crypto. 9 00:00:46,440 --> 00:00:50,900 And I'd say I have a knack for identifying what sort of good crypto looks like in common 10 00:00:50,900 --> 00:00:57,940 implementations. And this one definitely falls in that category. So to get this out of the 11 00:00:57,940 --> 00:01:03,760 way at the beginning, I sort of believe that demonstration of security vulnerabilities is 12 00:01:03,760 --> 00:01:08,780 really vital for actually getting somebody to fix something, right? Many CVEs are 13 00:01:08,780 --> 00:01:15,420 theoretical. But demonstrating them is, you know, key for getting remediation. The neat thing 14 00:01:15,420 --> 00:01:20,680 about a crypto vulnerability is that I can prove to you that this is a vulnerability without 15 00:01:20,680 --> 00:01:27,680 actually telling you how I did it. In this case, I can provide a token, which is in this QR code here, 16 00:01:27,680 --> 00:01:33,220 here, which is signed by Microsoft with a key that I don't control. But the contents 17 00:01:33,220 --> 00:01:38,720 are all values that I do control. And in particular, like the email address field in the token 18 00:01:39,280 --> 00:01:44,960 is one that's not owned by me. In this case, a token like this one could be used to enumerate 19 00:01:44,960 --> 00:01:51,060 all bug bounty submissions to Microsoft through their web portal and only using sort of the 20 00:01:51,060 --> 00:01:59,460 email address of a victim. All right, so before I get into the weeds of this vulnerability, I wanted 21 00:01:59,460 --> 00:02:06,960 to quickly dive into some sort of background info on crypto, JWTs, and Azure B2C in particular. 22 00:02:07,480 --> 00:02:13,360 So when most people think of cryptography and encryption, they think of AES or symmetric 23 00:02:13,360 --> 00:02:19,780 encryption. And basically, in this mode, you have a secret key that is used to encrypt plain text, 24 00:02:19,840 --> 00:02:21,040 and the same secret key is used to encrypt plain text. And the same secret key is used to encrypt 25 00:02:22,680 --> 00:02:30,200 ciphertext. The sort of cons of this are that you sort of need to negotiate the secret key in 26 00:02:30,200 --> 00:02:36,580 advance. So both parties need to sort of have it. This does provide confidentiality. In some 27 00:02:36,580 --> 00:02:45,080 cases, it provides integrity in the sense that some block cipher algorithms can be modified in 28 00:02:45,080 --> 00:02:50,980 transit so that you might not know exactly that the cipher has not been sort of modified by a 29 00:02:50,980 --> 00:02:56,720 someone in transit. Conversely, for this talk, asymmetric encryption is done with asymmetric 30 00:02:56,720 --> 00:03:03,740 algorithms like RSA or elliptic curves. In this set up, you encrypt with a public key and then decrypt 31 00:03:03,740 --> 00:03:08,300 with a private key. And there's reasons you would want to do this, right? You say, for example, 32 00:03:08,300 --> 00:03:13,240 you have email or GPG or something set up, you want anyone with a public key to send you a message 33 00:03:13,240 --> 00:03:20,960 that only you with the private key can decrypt. So in this way, because it's sort of consistent with 34 00:03:20,980 --> 00:03:25,020 structure in this way, there is essentially no integrity in the encryption, right? You don't know 35 00:03:25,020 --> 00:03:30,580 who sent you the message unless it's been signed sort of out of band of this method. So that sort of 36 00:03:30,580 --> 00:03:36,640 plays a big piece in this vulnerability. So building on encryption types, when most people 37 00:03:36,640 --> 00:03:42,980 think of JWTs or JSON web tokens, they think of this construct, a signed blob. So essentially 38 00:03:42,980 --> 00:03:49,340 there's a header, some plain text text in there, and then a signature on the end. These definitely 39 00:03:49,340 --> 00:03:50,960 have integrity. You can't modify it. You can't modify it. You can't modify it. You can't modify 40 00:03:50,980 --> 00:03:56,200 the contents without invalidating the signature. But there's no sort of confidentiality, right? I can 41 00:03:56,200 --> 00:04:03,720 just read the contents. Another variant of JWTs are what's called a JSON web encryption, or JWE. 42 00:04:04,160 --> 00:04:12,040 And essentially this is an encrypted version of the same token. The first block there is just a 43 00:04:12,040 --> 00:04:16,240 sort of header values which tells you which algorithms are used. And the rest is all sort of 44 00:04:16,240 --> 00:04:17,900 pieces of the encryption. 45 00:04:20,980 --> 00:04:25,380 Based on which encryption algorithm you use, this will or will not have integrity. And in 46 00:04:25,380 --> 00:04:30,120 particular, if you use asymmetric encryption, there's essentially no integrity because anyone 47 00:04:30,120 --> 00:04:41,020 with the public key could construct an encrypted token and use it. All right. So Azure B2C is 48 00:04:41,600 --> 00:04:50,120 sort of the basis of this talk. It is a service developed by Microsoft. B2C stands for business to 49 00:04:50,980 --> 00:04:55,620 do. And essentially what it does is you can offload all of the authentication and session 50 00:04:55,620 --> 00:05:00,320 management and everything else from what you're developing onto this Microsoft service. You can 51 00:05:00,320 --> 00:05:06,820 set up log in flows to do things like log in, password resets, that sort of thing. You can 52 00:05:06,820 --> 00:05:11,540 integrate with Twitter, Facebook, Google log ins. There's a lot of documentation out there. I'm 53 00:05:11,540 --> 00:05:20,960 not going to repeat. But if you're interested, go take a look. So when you're configuring your B2C tenant, you set up an application. So you can set up a 54 00:05:20,980 --> 00:05:28,960 application. An application is really something like a single page app, a native app, like a mobile or desktop app. There are several 55 00:05:28,960 --> 00:05:35,980 fields you have to fill in. And on the right here, you can see that this is what it looks like in the Azure portal. You can see you specify, like, 56 00:05:36,020 --> 00:05:47,920 your OAuth flows, your redirect URIs, that sort of thing. To set up the user flows that go along with applications, you can use 57 00:05:47,920 --> 00:05:49,620 something called the identity experience framework. 58 00:05:52,260 --> 00:06:09,980 Microsoft, essentially what you do is you provide a bunch of XML syntax user flows, upload them to your Azure portal instance, and then they're used to sort of configure how users log in, right? You enter your email, you enter your password, your MFA, whatever you have. There are various 59 00:06:09,980 --> 00:06:19,780 starter packs and sort of community developed samples that you can go online on GitHub and download and install. And in particular, there's a tutorial, which I'm going to get to in a minute. 60 00:06:20,980 --> 00:06:34,540 which talks about signing and encryption keys and how to set up these policies. So in the image here, this is just set up using the basic starter pack, which has things like profile editing, password resets, sign in, that sort of thing. 61 00:06:36,940 --> 00:06:50,960 All right. So who uses B2C? Once you configure it, you set your sort of tenant name, and every B2C tenant is a subdomain off of B2C login.com. So you don't get a user 62 00:06:50,980 --> 00:06:59,680 unique certificate, so you can't look at, like, certificate transparency logs, but you can just, you know, Google online and find services which will just enumerate all subdomains of this one. 63 00:07:00,140 --> 00:07:13,580 It turns out that Microsoft also has, you know, publicly on their website, they have these customer success stories, which, you know, sort of pronounce which, you know, popular organizations are actually using their service. 64 00:07:13,740 --> 00:07:20,960 So just from their website, there is a healthcare provider in the U.K., a university in Japan, a manufacturer in Japan. 65 00:07:20,980 --> 00:07:31,060 I'm sure the U.S. government ID service for a country of 5 million. And, you know, even in my own personal life, I noticed that my own power company actually uses Azure B2C. 66 00:07:31,240 --> 00:07:40,580 So it sort of seems to be all over the place. All right. So part one of this vulnerability is going to be in this next section. 67 00:07:41,100 --> 00:07:49,880 And it all started basically when I started reading the documentation, right? So as I mentioned, they have this getting started. 68 00:07:50,980 --> 00:07:54,200 And what you see here on the right is just a screenshot of their documentation. 69 00:07:54,920 --> 00:08:03,280 And if you see it, it says to set up a signing key with type RSA and usage signature, and then an encryption key with type RSA and type encryption. 70 00:08:03,660 --> 00:08:08,300 And so knowing a bit about asymmetric encryption, this sort of struck me as a little strange. 71 00:08:09,000 --> 00:08:11,220 And so I, you know, began to dig deeper. 72 00:08:11,720 --> 00:08:16,500 On the left here is a screenshot of what it looks like in the Azure portal when you're setting it up. 73 00:08:16,560 --> 00:08:19,880 So it's just like a click box, auto-generate your keys sort of thing. 74 00:08:22,040 --> 00:08:28,480 So once you set it up, you, your environment gets sort of configured with this OAuth login flow. 75 00:08:28,760 --> 00:08:30,720 And I'll step through it briefly here, right? 76 00:08:30,820 --> 00:08:41,060 So you have, you get your login page, then you post your, yeah, you post your credentials, like your email, password, MFA, that sort of thing. 77 00:08:41,500 --> 00:08:46,560 Once you've completed your authentication, you get a code, you submit that to the token endpoint there. 78 00:08:46,840 --> 00:08:50,960 And it will, once it's validated, it will provide you with an ID token and a refund. 79 00:08:50,980 --> 00:09:00,160 And then at some point, you know, later in your session, say when your ID token is expired, you can present your refresh token again and get a new ID token and a new refresh token. 80 00:09:01,120 --> 00:09:07,200 The format of the ID token is a JWS signed with that sign-in key that you configured before. 81 00:09:07,480 --> 00:09:13,840 And the format of the refresh token is a JWE with, encrypted with that encryption key you set up before. 82 00:09:16,500 --> 00:09:20,500 So when you generate keys automatically, 83 00:09:21,520 --> 00:09:27,940 using their getting started documentation, what you find is that it looks like this in the Azure portal. 84 00:09:28,120 --> 00:09:34,800 So if you're the admin for your portal and you log in and sort of look at all the keys, you'll see the two keys on the right here. 85 00:09:34,880 --> 00:09:37,660 The token signing key and the token encryption key. 86 00:09:38,900 --> 00:09:41,160 You can't actually export these. 87 00:09:41,640 --> 00:09:44,700 And what you're actually viewing is just the public content, right? 88 00:09:44,760 --> 00:09:46,480 Not the private key part of it. 89 00:09:48,000 --> 00:09:50,960 If you instead try to generate an AES token, 90 00:09:50,980 --> 00:09:53,420 the AES key, which is the symmetric one instead of the asymmetric one, 91 00:09:53,560 --> 00:09:55,420 you'd get something that looks like the screenshot on the bottom. 92 00:09:55,940 --> 00:10:00,540 Very similar, but again, the actual key portion of that is not listed in the portal. 93 00:10:00,760 --> 00:10:01,800 And you can't export it. 94 00:10:03,080 --> 00:10:07,900 So it turns out that running through the sort of default setup, 95 00:10:08,380 --> 00:10:11,040 if you chose secret keys instead, 96 00:10:11,860 --> 00:10:15,520 and then once everything was set up, you logged in with a new user, 97 00:10:15,740 --> 00:10:17,120 you would get to this error page. 98 00:10:17,680 --> 00:10:20,020 And it sort of suggests, the error message there says, 99 00:10:20,980 --> 00:10:22,380 this must be 256-bit key. 100 00:10:22,600 --> 00:10:25,840 So it seems like what happens is on the back end, 101 00:10:25,960 --> 00:10:30,700 the auto-generation function is generating a key of, say, 128 bits or something like that. 102 00:10:30,920 --> 00:10:34,520 But then when it's generating your token, it's expecting a key of a different size. 103 00:10:34,860 --> 00:10:39,380 So basically, if a user on the street wanted to just use this out of the box, 104 00:10:39,640 --> 00:10:42,440 they would hit this error message and say, you know, what the heck's happening? 105 00:10:42,680 --> 00:10:46,160 So it seems unlikely that anyone actually uses symmetric keys in practice. 106 00:10:48,500 --> 00:10:48,980 However, 107 00:10:48,980 --> 00:10:52,420 instead of the auto-generation function, 108 00:10:52,660 --> 00:10:57,460 they do have an option for generating a key locally and uploading it to your environment. 109 00:10:57,660 --> 00:11:02,820 So in this way, you can know what your key is for your environment, set it up. 110 00:11:02,980 --> 00:11:05,420 And this is great for volume research in particular, 111 00:11:05,540 --> 00:11:09,560 because I can decrypt my own tokens with the keys that I know about. 112 00:11:11,260 --> 00:11:11,840 All right. 113 00:11:11,900 --> 00:11:15,740 So diving a little bit deeper here. 114 00:11:16,140 --> 00:11:18,960 So when you go through a login function, 115 00:11:18,980 --> 00:11:20,420 when you go through a login flow with this open ID scope, 116 00:11:21,140 --> 00:11:23,660 you will get an ID token returned to you. 117 00:11:23,800 --> 00:11:28,180 And as I mentioned before, this is signed with the signing key you configured. 118 00:11:28,820 --> 00:11:31,080 When you go through a login flow with offline access, 119 00:11:31,380 --> 00:11:38,360 you will get a refresh token similarly encrypted with the token encryption key that you configured. 120 00:11:39,520 --> 00:11:42,360 If you look at the putting the ID token aside, 121 00:11:42,640 --> 00:11:44,000 if you look at the refresh token, 122 00:11:44,200 --> 00:11:48,880 you'll notice that it has some headers in the first sort of block. 123 00:11:48,980 --> 00:11:50,580 But it doesn't have all of them. 124 00:11:50,740 --> 00:11:54,180 In particular, it doesn't have the algorithms that are used to encrypt the token. 125 00:11:54,400 --> 00:11:58,940 But it does have the key ID and the sort of deflate method in there. 126 00:12:01,620 --> 00:12:06,000 So in my own test setup, I can upload my own key. 127 00:12:06,320 --> 00:12:09,180 I can go through my login flow, get my tokens, 128 00:12:09,600 --> 00:12:10,980 decrypt them with the key that I know about, 129 00:12:11,560 --> 00:12:16,280 and sort of do a little trial and error to figure out what the algorithms were. 130 00:12:16,440 --> 00:12:18,440 So it turns out it's what you might expect. 131 00:12:18,980 --> 00:12:22,840 So I'll say OAEP for the outer layer of the JWE encryption, 132 00:12:23,140 --> 00:12:25,500 and then AES 256-bit GCM. 133 00:12:26,160 --> 00:12:28,680 And then once you've done all that decryption, 134 00:12:28,940 --> 00:12:32,140 the actual contents are just compressed with Zlib. 135 00:12:33,240 --> 00:12:38,160 One thing you do notice is that once you've gone through all those layers, 136 00:12:38,400 --> 00:12:41,860 you'll notice that it's not actually a nested JWT. 137 00:12:42,040 --> 00:12:45,160 And this is a concept where essentially you have a signed token 138 00:12:45,160 --> 00:12:47,080 and then you encrypt that signed token 139 00:12:47,080 --> 00:12:51,020 so that you have a signed blob inside of your encrypted blob. 140 00:12:51,740 --> 00:12:54,840 So without being nested, there's essentially no integrity, right? 141 00:12:54,920 --> 00:12:57,940 I could craft my own token. 142 00:12:58,540 --> 00:13:02,940 And so this is, roughly speaking, what the two tokens look like. 143 00:13:03,100 --> 00:13:05,820 So if I go ahead and decrypt my refresh token, 144 00:13:06,080 --> 00:13:08,440 it looks something like the field on the left. 145 00:13:08,500 --> 00:13:10,360 I've formatted it nicely so you can see it. 146 00:13:10,820 --> 00:13:13,920 But essentially, when you have a refresh token of this type 147 00:13:13,920 --> 00:13:15,000 and submit it, 148 00:13:16,900 --> 00:13:18,320 to the token endpoint, 149 00:13:18,580 --> 00:13:22,160 you'll get an ID token corresponding to the values in your refresh token. 150 00:13:22,520 --> 00:13:25,540 So in bold here, I have a couple of fields which are modified, 151 00:13:25,760 --> 00:13:31,360 and essentially it's showing that if I modify some fields in my refresh token, 152 00:13:31,560 --> 00:13:33,200 they're actually reflected in my ID token. 153 00:13:34,880 --> 00:13:38,580 These values don't actually have to match whatever's on my account. 154 00:13:38,760 --> 00:13:40,120 It could match anything I wanted. 155 00:13:40,280 --> 00:13:41,420 You can see I changed my name there. 156 00:13:41,520 --> 00:13:44,660 I added some extra parameters that may or may not mean something 157 00:13:45,000 --> 00:13:46,660 to whatever environment I'm working in. 158 00:13:48,980 --> 00:13:50,480 So as I've said, 159 00:13:51,700 --> 00:13:55,040 with the known format and a public RSA key, 160 00:13:55,260 --> 00:14:00,620 I can essentially encrypt and generate and encrypt a refresh token with any contents I want, 161 00:14:00,840 --> 00:14:03,320 submit it to the token endpoint, and get an ID token. 162 00:14:04,500 --> 00:14:09,720 It should be noted that this public key is actually just exposed in the Azure portal only 163 00:14:09,720 --> 00:14:14,720 to these three user roles, the fairly privileged admin roles. 164 00:14:16,880 --> 00:14:21,500 And so the sort of first step of this attack chain, 165 00:14:22,160 --> 00:14:24,640 you essentially lop off the whole authentication flow. 166 00:14:25,740 --> 00:14:29,420 If you have some, say, unknown means to recover this public key, 167 00:14:30,180 --> 00:14:33,180 but then using what I just showed, you can generate your refresh token, 168 00:14:34,200 --> 00:14:35,860 submit it, and get a new ID token. 169 00:14:36,400 --> 00:14:39,620 So I went ahead. 170 00:14:40,420 --> 00:14:43,800 I did a whole bunch of this research about two, two and a half years ago, 171 00:14:44,420 --> 00:14:44,980 submitted it. 172 00:14:45,000 --> 00:14:46,680 I submitted it to the Microsoft Security Response Center. 173 00:14:48,080 --> 00:14:50,580 And my submission at the time mentioned that, you know, 174 00:14:50,580 --> 00:14:53,080 you need this public key, and there's, you know, 175 00:14:53,080 --> 00:14:55,640 you can get it with this read-only role, but it's really, it's hard. 176 00:14:55,760 --> 00:14:58,040 It's not exposed in any other way, right? 177 00:14:58,120 --> 00:15:00,040 It's not on, like, some secret endpoint I could just query. 178 00:15:01,000 --> 00:15:03,960 And so after a little bit of back and forth, 179 00:15:04,100 --> 00:15:07,940 they closed this issue with essentially no action taken in April. 180 00:15:09,300 --> 00:15:13,740 Personally, I'd sort of argue that if your security depends on hiding a secret key 181 00:15:13,740 --> 00:15:14,520 or a public key, 182 00:15:15,000 --> 00:15:15,960 then it really isn't secure, right? 183 00:15:16,000 --> 00:15:17,840 You're just hiding something that should be public. 184 00:15:20,540 --> 00:15:23,820 And, you know, going a step further, in instances, you know, 185 00:15:23,880 --> 00:15:27,160 on security assessments, oftentimes we'll get source code for our clients, right? 186 00:15:27,260 --> 00:15:30,340 And we want to make sure that even with source code access, 187 00:15:30,600 --> 00:15:33,460 there shouldn't be anything like hard-coded keys or back doors or whatever, right? 188 00:15:33,880 --> 00:15:38,260 Similarly, in cloud environments, I'd argue that getting read-only access 189 00:15:38,260 --> 00:15:41,320 to a cloud environment, you shouldn't be able to do things like read your database 190 00:15:41,320 --> 00:15:44,200 or, you know, read keys or elevate privileges or anything else. 191 00:15:45,820 --> 00:15:47,920 So that's sort of my two cents here. 192 00:15:49,800 --> 00:15:52,840 So if that was the end of the story, I probably wouldn't be here talking at DEF CON. 193 00:15:53,980 --> 00:15:55,820 But there is a part two to this story. 194 00:15:56,240 --> 00:15:58,420 And in particular, it's a side channel attack. 195 00:15:59,240 --> 00:16:00,620 So really what I'm... 196 00:16:00,620 --> 00:16:03,820 The objective here is to recover the public key, right? 197 00:16:03,960 --> 00:16:05,620 We have all the other pieces of this attack chain. 198 00:16:05,820 --> 00:16:07,180 All we need is this public key. 199 00:16:07,600 --> 00:16:11,800 So for RSA, the public key is... 200 00:16:12,540 --> 00:16:14,120 The public components of RSA 201 00:16:15,000 --> 00:16:17,100 N, a modulus of 20, 48 bits. 202 00:16:17,460 --> 00:16:18,740 And then E, your exponent. 203 00:16:19,280 --> 00:16:21,100 So for all intents and purposes, 204 00:16:21,620 --> 00:16:26,020 you know, 99% of RSA implementations have a fixed E value. 205 00:16:26,200 --> 00:16:27,320 So we'll just say that's known. 206 00:16:28,340 --> 00:16:31,200 But the modulus is really what we want to figure out and recover. 207 00:16:32,140 --> 00:16:35,520 Another thing we know is that anytime you encrypt something, 208 00:16:36,880 --> 00:16:38,080 you get a ciphertext. 209 00:16:38,260 --> 00:16:40,680 And that ciphertext is necessarily going to be less than N 210 00:16:40,680 --> 00:16:42,680 based on the math that's involved in RSA. 211 00:16:43,240 --> 00:16:44,580 So you can get, you know, 212 00:16:45,000 --> 00:16:46,620 a rough lower bound for what N is. 213 00:16:47,480 --> 00:16:49,100 You know, it's not very practical. 214 00:16:49,280 --> 00:16:51,880 It would take an inordinate amount of samples 215 00:16:51,880 --> 00:16:53,180 to actually recover something. 216 00:16:54,340 --> 00:16:56,140 But, you know, it's a stepping stone here. 217 00:16:57,700 --> 00:16:59,320 So what do I have here? 218 00:16:59,520 --> 00:16:59,940 I have... 219 00:16:59,940 --> 00:17:01,840 When I have a refresh token 220 00:17:01,840 --> 00:17:04,480 and I'm submitting it to this B2C endpoint, 221 00:17:04,920 --> 00:17:07,180 effectively what's happening at some level, right, 222 00:17:07,280 --> 00:17:08,960 is it's going to call decrypt RSA 223 00:17:08,960 --> 00:17:11,540 with a ciphertext that I get to control 224 00:17:11,540 --> 00:17:14,980 and then the other components of my RSA key, right? 225 00:17:15,000 --> 00:17:16,660 The N and the D exponent. 226 00:17:17,360 --> 00:17:20,920 So essentially I can feed in whatever ciphertext I want. 227 00:17:22,000 --> 00:17:24,280 Looking at what decrypt RSA is, 228 00:17:24,480 --> 00:17:26,000 you know, a 10,000-foot view, 229 00:17:26,260 --> 00:17:29,200 it effectively does these sort of math operations. 230 00:17:29,380 --> 00:17:32,200 It computes your plaintext based off your ciphertext 231 00:17:32,200 --> 00:17:33,260 raised to the power D. 232 00:17:33,920 --> 00:17:37,440 It then verifies the OAEP padding, 233 00:17:37,700 --> 00:17:41,160 which involves doing a SHA hash on your plaintext. 234 00:17:41,980 --> 00:17:43,600 If that is verified, 235 00:17:43,840 --> 00:17:44,540 then... 236 00:17:45,000 --> 00:17:46,060 it'll return your plaintext. 237 00:17:46,300 --> 00:17:48,560 Otherwise it's just gonna, you know, chuck out an error 238 00:17:48,560 --> 00:17:49,700 and say, you know, 239 00:17:49,700 --> 00:17:52,600 you provided some ciphertext that didn't match. 240 00:17:53,260 --> 00:17:56,900 It turns out that this is somewhat computationally expensive. 241 00:17:57,240 --> 00:18:00,220 The modular exponentiation and the hash 242 00:18:00,220 --> 00:18:04,040 both take, you know, non-negative CPU time to compute. 243 00:18:05,440 --> 00:18:09,380 So suppose there is a crypto library that does this, right? 244 00:18:09,480 --> 00:18:11,680 Since we know the ciphertext 245 00:18:12,800 --> 00:18:14,760 is gonna be less than our value N, 246 00:18:15,560 --> 00:18:17,420 why not just add an if statement at the top 247 00:18:17,420 --> 00:18:19,420 that says if your ciphertext is too big, 248 00:18:19,500 --> 00:18:20,900 just error out, right? 249 00:18:20,980 --> 00:18:23,340 Don't do the rest of the decryption. 250 00:18:23,440 --> 00:18:24,320 Save yourself some time. 251 00:18:25,040 --> 00:18:26,460 And, you know, return the error. 252 00:18:27,180 --> 00:18:30,020 This shouldn't actually expose any sort of information 253 00:18:30,700 --> 00:18:33,440 because, again, N is supposed to be a public value. 254 00:18:33,900 --> 00:18:36,900 And so there's no sort of crypto bug in any library 255 00:18:36,900 --> 00:18:38,820 that's out there just based on this. 256 00:18:40,060 --> 00:18:43,440 However, what you do get is you get a time differential, right? 257 00:18:43,520 --> 00:18:44,980 So if I improvise a time differential, 258 00:18:45,000 --> 00:18:48,900 providing a ciphertext that is greater or less than N, 259 00:18:49,020 --> 00:18:51,160 this decrypt function is gonna return 260 00:18:51,160 --> 00:18:53,440 in one of two different times, right? 261 00:18:54,040 --> 00:18:57,760 And so based on if I can observe the timing difference, 262 00:18:58,020 --> 00:19:01,140 I could see what... 263 00:19:01,140 --> 00:19:05,200 I could glean some information about what N actually is. 264 00:19:11,000 --> 00:19:13,640 All right, so I did this. 265 00:19:15,000 --> 00:19:19,780 I took a JWE with a cipher encryption key of 2 to the 2047 266 00:19:19,780 --> 00:19:21,940 and then one with 2 to the 2048. 267 00:19:22,540 --> 00:19:24,880 I knew these values would be both less than 268 00:19:24,880 --> 00:19:26,140 and then greater than N. 269 00:19:26,600 --> 00:19:31,420 I submitted both of these tokens to my B2C token endpoint 270 00:19:32,020 --> 00:19:34,780 and then, you know, observed the response time and compared. 271 00:19:35,580 --> 00:19:39,340 One thing I will note that you're trying to observe 272 00:19:39,340 --> 00:19:42,380 a time that is sort of very small here, right? 273 00:19:42,400 --> 00:19:44,040 So doing this over my... 274 00:19:45,000 --> 00:19:46,920 over my own laptop, over my Wi-Fi network, 275 00:19:47,100 --> 00:19:49,000 all the way across the internet to the endpoint 276 00:19:49,620 --> 00:19:52,500 is gonna introduce a lot of jitter in your timing, right? 277 00:19:52,580 --> 00:19:55,580 So I tried to reduce this as much as possible, 278 00:19:55,640 --> 00:19:57,240 doing things like, you know, 279 00:19:57,240 --> 00:19:59,720 say, running on Azure cloud infrastructure, right? 280 00:20:00,140 --> 00:20:04,280 Just shorten the distance between where my code is 281 00:20:04,280 --> 00:20:05,260 and where the endpoint is. 282 00:20:05,860 --> 00:20:07,880 I also tried to avoid some load balancing 283 00:20:07,880 --> 00:20:09,600 by, you know, fixing IP addresses 284 00:20:09,600 --> 00:20:13,200 so that I wasn't hitting different B2C token endpoints 285 00:20:13,200 --> 00:20:14,600 every time I submitted a request. 286 00:20:15,080 --> 00:20:16,380 And then other things like, you know, 287 00:20:16,400 --> 00:20:18,700 pipelining your TLS session and stuff like that. 288 00:20:20,000 --> 00:20:24,200 So what you find is that with these two values, 289 00:20:26,140 --> 00:20:28,420 you...I submitted 2,000 requests of each type 290 00:20:29,040 --> 00:20:30,120 and plotted them. 291 00:20:30,420 --> 00:20:32,580 And essentially what you see is that 292 00:20:33,300 --> 00:20:36,960 the ciphertext that is smaller is in blue here 293 00:20:36,960 --> 00:20:38,460 and the larger one is in red. 294 00:20:38,620 --> 00:20:41,460 And you'll note that the curve for the blue one 295 00:20:41,460 --> 00:20:44,160 is just ever so slightly to the right of the other one, right? 296 00:20:44,160 --> 00:20:46,780 And this really means that there is a timing differential, 297 00:20:47,300 --> 00:20:49,600 and it is observable, even across the internet, 298 00:20:50,180 --> 00:20:51,460 to these token endpoints. 299 00:20:53,120 --> 00:20:55,480 These graphs are very close together, right? 300 00:20:55,580 --> 00:20:56,440 They're kind of noisy. 301 00:20:57,040 --> 00:20:59,740 But it is there, and it is within reach 302 00:20:59,740 --> 00:21:02,040 for a sort of timing attack. 303 00:21:03,040 --> 00:21:05,960 In this instance, I recorded the averages 304 00:21:05,960 --> 00:21:08,540 at a 28.1 and 26.8 milliseconds. 305 00:21:09,160 --> 00:21:11,120 If you ran this at home, it might, you know, 306 00:21:11,120 --> 00:21:13,240 differ based on where you're running from. 307 00:21:16,120 --> 00:21:17,660 So let's generalize, right? 308 00:21:17,760 --> 00:21:20,400 We have a timing attack that tells you 309 00:21:20,400 --> 00:21:23,820 if you're greater or less than a certain value, 310 00:21:25,060 --> 00:21:27,940 as any sort of undergraduate computer science major 311 00:21:27,940 --> 00:21:28,780 will tell you. 312 00:21:28,940 --> 00:21:30,500 Why not use a binary search, right? 313 00:21:31,040 --> 00:21:33,940 So you take this timing differential, 314 00:21:34,240 --> 00:21:35,580 you submit a bunch of samples, 315 00:21:35,720 --> 00:21:37,920 starting with an upper and lower bound and a midpoint, 316 00:21:38,120 --> 00:21:40,160 and then you make some judgment call on 317 00:21:40,160 --> 00:21:43,900 if the time of your midpoint 318 00:21:44,400 --> 00:21:46,840 closer matches your upper or your lower bound, 319 00:21:47,040 --> 00:21:50,360 and then you sort of shorten your search space by half, right? 320 00:21:50,620 --> 00:21:51,440 And then you repeat. 321 00:21:51,760 --> 00:21:54,780 So essentially, this sort of timing attack, 322 00:21:54,960 --> 00:21:56,040 based on this fact, 323 00:21:56,220 --> 00:21:58,820 lets you recover one bit of your public key 324 00:21:58,820 --> 00:21:59,800 for each round. 325 00:22:01,120 --> 00:22:04,440 So again, I did this on an environment 326 00:22:04,440 --> 00:22:05,340 that I did not control. 327 00:22:06,880 --> 00:22:08,940 Because you're running a timing attack, 328 00:22:09,740 --> 00:22:13,220 each of these rounds is not fully reliable, right? 329 00:22:15,060 --> 00:22:16,240 There are going to be instances 330 00:22:16,240 --> 00:22:18,080 where you do your timing attack 331 00:22:18,080 --> 00:22:20,620 and you actually guess incorrectly 332 00:22:20,620 --> 00:22:21,860 where the midpoint was. 333 00:22:22,040 --> 00:22:25,180 So I had to build in some logic for backtracking 334 00:22:25,180 --> 00:22:28,540 and assuming, you know, 335 00:22:28,540 --> 00:22:30,480 backing it one step up in my binary search 336 00:22:30,480 --> 00:22:33,000 so that I didn't just go down a rabbit hole 337 00:22:33,000 --> 00:22:33,500 that was incorrect. 338 00:22:34,440 --> 00:22:36,060 Additionally, the Azure token endpoint 339 00:22:36,060 --> 00:22:37,840 has rate limiting, so I couldn't just 340 00:22:38,440 --> 00:22:40,860 spam it with requests as fast as I wanted to. 341 00:22:42,040 --> 00:22:42,980 But all in all, 342 00:22:44,160 --> 00:22:46,060 I implemented this attack and ran it on an environment 343 00:22:46,060 --> 00:22:47,720 that I did not control, 344 00:22:48,520 --> 00:22:50,100 and it recovered about 50, 345 00:22:50,120 --> 00:22:51,840 55 bits an hour. 346 00:22:52,280 --> 00:22:53,740 This may seem slow. 347 00:22:54,500 --> 00:22:54,940 However, 348 00:22:56,400 --> 00:22:58,460 refresh tokens probably are valid for 349 00:22:58,460 --> 00:23:00,320 something on the order of 90 days. 350 00:23:00,720 --> 00:23:01,840 And so, 351 00:23:02,000 --> 00:23:04,040 you know, the keys associated with those 352 00:23:04,040 --> 00:23:06,420 are likely valid for something like years, right? 353 00:23:06,520 --> 00:23:09,060 So even if your attack takes a day and a half 354 00:23:09,060 --> 00:23:10,960 for a key that lasts a year, 355 00:23:11,060 --> 00:23:12,800 I think that's perfectly reasonable. 356 00:23:14,720 --> 00:23:17,800 This graph here is the sort of attack and action 357 00:23:17,800 --> 00:23:18,800 as I implemented it. 358 00:23:19,040 --> 00:23:21,020 You see in the zoomed-in part there, 359 00:23:21,100 --> 00:23:23,660 the jitter is essentially the backtracking, 360 00:23:23,820 --> 00:23:28,200 and then the little gaps that are in there 361 00:23:28,200 --> 00:23:30,580 are the rate limiting that I was hitting. 362 00:23:34,000 --> 00:23:35,200 So there we go. 363 00:23:35,260 --> 00:23:36,800 The attack is sort of complete now. 364 00:23:37,460 --> 00:23:38,900 I have this timing attack. 365 00:23:39,100 --> 00:23:40,680 I can recover this public key. 366 00:23:40,920 --> 00:23:43,520 I can generate a refresh token 367 00:23:43,520 --> 00:23:44,600 with any user details, 368 00:23:45,140 --> 00:23:47,220 and then I can post this refresh token 369 00:23:47,220 --> 00:23:49,640 and get back an ID token 370 00:23:49,640 --> 00:23:51,120 with whatever I want, right? 371 00:23:51,200 --> 00:23:52,080 So essentially, 372 00:23:52,660 --> 00:23:54,500 I can use this to compromise 373 00:23:54,500 --> 00:23:56,600 any B2C tenant that I like. 374 00:23:58,100 --> 00:23:58,540 So, 375 00:24:00,220 --> 00:24:01,620 going back to the very beginning here, 376 00:24:01,960 --> 00:24:02,940 demonstration, right? 377 00:24:04,440 --> 00:24:06,020 When you, if, 378 00:24:06,140 --> 00:24:07,980 you know, I'm sure some of you in the audience 379 00:24:07,980 --> 00:24:09,340 have submitted vulnerabilities to Microsoft. 380 00:24:10,500 --> 00:24:12,600 When you do that, you likely went through 381 00:24:12,600 --> 00:24:13,980 the Microsoft Security Response Center. 382 00:24:15,260 --> 00:24:16,700 When you go to the login page, 383 00:24:16,960 --> 00:24:21,200 you'll notice that it is this msrcweb.b2clogin.com. 384 00:24:21,480 --> 00:24:25,340 So essentially, Microsoft is using B2C 385 00:24:25,340 --> 00:24:27,580 as their authentication service 386 00:24:27,580 --> 00:24:29,840 for submitting vulnerabilities to their platform. 387 00:24:30,280 --> 00:24:32,200 So it seems like a perfect target. 388 00:24:32,440 --> 00:24:34,560 It doesn't, it's a Microsoft property. 389 00:24:34,780 --> 00:24:37,660 It's not gonna violate their sort of terms of service, right? 390 00:24:37,760 --> 00:24:39,500 But it's gonna demonstrate that I can, 391 00:24:39,500 --> 00:24:42,320 that I can do something on a live environment 392 00:24:42,320 --> 00:24:43,260 that isn't my own. 393 00:24:45,260 --> 00:24:45,660 So, 394 00:24:49,200 --> 00:24:50,320 so as I mentioned, 395 00:24:51,260 --> 00:24:52,560 you just, you know, 396 00:24:52,560 --> 00:24:53,720 you go through this login flow. 397 00:24:55,000 --> 00:24:57,560 If you, it's basically as easy as 398 00:24:57,560 --> 00:24:58,480 if you're, you know, 399 00:24:58,480 --> 00:25:00,900 if you run your session through a proxy 400 00:25:00,900 --> 00:25:01,780 like burp or something, 401 00:25:02,200 --> 00:25:04,220 and then just observe all the 402 00:25:04,980 --> 00:25:06,320 back and forth, you'll see 403 00:25:06,820 --> 00:25:09,060 basically all the components of the login flow you need, right? 404 00:25:09,100 --> 00:25:09,360 The, 405 00:25:14,140 --> 00:25:16,600 all of the artifacts that are part of it, right? 406 00:25:16,680 --> 00:25:19,260 And how you get the refresh token at the end. 407 00:25:19,380 --> 00:25:20,840 So there's really no guesswork in, 408 00:25:20,840 --> 00:25:23,220 in how to set up the OAuth login flow 409 00:25:23,220 --> 00:25:24,140 in a custom environment. 410 00:25:24,340 --> 00:25:25,180 You don't really need that. 411 00:25:25,240 --> 00:25:26,460 You can just sort of replay, 412 00:25:26,600 --> 00:25:28,040 replay requests as necessary. 413 00:25:29,800 --> 00:25:31,660 So, right, I ran the stack. 414 00:25:32,200 --> 00:25:35,380 I recovered the public key for this msrckeyid. 415 00:25:36,160 --> 00:25:38,860 I used the known format to make a refresh token 416 00:25:38,860 --> 00:25:41,060 for a victim that I did not control. 417 00:25:41,060 --> 00:25:42,880 I encrypted the contents, 418 00:25:43,020 --> 00:25:44,560 sent it to their token endpoint, 419 00:25:45,020 --> 00:25:46,440 and then got back an ID token 420 00:25:46,440 --> 00:25:48,840 for that fake victim user. 421 00:25:49,480 --> 00:25:50,400 And so we're, 422 00:25:50,400 --> 00:25:51,640 here we are back at the beginning again. 423 00:25:52,200 --> 00:25:54,460 This is one of a couple ID tokens 424 00:25:54,460 --> 00:25:55,640 I was playing around with. 425 00:25:55,940 --> 00:25:58,100 If you look at the actual contents in there, 426 00:25:58,240 --> 00:25:59,580 the email address is 427 00:26:00,400 --> 00:26:01,940 alice.bob at example.com. 428 00:26:02,060 --> 00:26:03,460 I don't own that domain. 429 00:26:04,120 --> 00:26:05,280 Don't have access to that account. 430 00:26:05,440 --> 00:26:07,780 Nor do I actually think it's a bug bounty researcher. 431 00:26:08,640 --> 00:26:10,420 And I also, for kicks, 432 00:26:11,060 --> 00:26:13,280 added an additional parameter defcon31 in there 433 00:26:13,280 --> 00:26:15,920 just to show that you can just inject whatever, 434 00:26:16,380 --> 00:26:18,180 whatever sort of claims you would want 435 00:26:18,180 --> 00:26:19,420 into your ID token. 436 00:26:20,700 --> 00:26:22,180 So, if you're sitting in the audience 437 00:26:22,180 --> 00:26:23,220 and want to verify this, 438 00:26:24,720 --> 00:26:25,800 I haven't checked today. 439 00:26:26,140 --> 00:26:28,580 But the, I believe that the public key associated 440 00:26:28,580 --> 00:26:30,780 with these ID tokens is still the same. 441 00:26:31,140 --> 00:26:33,700 And you can just view it online and decode it 442 00:26:33,700 --> 00:26:35,900 and validate that this is a real token. 443 00:26:38,660 --> 00:26:41,040 So, what do you do with these tokens, right? 444 00:26:41,720 --> 00:26:43,980 Well, on this domain, 445 00:26:44,180 --> 00:26:46,460 probably one of the most interesting things 446 00:26:46,460 --> 00:26:48,540 you want to do is list vulnerability reports, right? 447 00:26:49,600 --> 00:26:52,040 So, I went through the legwork 448 00:26:52,040 --> 00:26:55,880 of constructing an ID token 449 00:26:55,880 --> 00:26:57,180 with the least, 450 00:26:57,800 --> 00:26:59,860 the smallest set of claims that I needed 451 00:26:59,860 --> 00:27:03,600 to list vulnerabilities for a user. 452 00:27:04,320 --> 00:27:05,880 So, I can't zoom in here, 453 00:27:05,980 --> 00:27:07,640 but if you look at the decoded section, 454 00:27:07,920 --> 00:27:10,520 there are actually a bunch of the fields 455 00:27:10,520 --> 00:27:11,260 that are zeroed out, 456 00:27:11,340 --> 00:27:13,680 essentially meaning that I can craft the token, 457 00:27:14,580 --> 00:27:16,900 just put in dummy values for a couple of them, 458 00:27:17,330 --> 00:27:18,760 and it'll still validate for, 459 00:27:19,620 --> 00:27:21,400 and you can use it for any account. 460 00:27:22,080 --> 00:27:24,300 There are a couple non-random values in there, 461 00:27:24,380 --> 00:27:24,660 I'll grant. 462 00:27:25,580 --> 00:27:27,560 However, again, if you just look at your 463 00:27:27,560 --> 00:27:30,100 sort of burp history as you're running this attack, 464 00:27:30,400 --> 00:27:32,960 you'll see that the audience and tenant ID values 465 00:27:32,960 --> 00:27:35,420 are just, they're in public information, right? 466 00:27:35,500 --> 00:27:36,760 They're in like client-side JavaScript, 467 00:27:37,460 --> 00:27:40,240 URL headers or HTTP headers, stuff like that. 468 00:27:40,520 --> 00:27:43,800 So, they're not hidden values to find, 469 00:27:43,880 --> 00:27:45,040 they're actually just public. 470 00:27:49,600 --> 00:27:51,540 So, I could essentially use this 471 00:27:51,540 --> 00:27:54,300 to list any vulnerability submissions 472 00:27:54,300 --> 00:27:57,360 knowing only a user's email account, right? 473 00:27:58,200 --> 00:27:59,960 Likely, these are things like, you know, 474 00:27:59,980 --> 00:28:01,500 Windows, Azure Exchange, Zero Days 475 00:28:01,500 --> 00:28:03,560 that people have submitted that are not yet patched. 476 00:28:03,960 --> 00:28:06,120 I'm sure that, as with any bug bounty program, 477 00:28:06,260 --> 00:28:08,000 there's a bunch of junk submissions that are in there 478 00:28:08,500 --> 00:28:10,340 that you'd have to wade through, 479 00:28:10,520 --> 00:28:13,840 but, you know, knowing if you wanted to use this 480 00:28:13,840 --> 00:28:15,460 and knew a security researcher's email, 481 00:28:16,540 --> 00:28:18,780 odds are you could've used it at the time. 482 00:28:20,080 --> 00:28:22,440 For this environment, you could've also done things like, 483 00:28:22,440 --> 00:28:24,460 you know, change their payment processor ID, 484 00:28:24,560 --> 00:28:26,920 so essentially stolen all the bounties they would've gotten, 485 00:28:27,040 --> 00:28:29,760 but I'm sure that would've, you know, been picked up 486 00:28:29,760 --> 00:28:31,080 as they wouldn't have gotten paid. 487 00:28:33,300 --> 00:28:33,700 Okay. 488 00:28:35,600 --> 00:28:37,840 So, how does this story end, right? 489 00:28:37,840 --> 00:28:41,460 So, really, the crux of this issue 490 00:28:41,460 --> 00:28:43,920 is the crypto vulnerability, right? 491 00:28:44,340 --> 00:28:46,760 It does seem sort of a bit silly to me 492 00:28:46,760 --> 00:28:48,540 to devise a side-channel attack 493 00:28:48,540 --> 00:28:51,000 to recover a public value that should've been public 494 00:28:51,000 --> 00:28:51,680 in the first place, 495 00:28:52,420 --> 00:28:54,580 but, you know, I think in this case, 496 00:28:54,640 --> 00:28:56,280 it was very critical to do this 497 00:28:56,280 --> 00:28:59,460 to get the issue understood 498 00:28:59,460 --> 00:29:01,180 and taken seriously, right? 499 00:29:02,220 --> 00:29:04,620 And in general, I sort of believe that, you know, 500 00:29:05,880 --> 00:29:07,540 crypto vulnerabilities and misuse 501 00:29:07,840 --> 00:29:09,220 can often be misunderstood. 502 00:29:09,560 --> 00:29:10,540 You know, people will see it and say, 503 00:29:10,580 --> 00:29:12,660 oh, that's just some crypto bug that's theoretical 504 00:29:12,660 --> 00:29:14,120 and never going to be able to do it. 505 00:29:16,080 --> 00:29:18,220 I wrote a blog post which talks about 506 00:29:18,680 --> 00:29:20,120 essentially part one of this talk, 507 00:29:20,720 --> 00:29:22,800 not the side-channel attack. 508 00:29:23,240 --> 00:29:24,600 It's on our company blog. 509 00:29:26,320 --> 00:29:28,200 I'd say at this point, 510 00:29:28,680 --> 00:29:31,620 my recommendation to users of Azure B2C 511 00:29:31,620 --> 00:29:34,980 would be to, instead of using that RSA 512 00:29:36,480 --> 00:29:37,260 asymmetric encryption, 513 00:29:37,840 --> 00:29:39,680 switch to the secret encryption with AES. 514 00:29:40,180 --> 00:29:41,960 I believe Microsoft's still working on it, 515 00:29:42,040 --> 00:29:44,000 but I think they're going to put out a change 516 00:29:44,000 --> 00:29:45,640 that should make it sort of straightforward 517 00:29:45,640 --> 00:29:46,780 to make that change. 518 00:29:47,520 --> 00:29:48,840 And, you know, if you do that, 519 00:29:48,880 --> 00:29:51,040 essentially that lack of integrity 520 00:29:51,040 --> 00:29:52,480 that you get with asymmetric encryption 521 00:29:52,480 --> 00:29:55,200 can just be replaced with the integrity 522 00:29:55,200 --> 00:29:56,620 you do get with symmetric encryption 523 00:29:56,620 --> 00:29:58,740 so that it would sort of negate this altogether. 524 00:30:00,520 --> 00:30:04,080 Long-term, I think my suggestion to Microsoft 525 00:30:04,080 --> 00:30:07,400 was to use nested JWTs, as I mentioned earlier, 526 00:30:08,540 --> 00:30:10,400 this is, you know, I recognize 527 00:30:10,400 --> 00:30:12,260 that it's a sort of hard engineering problem 528 00:30:13,780 --> 00:30:16,160 and changing the structure of something 529 00:30:16,160 --> 00:30:18,380 that sort of underpins your whole authentication flow 530 00:30:18,380 --> 00:30:19,880 is not an easy change, right? 531 00:30:20,280 --> 00:30:22,680 So, at the very least, 532 00:30:23,240 --> 00:30:25,180 if I was remitting this bug myself, 533 00:30:25,360 --> 00:30:28,800 it would essentially invalidate all keys 534 00:30:28,800 --> 00:30:30,300 for all sessions for all users, right? 535 00:30:30,360 --> 00:30:33,720 And so the usability alone would be sort of horrendous. 536 00:30:33,860 --> 00:30:36,800 But I think long-term, that's what you need to do. 537 00:30:36,800 --> 00:30:39,600 And I believe Microsoft is working toward 538 00:30:39,600 --> 00:30:42,720 doing something analogous to nested JWTs 539 00:30:42,720 --> 00:30:44,120 for their platform. 540 00:30:48,560 --> 00:30:50,440 So, disclosure part two, right? 541 00:30:50,500 --> 00:30:54,580 So, in July 22, 2022, about a year ago, 542 00:30:54,740 --> 00:30:56,220 I discovered the Sinai channel attack 543 00:30:56,630 --> 00:30:57,960 and disclosed it to Microsoft. 544 00:30:58,960 --> 00:31:06,520 There was a period of not great responses 545 00:31:06,800 --> 00:31:07,860 for a little while, 546 00:31:08,040 --> 00:31:10,260 but I did manage to talk to the team 547 00:31:10,260 --> 00:31:12,480 and, you know, get them to validate the issue. 548 00:31:12,680 --> 00:31:14,980 And the first of two fixes 549 00:31:14,980 --> 00:31:17,040 was put in place in December 2022. 550 00:31:17,460 --> 00:31:19,560 And essentially what that fix does 551 00:31:19,560 --> 00:31:23,000 is that now, if you submit a token that is invalid 552 00:31:23,660 --> 00:31:24,580 of any format, 553 00:31:25,560 --> 00:31:28,180 your HTTP request will essentially just get dropped. 554 00:31:28,840 --> 00:31:29,900 It will... 555 00:31:29,900 --> 00:31:31,960 The connection will hang, it won't return. 556 00:31:32,260 --> 00:31:33,960 And so essentially what happens is 557 00:31:33,960 --> 00:31:35,940 you get no timing information, right? 558 00:31:36,800 --> 00:31:39,560 There's no timing attack to recover that key 559 00:31:39,560 --> 00:31:40,220 in the first place. 560 00:31:41,060 --> 00:31:42,960 This is a good sort of stopgap measure 561 00:31:42,960 --> 00:31:45,640 because it sort of negates the attack 562 00:31:45,640 --> 00:31:46,740 as I described it. 563 00:31:47,640 --> 00:31:49,540 But it doesn't go as far as putting 564 00:31:49,540 --> 00:31:50,920 all the nested stuff in place. 565 00:31:51,760 --> 00:31:55,380 That second part was planned for February 2023, 566 00:31:55,660 --> 00:31:58,280 but there were some engineering complications 567 00:31:58,280 --> 00:31:59,780 as I sort of... 568 00:31:59,780 --> 00:32:01,240 As I understand it. 569 00:32:01,300 --> 00:32:03,160 I really don't know a lot of details about those. 570 00:32:03,280 --> 00:32:05,380 But that fix wasn't quite put into place 571 00:32:07,920 --> 00:32:08,480 until February 2022. 572 00:32:08,480 --> 00:32:10,640 This is sort of the disclosure timeline 573 00:32:10,640 --> 00:32:14,460 from July to February 574 00:32:14,460 --> 00:32:16,280 when I published that blog post. 575 00:32:17,880 --> 00:32:20,300 You can look at the slides in your own time 576 00:32:20,300 --> 00:32:21,440 on the DEF CON media server, 577 00:32:21,580 --> 00:32:24,520 but essentially it shows sort of back and forth 578 00:32:24,520 --> 00:32:26,980 in what was happening with different parties at Microsoft. 579 00:32:30,020 --> 00:32:31,940 The risk rating for this vulnerability 580 00:32:31,940 --> 00:32:35,420 was assigned important, not critical. 581 00:32:35,420 --> 00:32:38,820 I personally argue that if all you need 582 00:32:38,820 --> 00:32:40,880 is sort of tenant details and an email address 583 00:32:40,880 --> 00:32:43,660 and what you get out of it is full compromise of a victim, 584 00:32:43,880 --> 00:32:45,880 that's going to be a critical vulnerability rate. 585 00:32:46,600 --> 00:32:48,540 It doesn't seem like just something important. 586 00:32:49,140 --> 00:32:50,280 But I digress. 587 00:32:50,680 --> 00:32:54,080 It was also categorized as info disclosure, 588 00:32:54,280 --> 00:32:55,300 not elevation of privilege. 589 00:32:56,920 --> 00:32:59,420 Surely, yes, a public key was disclosed, 590 00:32:59,440 --> 00:33:00,360 so maybe by definition 591 00:33:01,280 --> 00:33:03,080 that is the right way to categorize it. 592 00:33:03,700 --> 00:33:05,400 But again, I sort of argue that it's not 593 00:33:05,420 --> 00:33:07,060 a way that you're recovering a key 594 00:33:07,060 --> 00:33:09,480 that you can use to grant yourself privileges 595 00:33:09,480 --> 00:33:10,380 to anything you want. 596 00:33:10,540 --> 00:33:13,140 So maybe it falls into the latter category. 597 00:33:17,140 --> 00:33:19,280 Unfortunately, at disclosure time, 598 00:33:19,480 --> 00:33:21,700 Microsoft had two bug bounty programs 599 00:33:21,700 --> 00:33:22,900 that might have applied. 600 00:33:23,400 --> 00:33:25,680 There was the Microsoft Azure Bounty Program 601 00:33:25,680 --> 00:33:27,380 and the Microsoft Identity Bounty Program. 602 00:33:27,620 --> 00:33:30,380 So it turns out this bug was not eligible 603 00:33:30,380 --> 00:33:33,620 for the Azure one because it isn't an identity service. 604 00:33:34,240 --> 00:33:35,400 It also turns out 605 00:33:35,420 --> 00:33:38,180 that it's not eligible for the identity program 606 00:33:38,180 --> 00:33:41,440 because this bdclogin.com was not in scope 607 00:33:41,440 --> 00:33:42,720 for that program. 608 00:33:43,040 --> 00:33:46,660 So despite being a somewhat important bug 609 00:33:46,660 --> 00:33:48,580 for this service that they're using internally, 610 00:33:49,280 --> 00:33:52,240 it is ineligible for any bounty program, 611 00:33:52,380 --> 00:33:53,440 so it was not rewarded. 612 00:33:54,300 --> 00:33:55,980 I will say to Microsoft's credit 613 00:33:55,980 --> 00:33:58,580 and some lengthy back and forth I've had with them since, 614 00:33:58,800 --> 00:34:01,700 they have added Azure B2C to their identity program 615 00:34:02,220 --> 00:34:04,840 in the intervening time in July or June, 616 00:34:04,840 --> 00:34:05,480 a couple months ago, 617 00:34:06,640 --> 00:34:08,960 but bounties are not sort of retroactive, 618 00:34:09,060 --> 00:34:11,260 so it's not gonna get paid out. 619 00:34:15,120 --> 00:34:17,380 So the last slide here on Microsoft, 620 00:34:18,020 --> 00:34:21,320 there are some lingering remediations I mentioned. 621 00:34:22,640 --> 00:34:25,320 The first fix that I mentioned in December 622 00:34:25,840 --> 00:34:27,220 was kind of narrow, right? 623 00:34:27,300 --> 00:34:31,560 It was cutting off just the timing attack itself. 624 00:34:33,080 --> 00:34:34,280 So it's unclear 625 00:34:34,840 --> 00:34:36,800 if there are other artifacts in that session 626 00:34:36,800 --> 00:34:38,880 that you could use to still recover a key, right? 627 00:34:39,080 --> 00:34:42,740 If they're terminating a connection or whatever, right? 628 00:34:43,280 --> 00:34:44,680 And I was sort of inspired 629 00:34:44,680 --> 00:34:46,140 by James Kettle's talk this morning, 630 00:34:46,680 --> 00:34:50,280 talking about his tools to do similar things. 631 00:34:50,440 --> 00:34:52,760 So it may be possible to get around this mitigation, 632 00:34:53,800 --> 00:34:55,620 but I haven't really found any way. 633 00:34:57,200 --> 00:35:00,320 I also haven't checked quite yet today, 634 00:35:00,400 --> 00:35:04,740 but I think they are actually going to encourage users 635 00:35:04,740 --> 00:35:05,940 to use the secret key generation 636 00:35:05,940 --> 00:35:10,040 instead of the public key or the RSA key generation. 637 00:35:11,760 --> 00:35:13,200 And as I mentioned, 638 00:35:13,280 --> 00:35:14,920 the new sign element in the refresh tokens 639 00:35:14,920 --> 00:35:16,780 isn't quite implemented yet, 640 00:35:16,880 --> 00:35:19,480 but I think they're still working toward that. 641 00:35:21,960 --> 00:35:22,480 Okay. 642 00:35:23,680 --> 00:35:25,720 So just for the DEF CON audience here, 643 00:35:26,280 --> 00:35:28,140 so most of this talk is focused on 644 00:35:28,500 --> 00:35:30,460 an identity service for Microsoft, 645 00:35:31,120 --> 00:35:32,600 but looking at other vendors 646 00:35:32,600 --> 00:35:34,720 and other OAuth implementations, 647 00:35:34,740 --> 00:35:36,940 you might find similar things. 648 00:35:39,160 --> 00:35:43,000 So AWS has a AWS Cognito. 649 00:35:43,400 --> 00:35:45,680 It's a service very similar to Azure B2C. 650 00:35:45,780 --> 00:35:47,620 It is an identity service. 651 00:35:47,920 --> 00:35:49,580 It has a similar login flow. 652 00:35:49,940 --> 00:35:51,180 You get a refresh token. 653 00:35:51,440 --> 00:35:52,840 And if you decode the headers, 654 00:35:53,000 --> 00:35:56,040 you'll actually notice that the encryption algorithm 655 00:35:56,040 --> 00:35:57,920 is, again, RSA OAEP. 656 00:35:59,480 --> 00:36:02,380 I wouldn't put this up here to, you know, 657 00:36:02,380 --> 00:36:03,960 if I thought this was really a bug, 658 00:36:04,060 --> 00:36:04,720 but it is. 659 00:36:04,740 --> 00:36:06,540 It is interesting that they use this. 660 00:36:07,560 --> 00:36:10,580 I don't have the same introspection in AWS 661 00:36:10,580 --> 00:36:12,800 that I do in Azure. 662 00:36:13,020 --> 00:36:14,720 Particularly, I can't, you know, 663 00:36:14,720 --> 00:36:16,900 specify my own keys and upload them and use them. 664 00:36:17,060 --> 00:36:18,680 So I can't actually see what the contents are, 665 00:36:18,800 --> 00:36:21,180 but, you know, external indicators suggest 666 00:36:21,180 --> 00:36:23,520 that they're actually using nested JWTs, 667 00:36:23,580 --> 00:36:25,360 so they're likely not a, 668 00:36:26,560 --> 00:36:28,100 it's likely not an issue for AWS. 669 00:36:28,320 --> 00:36:31,260 But it is interesting that they have designed 670 00:36:31,260 --> 00:36:33,680 a very similar flow to what you see 671 00:36:33,680 --> 00:36:35,820 in Azure. 672 00:36:37,820 --> 00:36:38,360 That's all I got. 673 00:36:48,860 --> 00:36:50,220 Yeah, I have a little time, 674 00:36:50,260 --> 00:36:51,280 so I'll take some questions, 675 00:36:51,380 --> 00:36:52,360 or if you want to find me after, 676 00:36:52,440 --> 00:36:53,240 that's fine as well. 677 00:36:53,420 --> 00:36:54,640 So we have some mics here. 678 00:36:54,800 --> 00:36:55,720 If you have questions, 679 00:36:55,820 --> 00:36:56,820 please line up at the mics. 680 00:36:58,520 --> 00:36:59,380 If you have questions, 681 00:36:59,520 --> 00:37:00,500 please line up at the mics. 682 00:37:05,260 --> 00:37:05,600 Okay. 683 00:37:06,060 --> 00:37:06,820 Oh, hold on. 684 00:37:08,780 --> 00:37:09,960 I think they got to heat it. 685 00:37:13,160 --> 00:37:14,740 Give us a thumbs up, thumbs down. 686 00:37:16,100 --> 00:37:16,540 Thumbs up. 687 00:37:19,480 --> 00:37:20,080 Try it now. 688 00:37:22,160 --> 00:37:24,540 I'm not touching it because here's somebody. 689 00:37:25,100 --> 00:37:26,120 Hello? Okay. 690 00:37:26,480 --> 00:37:29,560 Hey, have you tested this? 691 00:37:29,620 --> 00:37:30,020 We can't hear you. 692 00:37:30,380 --> 00:37:31,260 Cut over to that mic. 693 00:37:31,540 --> 00:37:32,300 No, go ahead, you. 694 00:37:33,680 --> 00:37:34,140 Go ahead, go ahead. 695 00:37:34,260 --> 00:37:34,420 Go ahead. 696 00:37:35,000 --> 00:37:36,320 Have you tested this functionality 697 00:37:36,320 --> 00:37:38,540 against anything else besides the B2C? 698 00:37:40,880 --> 00:37:43,440 So Microsoft, for other things 699 00:37:43,440 --> 00:37:45,000 like the Microsoftonline.com, 700 00:37:45,180 --> 00:37:46,160 they have a different, 701 00:37:46,240 --> 00:37:49,140 a Webflow that is completely segmented. 702 00:37:49,160 --> 00:37:50,500 It looks like a different code base, right, 703 00:37:51,500 --> 00:37:52,300 from B2C. 704 00:37:52,380 --> 00:37:53,820 So it seems different in that respect. 705 00:37:54,400 --> 00:37:56,640 I haven't done a, you know, 706 00:37:56,640 --> 00:37:57,700 scoured the internet for every service, 707 00:37:57,800 --> 00:37:59,500 but I've looked at a couple, yeah. 708 00:38:00,260 --> 00:38:02,160 Take a look at the Azure shared tenants. 709 00:38:02,160 --> 00:38:03,040 All right. 710 00:38:07,120 --> 00:38:07,820 Hey, hello. 711 00:38:08,140 --> 00:38:08,600 Hi. 712 00:38:09,120 --> 00:38:13,260 I saw a couple of references to the MSRC kid, 713 00:38:13,500 --> 00:38:15,800 and I was wondering if you managed to meet them 714 00:38:15,800 --> 00:38:17,000 as a result of the disclosure. 715 00:38:17,680 --> 00:38:18,600 If I what? 716 00:38:18,940 --> 00:38:20,440 The MSRC kid. 717 00:38:20,660 --> 00:38:20,860 Yeah. 718 00:38:20,940 --> 00:38:22,580 I wondered if you managed to meet them 719 00:38:22,580 --> 00:38:23,400 as a result of the disclosure. 720 00:38:23,400 --> 00:38:23,460 Oh, yes. 721 00:38:23,600 --> 00:38:26,280 Yeah, he had a fun and interesting name there. 722 00:38:27,420 --> 00:38:29,000 This is a fantastic vulnerability. 723 00:38:29,320 --> 00:38:31,620 I've done a lot of research into OpenID Connect 724 00:38:31,620 --> 00:38:32,340 based vulnerabilities, 725 00:38:32,720 --> 00:38:35,380 and the cryptography is especially interesting. 726 00:38:35,720 --> 00:38:39,080 You know, we've moved over the past five years 727 00:38:39,080 --> 00:38:41,700 into a world where people are no longer entirely 728 00:38:41,700 --> 00:38:43,000 home-rolling their crypto, 729 00:38:43,120 --> 00:38:46,240 but taking it from off-the-shelf JWK configurations. 730 00:38:46,660 --> 00:38:48,040 And as a result, 731 00:38:48,080 --> 00:38:51,200 now we have generally applicable crypto vulnerabilities 732 00:38:51,200 --> 00:38:53,760 without having to meet an engineer 733 00:38:53,760 --> 00:38:55,040 and ask them, you know, 734 00:38:55,060 --> 00:38:57,640 how did you think you put this crypto system together? 735 00:38:57,960 --> 00:38:58,560 Yeah, exactly. 736 00:38:58,580 --> 00:38:59,820 I just thought it was super interesting. 737 00:39:00,080 --> 00:39:00,600 Thanks. 738 00:39:01,620 --> 00:39:02,000 Right. 739 00:39:02,140 --> 00:39:05,200 Going after the one implementation 740 00:39:05,200 --> 00:39:06,680 that rules a bunch of different applications 741 00:39:06,680 --> 00:39:08,940 is going to get you a beer bang for your buck for sure. 742 00:39:08,980 --> 00:39:09,820 I did have one question 743 00:39:09,820 --> 00:39:11,440 that wasn't a joke or a compliment, though. 744 00:39:11,580 --> 00:39:11,900 Okay. 745 00:39:12,240 --> 00:39:13,600 You mentioned the... 746 00:39:13,600 --> 00:39:16,820 So I've done some time attack-based attacks, 747 00:39:17,080 --> 00:39:19,380 and they seem very rudimentary by comparison. 748 00:39:19,600 --> 00:39:21,000 You mentioned the backtracking. 749 00:39:21,220 --> 00:39:21,620 What exactly... 750 00:39:22,300 --> 00:39:24,020 Could you elaborate on what backtracking means 751 00:39:24,020 --> 00:39:25,160 in the context of the attack? 752 00:39:25,400 --> 00:39:25,540 Yeah. 753 00:39:25,600 --> 00:39:26,480 I sort of... 754 00:39:27,120 --> 00:39:28,920 I kind of made it up as I went along. 755 00:39:29,040 --> 00:39:29,680 But essentially, 756 00:39:29,680 --> 00:39:32,540 if, you know, 757 00:39:32,540 --> 00:39:33,480 as I was running the attack 758 00:39:33,480 --> 00:39:36,500 and I noticed that there was no actual timing differential 759 00:39:36,500 --> 00:39:37,760 in, you know, 760 00:39:37,760 --> 00:39:39,280 in this current round that I was on, 761 00:39:39,820 --> 00:39:41,760 it seemed likely that, you know, 762 00:39:41,760 --> 00:39:43,920 a lack of any timing differential meant that 763 00:39:44,660 --> 00:39:46,020 all of my, you know, 764 00:39:46,040 --> 00:39:48,120 high, mid, and low points were all in this... 765 00:39:48,120 --> 00:39:50,860 either all higher than n or less than n. 766 00:39:50,960 --> 00:39:51,180 So... 767 00:39:51,620 --> 00:39:52,260 I see. 768 00:39:52,340 --> 00:39:54,460 Basically using a crude measurement 769 00:39:54,460 --> 00:39:57,620 for just detecting that I'm no longer progressing, right? 770 00:39:57,660 --> 00:39:58,640 I need to go backwards. 771 00:39:58,880 --> 00:39:59,160 Yeah. 772 00:39:59,160 --> 00:40:01,760 The confidence mathematics is very annoying 773 00:40:01,760 --> 00:40:03,560 to have to deal with when you're doing a timing attack. 774 00:40:03,840 --> 00:40:04,280 Thank you. 775 00:40:04,340 --> 00:40:04,660 Yeah. 776 00:40:04,700 --> 00:40:05,120 Thank you. 777 00:40:08,240 --> 00:40:08,660 All right. 778 00:40:08,680 --> 00:40:09,040 Thank you all.