これは Daily AlpacaHack B-SIDE の 2026-05-04/07 の 問題 The Sandbox の writeup です。
/flag-(md5 hash of the flag).txtにフラグがあり,root が所有しパーミッションは 400 である/app/app.pyの Flask アプリケーションが root ユーザーで動いている/appディレクトリ自体は root ユーザーが所有し,パーミッションは 1777 である- Flask アプリケーションのエンドポイント:
- GET
/- クエリパラメータ
idを受け取る runs/{id}/main.pyとruns/{id}/result.txtの内容を読んでテンプレートに埋め込んで返す- この際
O_NOFOLLOWをつけて open するので,読み取り対象のファイルがシンボリックリンクであると失敗する
- この際
- クエリパラメータ
- POST
/- フォームから
codeを受け取る - UUIDv4 の
idを生成し,runs/{id}ディレクトリを作成しruns/{id}/main.pyにcodeを書き込む - nobody ユーザーとして
python runs/{id}/main.pyを実行する - 標準エラーか標準出力を
runs/{id}/result.txtに書き込む(root ユーザーとして) /?id={id}にリダイレクトする
- フォームから
- GET
/ は 755 であるから nobody ユーザーで実行していてもフラグのファイル名は特定できる。
以下を code として POST する:
import os
os.system("ls -l /flag-*.txt")-r-------- 1 root root 17 May 17 05:52 /flag-3876917cbd1b3db12e39587c66ac2891.txt
しかしパーミッションが 400 であるため nobody ユーザーでフラグファイルの内容を読むことはできない。
/app は 1777 であるから nobody ユーザーで実行していても /app 直下にシンボリックリンクを作成できる。
ルートディレクトリ / を指すシンボリックリンクを /app/static に作成する。
以下を code として POST する:
import os
os.system("ln -s / static")(カレントディレクトリは /app であるため, static は /app/static に作成される)
Flask ではモジュールの隣に static ディレクトリを作るとアプリケーションの /static で利用可能になる1。
どうやら static がディレクトリへのシンボリックリンクでも機能するようで,今回 Step 2. で行った設定では GET /static/** でルートディレクトリ配下のファイルの内容を Flask 経由で root ユーザーの権限で読むことができる。
フラグファイル名は Step 1. で特定してあるので,ブラウザで /static/flag-3876917cbd1b3db12e39587c66ac2891.txt にアクセスするとフラグが表示される。
Alpaca{REDACTED}