SECCON CTF for Beginners 2022 Web 「Ironhand」Writeup
はじめに
ctf4bおつかれさまでした。運営の皆様もいつもありがとうございます。 IronhandのWriteupがぱっと見なかったので書きます。
score.beginners.azure.noc.seccon.jp
概要
- ログインするとJWTが与えられる
- IsAsminをtrueにしたJWTを持っている状態だと、flagが閲覧できる
- 署名はappの環境変数JWT_SECRET_KEYによって行われている
- appの
/static
APIにはディレクトリトラバーサル脆弱性があり、これを利用して/proc/self/environ
にアクセスし、JWT_SECRET_KEYを手に入れる
詳細
何もせずログインすると以下のような画面が表示されます。
Cookieとして付与されたJWTをデコードすると、IsAdminがfalseです。
appのコードのこの辺を読むと、このIsAdminがtrueならflagが表示される事がわかります。
if claims.IsAdmin { res, _ := http.Get("http://secret") flag, _ := ioutil.ReadAll(res.Body) if err := res.Body.Close(); err != nil { return c.String(http.StatusInternalServerError, "Internal Server Error") } return c.Render(http.StatusOK, "admin", map[string]interface{}{ "username": claims.Username, "flag": string(flag), }) }
同じくappのコードの以下の部分、本来ならstatic/以下のファイルを探すためのコードっぽいですが、パストラバーサルに利用できそうな気がします。Nginxの設定ファイルに見慣れないオプション(merge_slashes off;)があることも気になります。
e.GET("/static/:file", func(c echo.Context) error { path, _ := url.QueryUnescape(c.Param("file")) f, err := ioutil.ReadFile("static/" + path) if err != nil { return c.String(http.StatusNotFound, "No such file") } return c.Blob(http.StatusOK, mime.TypeByExtension(filepath.Ext(path)), []byte(f)) })
色々試してみると、以下のようにパストラバーサル脆弱性があることが分かりました。
脆弱性を利用して/proc/self/environへアクセスすることで、そのプロセスの環境変数を確認します。
JWT_SECRET_KEYが含まれています。
ここで得たJWT_SECRET_KEYを使って、IsAdminがtrueなJWTを作成します。画像のすぐ下に秘密鍵を入力するフォームがあるので、JWT_SECRET_KEYの値を入力します。「secret base64 encoded」はチェックしません。
出力されたJWTをブラウザのクッキーとして設定して更新すると、flagが表示された画面に遷移します。