← All talks

JWT Parkour by Louis Nyffenegger at BSides Toronto 2023

BSides Toronto29:14143 viewsPublished 2023-11Watch on YouTube ↗
About this talk
Presented on Oct 21 2023. Nowadays, JSON Web Tokens are everywhere. They are used as session tokens, OAuth tokens or just to pass information between applications or microservices. By design, JWT contains a high number of security and cryptography pitfalls that creates interesting vulnerabilities. In this workshop, we are going to learn how to exploit some of those issues. First, we are going to look at the old issues: the none algorithm, guessing/bruteforcing the hmac secret. Then we will look at more recent issues like how an RSA public key can be computed from multiple signatures to exploit algorithm confusion and how the same attack can be done with ECDSA. We will also look at leveraging issues with the kid/jku/x5u. And finally how to leverage CVE-2022-21449 to bypass the signature mechanism.
Show transcript [en]

L hi everyone so my name is Louie uh I'm based in Australia I came to Canada to do a few talks and meet new people I brought way too many swags so if you want kings or stickers just hit me up um as a job I teach web hacking to people and when you teach web hacking once you're done with the top 10 you want some things that are a bit more a bit sexier and part of it but is really important for people who want to find good bugs or people who as part of hacking or as part of application security is crypto engineering and when you want to teach people crypto engineering you need a good format to do

that so either you make one up or you find the perfect one and I found the perfect one the JWT format so JWT is composed of three parts the headers the payload the signature and they separated by a DOT so when you see in your browser in a cookie or in a URL something like that EJ do EJ dot that's most likely a JWT why because e YJ is basic4 of a c bracket and a double quat because JWT are Jon uh web token but where the Jon come from and so heer header and pill are B 64 coded Jon it's actually URL s b 64 coding without padding so there is some weirdish things about it but

nothing more really important and the signature is also B 64 uncoded as part of the header you have two things the type which tells the person receiving the token but it's a JS so just an web signed token and the algorithm uh to tell the receiving part how the token was signed this is what we're going to play with here in this example is it's hs256 for hm 256 you have a lot of different algorithm that are supported uh implement ation support uh some support all of them some support some of them I think by default you need to at least support non and hmx based uh algorithm here we also have the RSA the litic

curve and the PS family PS is kind of RSA with fancy padding um in the body you have again B 64 andc Jon with for example a username roles or over information you also have what JWT calls registered claims which are keywords that are defined in the RFC for JWT for example X for expired uh I add for issued at and you have a lot a few modes when you create a token you create the Json header you basically spun Cod it you create the Json payload you basically cut it then you concatenate them with a DOT and then you sign that part you sign both the header and the body concatenated with a DOT and then on

you have the signature you B 64 uncode it and you openen it with a DOT so that's what you're going to do when you create token as a micros service or as a web application which is a lot more fun is when an application verify a token basically if you do crypto engineering what you want is to limit the number of steps before the crypto kicks in and the number of things some an attacker can do let's see how many there are here so first you split the token in free Parts based on the dot then you basically for decode each part then you pass the just of the header to retrieve and the payload then you retrieve the algorithm

from the decoded header then you verify the signature based on the algorithm from the header which is obviously user controlled because that token comes from an attacker or a normal user and then finally you verify the claims for example to make sure that the token is not expired if you remember what I just say you want to limit the number of steps before the crypto kicks in here it's number number five bad very bad um when as an attacker you're attacking JWT your main goal is to bypass a signature mechanism or find a way to be someone else so that's what we're going to do today um one of the very common issues surprisingly is that people have JWT and

they don't verify the signature some libraries have two methods decode and verify and people use decode because that's the one in the documentation and Cod doesn't verify so that's bad basically you have a signed token you use the signature for security but you don't verify the signature uh or people just forget to reinforce the signature after check dis disabling it in production or something like that for to do some quick testing so very bad so if you're an attacker you get a token you decode and temper with a payload to change your username from hacker to admin and you become admin in the application you don't never need to care about the signature because no no

one is verifying it very easy attack now one that has made a lot of noise uh a few years back a lot of years back actually is the non algorithm so in the slide with the algorithm I talked quickly about nonone and that's something that needs to be implemented by libraries and a lot of people reading the RFC and creating libraries forgot to disable it by default we didn't see the risk in it because it was part of the RFC you need to implement it and basically it tells the person verifying the token but the token is not signed so you don't need to verify the signature because it's not signed it's even better it's like there

shouldn't be a signature um and it's used to be supported by default in a few libraries and it came back again recently in one libraries uh if you still find stuff like that nowadays it's you're very lucky but yeah so what you do as an attacker you get a token you decode the header and change algorithm to none and then you decod Cod and temper with a payload and you keep remove the signature depending on the implementation and you profit so when I submit my talk I did like I've put like six demos and you have no idea how much I regret it now so right now I'm logged in as hacker okay this is my browser I just

logged in inste of like to save a bit time uh I get more tools they developer tools I got a lovely cookie here I can see the E YJ I jump shell we can see the dots so what I'm going to do is decode it uh so we are on the Mac so it's Capital uppercase D so I got this I copy

it all reun code it just by changing the

algorithm obviously now I change that part and what I'm going to do ah is remove the signature copy all of that go back here replace it and reload and I'm still logged in as I care so why did I do that because first instead of trying to see there is an admin account I first try the attack on myself to see if it worked and I know it works because I'm still logged in if the library wasn't supporting none I will be logged out so now that I did the hard part just going to copy the

payload and see here some of the Jon is missing that's because it's URL safe uncoding without padding so let's add the padding equal sign in Bas 64 and now we got the full thing going to copy that and we want to be admin now what we're going to do is not take the equal sign just to remove the padding sorry didn't save it doesn't matter go back here and now I'm logged in as admin and well we've got a key because blah blah blah that's the default things how it works but basically just by changing the algorithm to to none and removing the signature we got a token that still got accepted and then we said that oh I

don't want to be hacker anymore I want to be admin and now we become someone else in the application and right another one is people use uh trivial secret so when you use the HM the strength of the signature depends on the strength of the secret and people do a bad thing is just to put secret as a sec secret or maybe the framework as a hardcoded version that uses secret and the good thing as well with that is that you just get one token then you can spend six month offline cracking it then you get the secret and then you come back with a temper token as someone else and for someone doing incident response

they only see two requests coming from you the first one to get the token and the one as someone else and as people say no logs no crime t c and you can do that with ashcat and so same thing you get a token you brute force it offline so no logs and uh until you get the same signature and then you temper with the payload and you resign the token since you have the secret and you logged in as someone else um algorithm confusion is probably the coolest thing about JWT so lot of text so um when you are an attacker you pick again what algorithm is used by the person receiving a token

and when you sign with hmark you sign with a secret and you verify with a secret when you sign with RSA or EDP curve you sign with a private key and you verify with a public key now let's say I'm a bad guy or bad person I sign the token with hmark using the public key if you think about the source code of the application verifying the token and if you tell this application actually it's an hmac token the code still say verify with the public key because it was using RSA but now since you're telling it to use hmar it's going to verify with hmar still using the public key and that's what algorithm

confusion is about it's very confusing but it's very cool and until recently um two three years ago uh people most people thought you needed to have uh access to the public key to get uh to to exploit this and it's hard to have access to the public key you can find it in documentation because it's public you can maybe a reverse like uh an Android app or an iPhone app but turns out um someone wrote a tool to do it with RSA uh that takes a few token and it's going to uh get the public key from the signature because you can get the uh public key from a signature because the public key is public if you could get

the pr private key from the signature that would be a bigger problem and recently we published something um with AC cdsa because I don't think it was really well known is uh when you sign with uh ecdsa you can recover the public key from the signature and that's how Bitcoin or ethereum work but basically you don't have the public key inside the transaction you just have the signature and they got an extra bit to say uh if it's uh because you extract two public key and they say if it's zero you're going to use the odd one or the even one if it's uh one and so this is how you do it using uh that's probably python yeah in Python

basically you just get the signature you split it and then you take the two part of the signature R and S and because it's ecdsa and then you can basically use most ecdsa most good ecdsa Library other way to recover the public key because it's needed by ethereum or any like most blockchains so you can just recover that and then you sign uh your new header and payload using that key you recovered and you don't forget to change the algorithm to hm and you also change your username to admin um so basically if we look at that uh with ecdsa uh there's a little typo it should be ecdsa here what we're going to do get a

token get a token sign with ecdsa we're going to recover the public key then we're going to decod the and change algorithm from ecdsa to hmar we're going to temper with the payload and we're going to sign the token with the ecdsa key sorry there are two Tyles so if we do that um so we're going to jump so oh we can do I don't know I'm going with time anyway um so with RSA this do it with RSA you just use this little program uh rs2 sign and you give it two tokens and from two tokens it's going to recover uh the public key and even sign new tokens from you for you taking a bit of

time um in the meantime we can do next to it uh [Music] oh so so we got two token from it and uh one of them should be valid so that's with RSA we can copy it uh that's this one so again we go to temper with cookies

yeah and it didn't change your username because by default the tools doesn't do that but if you change your login to admin or whatever it's named and you run it again you're going to get a token that is sign with the public key using hmark and that allows you to exploit the signature confusion um if we go there um so here um the rsa1 is still turning we're going to go to the ecds one

um in here so if we look at the code that's prob yeah again we're just changing the token and then we just use like this like it's part of the library recover public Keys No crypto like that's the good thing about hacking jts is that you don't need to be good at crypto or mathematics and that's oh there is sometimes some incorrect

ping sometimes the library complains about padding

uh no okay I got an issue with padding it used to work anyway sorry for that so here if we go back to ecdsa RSA we reload and we are logged in as another user as admin in the same way if um I go back to my notes sorry no I didn't took the I didn't okay so for ecdsa we can do the same thing and recover the token in the same way uh you will have to trust me on that but that works pretty well if you're not doing demo um

another thing people do is um as part of the header you have uh something named key ID and they use this key ID as an identifier to fetch data on the file system or to uh access a database and say okay this token is signed with key1 123 or this token is signed with uh SL Etc sljt key and they put a full path or information that will put will be put in an es query and what we can do is injecting that parameter and we're going to use that to say okay instead of using uh your secret that is really hard to guess or this key that is really hard to guess get use

that file instead in the case of the file system so for example what you can do is um use a directory traversal so to say instead of using the file name key do uh text use the file name do do do do do do dodev sln which is an empty string which is going to give us an empty string for the key used to sign the token so we know the secret use to sign the token we can create our own token now and we can do the same thing with an S injection and it's even more fun so we what we're going to get we get a token we decut the header and change a key ID with an SQL

injection then we temper with the payload because we want to become another user and then we sign the token using the return value from the SQL injection that's so basically using an S injection not to dump the database just to return a value that is predictable

um

so this is what it looks like so what we are going to do is create a token with a type JWT or algorithm hs256 to say we are using hmac and then in the key ID we using zzzz single code Union select a AA we do that part to make sure everything coming from from the original query uh that we don't control return nothing so we put a dumb value but make sure that uh everything from the un uh original query doesn't return anything and then we put on value and then our secret is a AA so this value here and we sign here with our secret we get a token we can copy it and hope I'm lucky

at this time again you can do a lot of hacking in your browser without any other tool we replace the cookie we reload the page and now we are logged in as admin just because the application took a token fetch basic for decoded everything fetch the key ID use the key ID in an SQL query that SQL query returned a a a AA thanks to injection and then the application use a aa aa the return value from T injection to verify the token and this allow us to become any anyone we want um now there was a really cool bug in last year CV 2022 21449 which is which impacted Java 15 16 17 and

18 basically when you have an ecdsa signature you have two component R and S and if you read Wikipedia or if you're good at crypto uh I read Wikipedia just so you know uh R and S should never ever ever ever ever be zero because it's basically imagine like a big equation where 0o time something equals 0 times something so the signature always return returns true and that's the bug and the good thing is the good thing if malicious person is it didn't depend on the library used it depends on the underlying version of java and people are really good at upgrading their version of java as you probably know that was sarcasm just in

case um so this is basically what it looks like if you want to be like an exploit writer uh you just create use a library named ecdsa you can do it in Python Ruby is much better but uh what you do is uh you use the ecd library you create a signature with both R and S set to zero and then you Bas 64 uncode the you basically URL safe B4 uncode without padding the D version of this signature and you get oh oh the better version the Ruby one so you do the same thing in Ruby if you prefer Ruby just a bit more readable and you get that so if you like have web app running Java with JWT and

you still have logs uh you probably want to grab for that it's a pretty good string to look for to not like if someone tried to explore that um so what we're going to do let's try one more time so I'm currently logged in as test at test.com more tools oh yeah I'm so running out of time going to get kicked out and my cookie disappeared to add to it um so the bad thing with me is I love JWT and I can talk about them for hours as you can probably tell already um so I got my uh token sign with ecdsa I'm removing almost all the signature I copy that part I remove the

rest copy that part get back into my browser change that reload and I'm still logged in as test ASP tab.com

but

um okay I'm copying

that so Java doesn't like it if I don't use eo- NE the Bas 64 decoding doesn't work for some

reason hopefully that's going to work

so a grab for that string if you have like logs from and running Java app and hopefully yeah and that worked so I become another user just because the underlying version of java was inable so you can do like a lot of shenanigans with uh JWT you can play with another head named jku which is to fetch a key from a remote location so you can basically do like a lot of cool stuff because of application sometime doesn't verify the jku or doesn't verify it properly uh so for example like a good one is people uh want to use trusted. example.com but people are terrible at regular expression so trusted the example.com works because they forget to

escape the dot in the regular expression that's a big classic I see like people noding and I'm going to jump jump JP jump and keep a positive note for the end so uh for The Blue Team um Good Luck now use strong keys and secrets make sure you have script but check that none uh doesn't work don't store them in your source code make sure you have key rotation butin it's really set easy to set up at the beginning to put it back at the end is really hard review your libraries and pick one that is simple make sure you check the signature make sure your token expire you don't want to sign things forever so you need to have

token that expire and force the algorithm so manually check the algorithm to make sure it's right um the JWT are complex and kind of insecure by Design they are great great tool to learn like web hacking because like I didn't say anything about mathematic I didn't even show you an equation and we still broke some pretty cool crypto today mostly me but um and they they introduced like JWT like really really really interesting bugs really interesting bug and apply crypto if you hate ma mathematics like me apply crypto is still very fun and you should look into it because yeah it's really cool and thanks for your time everyone and hope you had

fun thanks Lou so we actually have uh despite the time we have some time for questions if anyone wants to ask any questions uh in the orange

shirt

I haven't seen that and I wish I did because that's one of the thing I want to like do see that I haven't seen that in real application so that's why I didn't create like labs to teach people that but that's definitely an area to attack um but Jon passing is usually a lot better than yamal passing and all those formats like if J WT could be worse it would be named y WT and it would be using yam all right uh in the gray

shirt

yep so it's part um I would say so you need the dott definitely because what most Library do is they split on the dots and if they don't find free Parts they're very unhappy so you may find implementation but still let it through but most of the time you need to keep the dot at the end and that's a mistake a lot of people make is like they remove the dot and then get an N oh damn it it doesn't work right any other questions all right just a reminder the um the talks will be on on YouTube at a later date so if you want to go back and review this talk or any other talks at

your own pace uh you can do that in a in a little while so uh thank you so much Louie uh it was a pleasure having you here thank you fting me