
This lessons asks us to delete Tom’s account, let’s go ahead and press “Delete” on Tom’s account

The requests is a POST with a JWT token passed as parameter on the URL (GET style), this does not go through as the response feedback and output JSON parameters inform us that the token is not valid as the proposed signature does not match with the computed one

By copy/pasting the JWT token we get from Burp History on to https://jwt.io a number of key-value pairs are unveiled
Of all the keys in the JWT, those that could be interesting are, in my opinion
- kid <- key identifier
- sub <- subject of the JWT
- username
What we are looking to do is to create a valid JWT token, so the “kid” value seems something that needs tampering
WebGoat hints on this lesson tells us to try to manipulate the “kid” parameter by means of a SQL injection, so if “webgoat_key” is an identifier that is used to get an encryption key, it may be possible to force a new key thus creating a new valid token
In fact, in the https://github.com/WebGoat/WebGoat/blob/develop/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/jwt/JWTFinalEndpoint.java file from WebGoat GitHub (cheating here) there is the following SQL query
ResultSet rs = connection.createStatement().executeQuery("SELECT key FROM jwt_keys WHERE id = '" + kid + "'");

So if the passed “kid” value is simply concatenated with the query, injection is possible by using something like the following
something_else' UNION SELECT 'new_key' FROM INFORMATION_SCHEMA.SYSTEM_USERS; --
This form of a SQL injection allows an attacker to impose an arbitrary value, this happens because there is no “something_else” value inside the “jwt_keys” table, so the main query fails to populate the results, hence what is present in the result after the query is run is what has been put as SELECT value for the UNION query.
Moreover it is important to know that the
FROM INFORMATION_SCHEMA.SYSTEM_USERS
statement present in the query is there as the query needs a FROM <any table> statement to be valid, if it was not present the webapp would have returned a more serious java exception about the non-validity of the SQL query

Here a new JWT token is created by filling the details directly on jwt.io

But no luck, the token has not been accepted, nevertheless it is important to notice that what is not working here is the match of the passed signature with the computed signature, just like before, so the format of the JWT token is right

In fact by trying to pass a JWT token with alg: “None” and without signature, the webapp replies with a different error
But still the lesson has not been completed so something is missing.
By going back to the source code for this lesson, just after the query, the key is returned to the calling method by means of a
return TextCodec.BASE64.decode(rs.getString(1));
The key is base64 decoded before it is used to check the JWT claims, so let’s base64 encode our key “new_key” in the SQL injection and try again

Here the JWT token is crafted on jwt.io by using Tom’s details, the base64 encoded key in the JWT header and the clear text key for creating the signature

Paste the JWT token in Burp Repeater /delete endpoint request and the lesson is completed
This concludes WebGoat JWT token 8
I hope you liked it.
PVXs — https://twitter.com/pivixih