This is the first of the two parts to JSON Web Tokens and how to attack them. While the first part talks about what exactly are JSON Web Tokens, their use and their vulnerabilties. While the second part of this writeup would be focusing on attacks.
1. None Algorithm
JWT supports a “none” algorithm. If the application fails to verify the value of “alg” header, then we can change its value to “none” and in this way it omits the need of a valid signature for verification and also you may leave the signature blank.
This data is base64 encoded and is the part before the first dot of any JWT. The
alg field here indicates the algorithm used to sign the JWT. This type of Bugs allows the attacker to forge any token they want and also impersonate another user by using a forged token.
2. Change algorithm from RS256 to HS256
The algorithm HS256 uses a secret key to sign and verify each message. The algorithm RS256 uses a private key to sign messages, and a public key to verify them. If we change the algorithm from RS256 to HS256, the signature is now verified using the HS256 algorithm using the public key as secret key. Since the public key is not secret at all, we can correctly sign such messages.
Consider the following example code, which could be present at the server:
jwt = JWT.decode(token, public_key)
If the JWT uses asymmetric RS256, this correctly verifies the signature on the token. If the JWT uses symmetric HS256, however, the signature is compared to a HMAC of the token, where the
public_key is used as key. We can thus exploit this vulnerability by signing our own token using HS256 with the public key of the RS256 algorithm.
I used this tool to convert my algorithm from RS256 to HS256
Usage for the tool
RS256_2_HS256_JWT.py [-h] payload pubkeypositional arguments:
payload JSON payload from JWT to attack
pubkey Public key file to use for signingoptional arguments:
-h, --help show this help message and exit
3. Signature not being verified
Sometimes while fuzzing the data in the header and payload section, if the application returned no error, that means that the signature is not being verified after it has been signed by the authorization server. This way we can insert our payload in the claim and the token would still be valid
4. Brute forcing the key
The HS256 algorithm uses a secret key to sign and verify messages. If we know this key, we can create our own signed messages. If the key is not sufficiently strong it may be possible to break it using a brute-force or dictionary attack. By trying a lot of keys on a JWT and checking whether the signature is valid we can discover the secret key. This can be done offline, without any requests to the server, once we have obtained a JWT.
We can gain access to SECRET_KEY file via vulnerabilities like LFI, XXE, SSRF etc. but if that is not possible, then other attacks can still be made to check if the token is using any weak secret string for the encryption.
For cracking the key, a Burpsuite extension called JWT Heartbreaker can also be used
5. Vulnerable Kid
Key ID (kid) is an optional header having a string type which is used to indicate the specific key present in the filesystem or a database and then use its content for verifying the Signature. This parameter is helpful if the Application has multiple keys for signing the tokens, but can be dangerous if it is injectable because then an attacker can point to a specific file which content is predictable.
For example, “/dev/null” is called the null device file and will always return nothing, so it would work perfectly in Unix based systems.
python3 jwt_tool.py <JWT> -I -hc kid -hv "../../dev/null" -S hs256 -p ""
Alternatively, you can use any file present in the web root like CSS or JS and use its content to verify the Signature.
Now these are some basic attacks. There are more advanced attacks like SQL Injection, Local File Intrusion etc. for which you can refer to the following writeup by Kleitonx00.
Please give me your feedback if you find this article helpful.