credstuff picoCTF 2022 Solution

Published: July 20, 2023

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 1
    Map the username
    Observation
    I noticed the archive contained two separate files, usernames.txt and passwords.txt, aligned line-by-line, which suggested that finding the line number of cultiris in the username file would directly index the correct password entry in the other file.
    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 just the matching line content with no line number, so you see 'cultiris' but have no index to carry over to passwords.txt. Without the line number you have no way to pick the right row from passwords.txt unless you count manually, which is error-prone across 1000+ entries.

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

    The ciphertext 'cvpbPGS{P7e1S_54I35_71Z3}' is not valid base64 because it contains curly braces and the character distribution does not match base64 alphabet. base64 -d returns an error or garbled bytes. The correct clue is that the prefix 'cvpbPGS' has the same letter-count shape as 'picoCTF', pointing to a fixed-shift Caesar cipher rather than an encoding scheme.

    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 2
    Retrieve the password entry
    Observation
    I noticed that grep -n returned line 378 for cultiris, which told me exactly which line to extract from passwords.txt using sed -n '378p' to get 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 3
    Apply ROT13
    Observation
    I noticed the retrieved ciphertext cvpbPGS{P7e1S_54I35_71Z3} preserved the flag-shaped structure with curly braces and had the prefix cvpbPGS matching the length and case pattern of picoCTF, which indicated a fixed-shift Caesar cipher and a shift of 13 (ROT13) was needed to decode it.
    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{...}

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

Key takeaway

Credential dumps expose the consequences of weak password storage: when passwords are kept in plaintext or protected only by a trivially reversible scheme like ROT13, an attacker who obtains the database file recovers every account immediately. Real systems store passwords as salted slow hashes (bcrypt, scrypt, Argon2) so that cracking each entry requires significant computation even after a breach. Recognizing classical substitution ciphers visually, such as noticing that 'cvpbPGS' has the same structure as 'picoCTF', is a foundational skill for crypto and OSINT challenges.

Related reading

Want more picoCTF 2022 writeups?

Tools used in this challenge

What to try next