ctf upsolve by kodai Advent Calendar 2025のDay4の記事になります。
取り扱った問題
AlpacaHack Round 11 (Web) Jackpot
Author: Ark
upsolve
15個のスロットを全て7で揃えることができればFLAGをゲットできるという問題です。

単純に運で7を揃えることができる確率は以下のようになります。
\frac{1}{10^{15}}
現実的に運でどうにかなる問題ではないです。
そこで何とかして7を揃えるためにコードの実装を読んでみます。
from flask import Flask, request, render_template, jsonify
from werkzeug.exceptions import BadRequest, HTTPException
import os, re, random, json
app = Flask(__name__)
FLAG = os.getenv("FLAG", "Alpaca{dummy}")
def validate(value: str | None) -> list[int]:
if value is None:
raise BadRequest("Missing parameter")
if not re.fullmatch(r"\d+", value):
raise BadRequest("Not decimal digits")
if len(value) < 10:
raise BadRequest("Too little candidates")
candidates = list(value)[:10]
if len(candidates) != len(set(candidates)):
raise BadRequest("Not unique")
return [int(x) for x in candidates]
@app.get("/")
def index():
return render_template("index.html")
@app.get("/slot")
def slot():
candidates = validate(request.args.get("candidates"))
num = 15
results = random.choices(candidates, k=num)
is_jackpot = results == [7] * num # 777777777777777
return jsonify(
{
"code": 200,
"results": results,
"isJackpot": is_jackpot,
"flag": FLAG if is_jackpot else None,
}
)
@app.errorhandler(HTTPException)
def handle_exception(e):
response = e.get_response()
response.data = json.dumps({"code": e.code, "description": e.description})
response.content_type = "application/json"
return response
if __name__ == "__main__":
app.run(debug=False, host="0.0.0.0", port=3000)
このコードを読んだときに分かった制約は以下です。
- 文字列全体が1文字以上の0~9の数字だけで構成されていること
- 文字に重複があってはいけないこと
- 10文字目以降の数字は無視される
これらの制約の中で7を揃える方法を考えました。
\dにマッチする、かつreturnの中でユーザの入力をint型に変換してリストに入れているので、int型に変換した時に、7になれば良さそうです。
def validate(value: str | None) -> list[int]:
if value is None:
raise BadRequest("Missing parameter")
if not re.fullmatch(r"\d+", value):
raise BadRequest("Not decimal digits")
if len(value) < 10:
raise BadRequest("Too little candidates")
candidates = list(value)[:10]
if len(candidates) != len(set(candidates)):
raise BadRequest("Not unique")
return [int(x) for x in candidates]
\dについてPythonのreモジュールのドキュメントを見てみると以下のように書いてありました。
Matches any Unicode decimal digit (that is, any character in Unicode character category [Nd]). This includes [0-9], and also many other digit characters.
参考リンク: https://docs.python.org/3/library/re.html
なので数字の7を表すUnicode文字列を10種類探せばいいことが分かります。
探したものは7٧۷७৭୭൭૭7߇になります。これを入力してスロットを回すとFLAGがゲットできます。
FLAG : Alpaca{what_i5_your_f4vorite_s3ven?}