Rating:

The challenge page is a true script kiddie blog - teaching the fine art of sqlmap and armitage. In the developer tools, we notice a cookie has been set:


skidtoken=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImtpZCI6InNraWQifQ.eyJ1c2VybmFtZSI6InNraWQifQ.sacXoUrQCXpaylE4a4RGrCawHqBJJVGfOozOaPxQqOo

The JWT token decodes to the header

 json
{
"typ": "JWT",
"alg": "HS256",
"kid": "skid"
}

and the body

 json
{
}


The kid field in the header represents a key identifier. The key identifier is used to let the server know which key has been used to sign the token. This is very useful for instance when the token issuing server rotates keys. This allows for a grace period where tokens that have issued right before the key rotation can still be validated by the server after the key rotation. The key identifier is also useful for simply having many different keys at the same time.

Anyway, this key identifier can often represent a key in a jwks.json file, a regular file or a key in a database. We can look for a publicly available jwks-file. We try a few different files:
* jwks.json
* /.well-known/jwks.json
* skid.json
* skid

and a few permutations of those, but no luck. Let's instead try to look for a sql injection. We can just modify our token with for instance the tool on jwt.io. Remember that since the kid field is used to look for the key used for the signature, we do not need to provide a valid signature now. Let's just change the kid to skid' and see if we can trigger an error. Change the cookie value in developer tools and refresh the page.



(sqlite3.OperationalError) unrecognized token: "'skid''"
[SQL: select * from key where name like 'skid'']
(Background on this error at: http://sqlalche.me/e/13/e3q8)


Nice, the key is stored in a sqlite db and we have a sql injection vulnerability! We can now use a union to choose our own key by effectivly changing the query to

 sql
select * from key where name like 'a key that does not exist'
union
select <our key>


But first we need to detect how many fields there are in the table. A few tries gives us the correct number of columns. The final payload for our kid field is asdbqweqwe' union select 'a','a','a. As we have replaced all fields of the key with a's we can forge our token in jwt.io setting the secret to a and the username field in the body to admin.

![SQL injection in jwt kid field in jwt.io][forging-token]

Updating our cookie with the forged token and refreshing the page reveals our flag.

[forging-token]: https://lorentzvedeler.com/assets/imgs/jwt-with-sqli.png "SQL injection in jwt kid field in jwt.io"

Original writeup (https://lorentzvedeler.com/writeup/2020/09/26/bsidesbos-web/).