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.
Setup
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.
wget https://artifacts.picoctf.net/c/151/leak.tartar -xf leak.tar && cd leakgrep -n "cultiris" usernames.txtsed -n '378p' passwords.txtsed -n '378p' passwords.txt | caesar 13Solution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Map the usernameObservationI noticed the archive contained two separate files,usernames.txtandpasswords.txt, aligned line-by-line, which suggested that finding the line number ofcultirisin the username file would directly index the correct password entry in the other file.grep -n "cultiris" usernames.txtshows the account at line 378. Because both files are line-aligned, that same line number inpasswords.txtholds the encrypted secret.bashgrep -n cultiris usernames.txtbashpaste usernames.txt passwords.txt | grep cultirisExpected 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.txtmatches line N inpasswords.txt.grep -nprints the line number alongside the match, which is what links the two files together.For one shot, just
pastethem:paste usernames.txt passwords.txt | grep cultirisjoins the columns side-by-side and shows you the user and their cipher in one row. Same idea aszip()in Python. Saves you from manuallysed -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.
Step 2
Retrieve the password entryObservationI noticed thatgrep -nreturned line 378 forcultiris, which told me exactly which line to extract frompasswords.txtusingsed -n '378p'to get the stored ciphertext.sed -n '378p' passwords.txtprintscvpbPGS{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
cvpbPGShas the same shape aspicoCTF(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'orhead -N file | tail -1.Step 3
Apply ROT13ObservationI noticed the retrieved ciphertextcvpbPGS{P7e1S_54I35_71Z3}preserved the flag-shaped structure with curly braces and had the prefixcvpbPGSmatching the length and case pattern ofpicoCTF, which indicated a fixed-shift Caesar cipher and a shift of 13 (ROT13) was needed to decode it.Running the line throughcaesar 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 26where 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(frombsdgames) applies the shift. Other quick methods:tr 'A-Za-z' 'N-ZA-Mn-za-m', Python'scodecs.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.