picoCTF – msfroggenerator2

公開日

投稿者:

カテゴリー:

,

タグ:

picoCTF – msfroggenerator2 より。

教訓

  • サーバ構成と通信の流れを把握する
  • bot を見たらこいつを操作することを考える

構成と通信の流れ

docker-compose.yml を見ると4つのコンテナが起動していて、OpenResty が通信を受け付ける窓口になっていることがわかる。

OpenResty は Nginx + LuaJIT がベースになっており、Lua で柔軟な制御が可能になっている。今回は url 変数を Lua でセットしている。

OpenResty の web.conf を見ると Nginx と同じ構造になっていて、/api/ については Host ヘッダを api に、/report については Host ヘッダを bot に付け替えている。

proxy_pass を見るとどちらも traefik へルーティングしているが Host ヘッダにより負荷分散しているのが traefik の web.yml から見て取れる。

api の web.js を見るとサイトを動かしているときには観測できなかった GET /api/reports/get と POST /api/reports/add の API がある。

bot の web.js を見るとクエリーパラメータ url を受け取って bot.js に渡して起動しているように見える。

bot.js は page.goto(url) で page.screenshot() をとって png を base64 にエンコードして /api/reports/add へ POST で送信している。

/api/reports/add はそれを受け取ってメモリ上の reports 配列に情報を格納している。/api/reports/get でその reports を取得可能。

bot.js ではそのコンテナ内に持っている /flag.txt を読み込んでBearer トークンとして使っている。

攻略の概要

bot.js の page.goto(url) に javascript:~ で javascript のコードを動かし、POST /api/reports/add に対し body を {screenshot: flag} にして投げ込み、その後 GET /api/reports/get で flag をとる。

攻撃のポイント

OpenResty では /report?id=XXX というアクセスに対し、Lua で “http://openresty:8080/?id=XXX” という $url 変数を作り、proxy_pass として “http://traefik:8080/?url=http://openresty:8080/?id=XXX” というアクセスにリバースプロキシする。

/report?id=XXX&url=YYY と渡すと OpenResty で url はそぎ落とされてしまう (id だけ $url に渡るので) が、ここで /report?id=XXX;url=YYY と渡すと OpenResty としては XXX;url=YYY までを id として認識し、それが trafiek まで届く。

trafiek は ; を & に変換するため、(Host ヘッダも bot に変換するため)

https://github.com/traefik/traefik/issues/9164

bot には url=http://openresty:8080/?id=XXX&url=YYY が渡り、URL.searchParams の仕様により後ろの url が利用される。

攻撃コード

以下動画を参照。