Description
We intercepted a suspicious file from a system, but instead of the password itself, it only contains its SHA-1 hash. Using OSINT techniques, you are provided with personal details about the target. Generate a custom password list and recover the original password by matching its hash. Download: userinfo.txt , hash.txt , and check_password.py .
Download userinfo.txt, hash.txt, and check_password.py.
Read userinfo.txt to understand the target's personal details.
cat userinfo.txtcat hash.txtcat check_password.pySolution
Want to try it yourself first?
The guided walkthrough reveals hints one step at a time.
Step 1
Profile the targetObservationI noticed the challenge description identified this as an OSINT-driven task and provided a userinfo.txt file containing personal details about the target, which suggested that profiling the target's information was the necessary first step before generating any password candidates.Read userinfo.txt carefully. It contains personal details like name, birthdate, favourite things, pet names, or other information people commonly use in passwords.bashcat userinfo.txtWhat didn't work first
Tried: Trying to crack the hash directly with hashcat or john using a generic rockyou.txt wordlist.
rockyou.txt contains ~14 million common passwords and will likely miss a personalized password like Aj_15901990 entirely. The challenge is designed around OSINT-driven profiling, so the password is constructed from the target's specific details rather than drawn from a public leak list. CUPP generates candidates that no generic wordlist would include.
Tried: Skimming userinfo.txt quickly and only entering the name and birthdate into CUPP, ignoring fields like nickname or pet name.
CUPP mutates every provided field and combines them with leet substitutions, separators, and year suffixes. Leaving fields blank shrinks the wordlist and may drop the exact combination that matches the hash. Reading every line of userinfo.txt and entering all non-empty fields is required to ensure the correct candidate is generated.
Learn more
Password profiling is an OSINT (Open Source Intelligence) technique used in penetration testing and red team engagements. Instead of brute-forcing all possible passwords, you generate a targeted wordlist based on information specific to the target: their name, birthday, spouse's name, pet's name, favourite sports team, employer, and common patterns like appending birth years or "123" suffixes.
Research shows that people overwhelmingly choose passwords based on memorable personal information. A 2019 study found that over 50% of users choose passwords containing their name or birthdate. Attackers who know a target's personal details can often crack their password with a few hundred candidates, whereas a brute-force attack against the same password might take millions of years.
In real engagements, profiling information comes from LinkedIn profiles, social media, company websites, and data breaches. This challenge simulates receiving that information in a file - in practice, gathering it requires careful OSINT research using tools like Maltego, SpiderFoot, or manual social media enumeration.
Step 2
Generate a custom wordlist with CUPP and crack the SHA-1ObservationI noticed the challenge involved a SHA-1 hash and personal details rather than a generic password list, which suggested that CUPP's interactive mode was the right tool to generate a targeted wordlist by combining the target's name, nickname, and birthdate into probable password candidates.Clone and run CUPP in interactive mode. Enter the personal details from userinfo.txt when prompted. CUPP generates a targeted wordlist (saved as alice.txt or similar). Copy it to passwords.txt, then run check_password.py to find the matching SHA-1 hash.bashgit clone https://github.com/Mebus/cupp.gitbashcd cupp && python3 cupp.py -ibash# Fill in the details from userinfo.txt interactively:bash# Name: Alice Johnsonbash# Nickname: A.J.bash# Birthdate: 15/07/1990 (European format: day/month/year)bash# (press Enter for fields you don't know)bash# CUPP saves the wordlist as alice.txt (or similar)bashcp alice.txt passwords.txtpythonpython3 check_password.pybash# The correct password is something like Aj_15901990Expected output
Password found: Aj_15901990 picoCTF{p4ssw0rd_pr0f1l3r_...}What didn't work first
Tried: Running CUPP without the -i flag (e.g. python3 cupp.py -l) to download a pre-built wordlist instead of generating a custom one.
The -l flag downloads generic wordlists like CUPP's own common-passwords list, which will not contain a password built from Alice Johnson's specific birthdate and initials. The -i (interactive) flag is the one that prompts for personal details and generates a targeted wordlist. Only the interactive mode output is likely to contain the correct candidate.
Tried: Copying the wordlist to a filename other than passwords.txt (e.g. wordlist.txt) and running check_password.py.
check_password.py opens the file by a hardcoded name. If the wordlist is saved under a different name the script raises a FileNotFoundError or silently finishes without finding a match. The cp command in the solution renames alice.txt to passwords.txt precisely because that is what check_password.py expects.
Learn more
SHA-1 is a cryptographic hash function that produces a 160-bit (40 hex character) digest. It is no longer considered secure for digital signatures (broken in 2017 by Google's SHAttered attack), but understanding it is important because it's still found in older systems and CTF challenges. SHA-1's main weakness for password storage is that it's fast: a GPU can compute billions of SHA-1 hashes per second, making dictionary attacks trivial.
The correct tool for password hashing is a purpose-built slow hash function like bcrypt, scrypt, Argon2, or PBKDF2 with a high iteration count. These deliberately take milliseconds to compute, making dictionary attacks tens of thousands of times slower. They also include a salt (a random value mixed into the hash) to prevent pre-computed rainbow table attacks. For a deeper tour of the cracking workflow see Hash cracking for CTF; for the Python idioms used in the loop above see Python for CTF.
Step 3
Run check_password.py to retrieve the flagObservationI noticed that check_password.py was provided alongside the hash and userinfo files, which suggested it was designed to automate the hash comparison loop against the generated wordlist and would output the flag directly upon finding the matching password.Copy your generated wordlist to passwords.txt (if not already done), then run check_password.py. The script reads from passwords.txt automatically and prints the flag when it finds the matching password.pythonpython3 check_password.pyWhat didn't work first
Tried: Running check_password.py from a different working directory than where passwords.txt was saved.
check_password.py opens passwords.txt by relative path, so it looks in the current working directory. If you cd into the cupp/ subdirectory to run the script but passwords.txt is in the parent directory, the script raises FileNotFoundError and exits without output. Both files must be in the same directory before running the script.
Tried: Writing a manual Python loop to hash each line of the wordlist and compare it to the SHA-1 from hash.txt instead of using check_password.py.
This approach can work in principle but commonly fails because the wordlist contains a trailing newline on each candidate. Hashing 'Aj_15901990\n' produces a different SHA-1 than hashing 'Aj_15901990'. check_password.py strips whitespace before hashing, so using it directly avoids this off-by-one encoding issue that trips up manual scripts.
Learn more
Hash cracking fundamentally works by preimage attack: given a hash H, find any input m such that hash(m) = H. For targeted attacks like this, you compute hash(candidate) for each candidate in your wordlist and compare against the target hash. This is conceptually simple but the quality of the wordlist determines success.
From a defensive standpoint, this challenge illustrates why password complexity rules alone are insufficient. "Fluffy123!" satisfies most complexity requirements (upper, lower, number, special character, 9+ characters) but is trivially cracked by any attacker who knows your pet's name. Password managers generating random strings are the correct solution because they make password profiling attacks impossible.
Flag
Reveal flag
picoCTF{p4ssw0rd_pr0f1l3r_...}
Use CUPP (Common User Passwords Profiler) in interactive mode with the target's personal details from userinfo.txt to generate a wordlist. Run check_password.py against it to find the matching SHA-1 hash. The password combines initials and birthdate (e.g. Aj_15901990).