調査
Sign InとSign Upができる。
アカウントを作って、ログインすると、挨拶できるページがある。
/say-hi
-> You are simple user.
adminユーザーで挨拶すればよさそう。
Proxy履歴を見てみよう。 それほど気になる部分もない。 タイトルにもあるようにJWTが使われているのでCookieに着目してみよう。
Cookie
token=eyJraWQiOiJIUzI1NiIsImFsZyI6IkhTMjU2In0.eyJqa3UiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvc2VjcmV0IiwiZXhwIjoxNjE3NTE2NjQ2LCJqdGkiOiJydU9Gend4S3E0ZWFNM2Q5OEN2dWxRIiwiaWF0IjoxNjE2OTExODQ2LCJuYmYiOjE2MTY5MTE3MjYsInN1YiI6ImV2aWxtYW4ifQ.v-nrjUjhjgdd5JNIi14KwXx5YpFwrqbKJ4s_CSC96t4 JSESSIONID=DE2FB55273E90C1D401C2EE1793BD917
JSESSIONIDは一旦無視して、tokenの中身を見る。
{ "kid": "HS256", "alg": "HS256" } . { "jku": "http://localhost:8080/secret", "exp": 1617516646, "jti": "ruOFzwxKq4eaM3d98CvulQ", "iat": 1616911846, "nbf": 1616911726, "sub": "evilman" } . 署名
/secret
へアクセスしてみたが403 Forbiddenだった。
jwks spoofingだろう
jwks spoofing
jku部分を自前のものに変更して、秘密鍵を差し替えよう。 How to generate a JSON Web Key (JWK) | Connect2id ここを参考にして、以下のように作って、公開する。
{ "kty" : "oct", "kid" : "HS256", "k" : "FdFYFzERwC2uCBB46pZQi4GG85LujR8obt-KWRBICVQ" }
鍵がkになるので、これを署名時に使ってJWSを作る。
後は、subをadminにして、jwt.ioでトークンを作り直す。
注意として、「secret base64 encoded」にチェックを入れること。
作ったJWTトークンを渡して/say-hi
を見ればフラグゲット。
VolgaCTF{jW5_jku_5u85T1TUt10n}
余談
RFC的にはjkuはHEADERに入っているべきだと思うが、これは正しい解釈? 別にPayloadに入っていてもいいのか?