Hack MAC 2025 – CTF Challenge Development
📌 Project Overview
Hack MAC 2025 is a Capture The Flag (CTF) competition where I contributed as a challenge creator. I designed two web exploitation challenges focusing on real-world vulnerabilities: Business Logic Errors and Blind SQL Injection.
The goal was to create educational yet challenging scenarios that require participants to analyze source code and understand underlying architectural flaws. All challenges were containerized using Docker to ensure isolated and reproducible environments.
🕹️ Challenge 1: business-logic-error
Category: Web
Difficulty: Easy
Scenario
A simple e-commerce page allows users to buy items. The “Flag” item costs 9,999,999 credits, but users start with only 10,000 credits. The server fails to validate whether the purchase quantity is positive.
Vulnerability Analysis
The backend code directly calculates the cost without checking for negative numbers.
# Vulnerable Logic
try:
qty = int(request.form.get("quantity", "1"))
except ValueError:
qty = 1
cost = item["price"] * qty
session["balance"] = pre_balance - cost # Subtracting a negative becomes addition!
Exploitation (Write-up)
Participants can exploit this by sending a negative quantity for a cheap item.
-
Open the store page.
-
Inspect the quantity input for ice_cream.
-
Edit the min value and type -10000).
-
Click Buy.
-
Since cost = 1000 * (-10000) = -10,000,000, the server does balance = balance - (-10,000,000) → balance increases by 10,000,000.
-
Buy Flag: With the inflated balance, the user can legally purchase the Flag.
🕹️ Challenge 2: Find-The-Pass
Category: Web / SQL Injection (Blind)
Difficulty: Hard
Scenario
A login page asks for a username and password. It behaves securely on the surface—no error messages are displayed, and no data is returned other than a generic “Success” or “Fail” page. The goal is to log in as admin, but the password is the Flag.
Vulnerability Analysis
The application uses Raw SQL instead of SQLAlchemy’s ORM features, making it vulnerable to injection.
# app/main.py - Vulnerable Code
query = text(f"SELECT * FROM user WHERE username = '{username}' AND password = '{password}'")
with db.engine.connect() as connection:
result = connection.execute(query)
user = result.fetchone()
Exploitation (Write-up)
Since the application swallows errors (Error-based injection doesn’t work) and doesn’t return data (Union-based doesn’t work), participants must use Boolean-based Blind SQL Injection.
- Determine Password Length: Inject a condition to check the length.
admin' AND length(password)=16 --
If the page returns “Success”, the length is 16.
- Extract Password (The Flag): Iterate through each character using ASCII functions.
admin' AND ascii(s1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111ubstr(password,1,1)) > 70 --
By analyzing the True/False response, attackers can brute-force the password character by character (e.g., finding ‘H’, ‘M’, ‘2’…).
🛠️ Infrastructure
Each challenge was deployed as a standalone service using Docker Compose to ensure stability during the competition.
# docker-compose.yml (Snippet)
services:
web:
build: .
ports:
- "5001:5001"
environment:
MYSQL_USER: ctf
MYSQL_PASSWORD: ctfpass
depends_on:
db:
condition: service_healthy
🎯 Learning Outcomes
Through this project, I deepened my understanding of:
Defensive Coding: How strictly validating inputs (e.g., qty > 0) and using Parameterized Queries (Prepared Statements) effectively prevents these attacks.
Containerization: Managing multi-container applications (Flask + MySQL) for CTF deployment.