Skip to main content

credstuff picoCTF 2022 Solution

Search a leaked credential database and decode an obfuscated password to find the flag.

Published: July 20, 2023Updated: August 25, 2026

Description

A leaked credential dump pairs usernames and encrypted passwords line-for-line. Locate the entry for cultiris, decode the stored password, and submit it as the flag.

Extract the archive to reveal usernames.txt and passwords.txt, which align line-by-line.

Search for the username cultiris to capture the correct line number.

Print the corresponding password entry and decode it from ROT13.

bash
wget https://artifacts.picoctf.net/c/151/leak.tar
bash
tar -xf leak.tar && cd leak
bash
grep -n "cultiris" usernames.txt
bash
sed -n '378p' passwords.txt
bash
sed -n '378p' passwords.txt | caesar 13

Solution

Want to try it yourself first?

The guided walkthrough reveals hints one step at a time.

Walk me through it
  1. Step 1Map the username
    Observation
    The archive holds usernames.txt and passwords.txt, aligned line for line. So the line number of the target username in one file indexes straight to the right entry in the other.
    grep -n "cultiris" usernames.txt shows the account at line 378. Because both files are line-aligned, that same line number in passwords.txt holds the encrypted secret.
    bash
    grep -n cultiris usernames.txt
    bash
    paste usernames.txt passwords.txt | grep cultiris

    Expected output

    378:cultiris
    What didn't work first

    Tried: Run grep without -n to find the username and assume the password is on the same screen output.

    grep without -n returns the matching line and no line number, so you see the username but have no index to carry into passwords.txt. Without it you are counting rows by hand across a thousand entries, which will go wrong.

    Tried: Use paste usernames.txt passwords.txt | grep cultiris and try to decode the password with a base64 decoder instead of ROT13.

    The ciphertext is not valid base64: it contains curly braces and its character distribution does not match the base64 alphabet, so base64 -d errors or returns garbled bytes. The real clue is that the prefix has the same letter-count shape as picoCTF, which points at a fixed-shift Caesar rather than an encoding.

    Learn more

    Credential dumps (or "combo lists") typically ship as paired text files: line N in usernames.txt matches line N in passwords.txt. grep -n prints the line number alongside the match, which is what links the two files together.

    For one shot, just paste them: paste usernames.txt passwords.txt | grep cultiris joins the columns side-by-side and shows you the user and their cipher in one row. Same idea as zip() in Python. Saves you from manually sed -n 'Np''ing on the password file.

    The root cause of this challenge: passwords were stored in plaintext (or trivially reversible) on the server. Real systems store a salted slow hash (bcrypt, scrypt, Argon2). When the dump leaks, attackers must crack each hash one by one instead of reading off the password directly. Cracking workflow in Hash Cracking for CTFs.

  2. Step 2Retrieve the password entry
    Observation
    grep -n puts the username on line 378, so sed pulls line 378 out of passwords.txt for the stored ciphertext.
    sed -n '378p' passwords.txt prints cvpbPGS{P7e1S_54I35_71Z3} - a substitution that still looks like the picoCTF format.
    Learn more

    How to recognize ROT13 visually: the ciphertext preserves word boundaries, punctuation, and case, and the prefix cvpbPGS has the same shape as picoCTF (4 lowercase + 3 uppercase). Each character is shifted by 13: p -> c, i -> v, c -> p, o -> b. Once you spot a flag-shaped string with the wrong letters, count the shift on one or two characters and ROT13 falls out. More cipher-spotting tactics in CTF Encodings.

    sed -n 'Np' is the shortest way to print line N. Alternatives: awk 'NR==N' or head -N file | tail -1.

  3. Step 3Apply ROT13
    Observation
    The retrieved ciphertext keeps the flag shape, curly braces and all, and its prefix matches picoCTF for length and letter case. That is a fixed-shift Caesar, and the shift is 13.
    Running the line through caesar 13 (from bsdgames) or any ROT13 decoder transforms it back into plaintext, yielding the final flag.
    Learn more

    ROT13 is a Caesar cipher with a fixed shift of 13. The mathematical formulation is E(x) = (x + 13) mod 26 where x is the letter's zero-based position (A=0, B=1, ..., Z=25). Because 13 is exactly half of 26, applying ROT13 twice gives (x + 26) mod 26 = x, so the cipher is its own inverse.

    Worked example on the prefix 'cvpb' (where a=0, b=1, ..., z=25):
      c (= 2)  -> (2  + 13) mod 26 = 15 -> 'p'
      v (= 21) -> (21 + 13) mod 26 = 8  -> 'i'
      p (= 15) -> (15 + 13) mod 26 = 2  -> 'c'
      b (= 1)  -> (1  + 13) mod 26 = 14 -> 'o'
    Result: 'pico'  -> matches the expected flag prefix.

    On Linux, caesar 13 (from bsdgames) applies the shift. Other quick methods: tr 'A-Za-z' 'N-ZA-Mn-za-m', Python's codecs.encode(s, 'rot_13'), or any online ROT13 tool. Storing passwords in ROT13 is essentially storing them in plaintext - real password storage requires a slow hash (bcrypt, scrypt, Argon2) with a per-user salt.

Interactive tools
  • ROT / Caesar CipherDecode Caesar-shifted and ROT-encoded text. Drag the shift slider or scan all 26 rotations at once.
  • Cipher Identifier & Auto-DecoderPaste any ciphertext and the tool auto-runs every common decoder (base64, hex, Morse, ROT, Atbash, Bacon, binary, decimal, URL) and ranks the results by English-likeness.
Alternate Solution

Once you have the ROT13-encoded password string, you can decode it directly in the browser with the ROT / Caesar Cipher tool. Paste the ciphertext (cvpbPGS{P7e1S_54I35_71Z3}), set the shift to 13, and the flag is revealed instantly - no terminal required.

Flag

Reveal flag

picoCTF{C7r1F_54V35_71M3}

Because the files are line-aligned, finding the username index immediately pinpoints the paired password.

Key takeaway

Credential dumps show what weak password storage costs. Keep passwords in plaintext, or behind something trivially reversible like ROT13, and whoever obtains the database owns every account at once. Real systems store salted slow hashes, bcrypt, scrypt, or Argon2, so cracking each entry stays expensive even after a breach. Recognizing a classical substitution on sight, noticing that a prefix has the same shape as picoCTF, is foundational for crypto and OSINT work.

Related reading

Tools used in this challenge

Where to go next