Overview
A single file: server.log. We’re told it came from a compromised internal server and we need to figure out what was exposed.
Reconnaissance
Opening the file, we see it’s a Python web application log with mostly routine traffic to a CTF admin API.
Scrolling through (or using a text editor’s search), one section stands out: a 500 Internal Server Error response followed by a full Python traceback.
Finding the Flag
Python’s default exception handler dumps local variables from each frame in the call stack when an unhandled exception occurs and the app is running in debug mode or logging is misconfigured. Developers often forget this means any sensitive values in scope at the time of the crash — database results, API keys, auth tokens — get written straight to the log file.
In this case, the /api/validate endpoint fetched the flag from the database into a local variable before calling the validator. The validator crashed because user_input was None (a missing POST body field). The exception handler dutifully logged everything:
Local variables (validate_submission):
request = <Request 'http://ctf.internal/api/validate' [POST]>
challenge_id = 42
user_id = 338
flag = 'MetaCTF{unhandl3d_3xc3pt10ns_l34k_s3cr3ts}' ← here
user_input = None
db_cursor = <psycopg2.extensions.cursor object at 0x7f3a1c2d4b80>
Solve
Read the file carefully, or grep for the flag:
grep -o "MetaCTF{[^']*}" server.log
Flag
MetaCTF{unhandl3d_3xc3pt10ns_l34k_s3cr3ts}