Ethical Hacking
Credential Harvesting
Cracking hashes and brute forcing services are technical approaches. Credential harvesting is broader — it covers every way that credentials end up in an attacker's hands without being cracked from scratch. Understanding the methods is essential for pen testers tasked with testing an organisation's resilience to them.
Credentials are everywhere — most organisations do not know where
The most common finding in a post-breach investigation is not that an attacker found a zero-day vulnerability. It is that they used credentials that were already available to them — from a phishing email, a previous breach, a misconfigured service that exposed them, or a developer who left them in a config file that ended up publicly accessible.
Credential harvesting in a pen test context means identifying every place where credentials are stored, cached, transmitted, or exposed — and assessing whether those sources could be exploited by a real attacker. It is part reconnaissance, part technical testing, and part social engineering assessment.
Where credentials live — the sources pen testers look for
Memory and running processes
Windows systems cache credentials in memory for single sign-on. Tools like Mimikatz can extract plaintext passwords and NTLM hashes from the LSASS process on older Windows versions or misconfigured systems. Finding credentials in memory requires local administrator access — making it a post-exploitation technique.
Configuration and environment files
Database connection strings, API keys, and admin passwords frequently appear in .env files, config.php, web.config, and similar files. Developers store them there for convenience. If those files are publicly accessible — or accessible to a compromised account — the credentials are effectively exposed.
Browser and application caches
Web browsers store saved passwords in local databases — Chrome's password store, Firefox's logins.json, Edge's encrypted vault. On a compromised machine with user-level access, these stores can be decrypted and extracted. Many users save every password in their browser, making this a rich source.
Shell history and scripts
Administrators frequently type passwords directly into terminal commands — connecting to databases, running deployment scripts, resetting service credentials. Those commands end up in ~/.bash_history or ~/.zsh_history. Reading shell history on a compromised Linux machine is one of the first things experienced pen testers do.
Network traffic — unencrypted protocols
Telnet, FTP, HTTP basic authentication, and SNMP v1/v2 transmit credentials in plaintext. A network capture on the same segment as a host using these protocols exposes every credential that passes over the wire. In the lab, you already know Telnet and FTP are running on Metasploitable.
Publicly exposed repositories
Developers accidentally commit credentials to public GitHub repositories with notable frequency. Secrets scanning tools exist specifically for this problem — and attackers use them too. A committed API key or database password may have been in a public repository for months before anyone notices.
Finding credentials in files — a systematic search
Once you have shell access to a system — whether through exploitation or a misconfiguration — searching for stored credentials is one of the first things to do. The commands below look for common patterns: files with "password" in the name, configuration files containing connection strings, and shell history containing sensitive commands.
The scenario: You have a low-privilege shell on Metasploitable — gained through the Samba misconfiguration from earlier lessons. Before attempting privilege escalation, you spend five minutes searching the filesystem for any stored credentials that might give you a faster route to higher access or reveal additional systems to target.
# Search for files with "password" in the filename anywhere on the system
# find scans the filesystem starting from / (root)
# -name "*.txt" -o -name "*.conf" -o -name "*.php" — common file types
# 2>/dev/null suppresses permission errors for files we cannot read
find / -name "*password*" -o -name "*passwd*" -o -name "*creds*" \
2>/dev/null | grep -v proc
# Search inside files for the word "password" — case insensitive
# -r recursive — searches all files in the directory and subdirectories
# -i case insensitive — matches Password, PASSWORD, password
# -l only prints filenames, not the matching lines (reduces output noise)
# Start in /etc and /var/www where config files commonly live
grep -r -i "password" /etc/ /var/www/ 2>/dev/null -l
# Read the shell history — commands the current user has previously typed
# Often reveals database connection commands, service passwords, SSH keys
cat ~/.bash_history
# Check for any world-readable files in sensitive locations
# World-readable means anyone on the system can read them — not just root
# -perm -o+r means the "other" (everyone) read bit is set
find /etc /home /var -perm -o+r -type f 2>/dev/null | \
grep -E "shadow|passwd|key|secret|token"
--- Files with "password" in filename --- /var/www/dvwa/config/config.inc.php /home/msfadmin/.mysql_history --- grep for "password" in config files --- /var/www/dvwa/config/config.inc.php --- bash_history --- mysql -u root -p toor ssh admin@192.168.56.50 -p 22 mysqldump -u root -ptoor dvwa > /tmp/backup.sql --- World-readable sensitive files --- /etc/passwd
Breaking it down:
The administrator typed the MySQL root password directly into a terminal command — "toor" — and it is now permanently in the shell history file. This is a finding in its own right: credentials stored in plaintext in a user-readable file. The root password itself is weak (it is "root" spelled backwards), but the real issue is the storage method. Any user who can read this file has the database root password.
The bash history revealed an SSH connection to 192.168.56.50 — an IP address that never appeared in your DNS enumeration or port scanning. The administrator has been connecting to another internal system. That address goes on the target list immediately. Credentials in history files frequently point to other systems the user accesses — following those leads is how lateral movement opportunities surface.
A PHP configuration file containing database connection details for the web application. These files almost always contain a database username and password in plaintext — they have to, because the application needs to connect to the database at runtime. Read this file and you have the web application's database credentials, which may differ from the root credentials already found.
Reading the DVWA config file
The grep search flagged config.inc.php — time to read it directly. Web application config files are structured specifically to contain database credentials and are one of the most reliable sources of additional credentials on any compromised web server.
# Read the DVWA configuration file directly
# cat prints the entire file contents to the terminal
cat /var/www/dvwa/config/config.inc.php
# If the file is long, use grep to pull out just the credential lines
# This finds any line containing "pass", "user", "db", or "host"
grep -iE "pass|user|db_|host" /var/www/dvwa/config/config.inc.php
# Also check .mysql_history — records of previous MySQL commands run interactively
# Similar to bash_history but specific to MySQL sessions
cat /home/msfadmin/.mysql_history
--- config.inc.php (relevant lines) ---
$_DVWA[ 'db_server' ] = '127.0.0.1';
$_DVWA[ 'db_database' ] = 'dvwa';
$_DVWA[ 'db_user' ] = 'root';
$_DVWA[ 'db_password' ] = 'toor';
--- .mysql_history ---
show databases;
use dvwa;
select * from users;
update users set password=md5('newpassword') where user='admin';
Breaking it down:
Two independent sources now confirm the same database root password — bash_history and config.inc.php. When multiple sources agree, the finding is confirmed beyond any doubt. Document both sources in the report: it demonstrates thoroughness and removes any possibility the client disputes the finding as a false positive.
The MySQL history shows an administrator manually setting a user password in the DVWA application using MD5 — the plaintext 'newpassword' is visible in the command. This reveals both the password and that the application stores passwords as MD5 hashes. Cross-reference this with the DVWA users table and you have the admin account's new password in plaintext from a history file. No cracking required.
Credential reuse — one password, multiple systems
Password reuse is one of the most persistent and impactful security problems in real organisations. People use the same password across multiple systems — their email, their VPN, their internal systems, their personal accounts. A credential found on one system is worth testing against every other system in scope.
The bash history revealed a connection to 192.168.56.50. The credentials found so far — msfadmin:msfadmin, root:toor, admin:newpassword — should all be tested against that new address. If the administrator reused any of those passwords on the other system, lateral movement requires nothing more than an SSH command.
# Test credentials found on Metasploitable against the new IP from bash history
# This is credential reuse testing — part of lateral movement assessment
# Only run against IPs within your authorised scope
# First confirm the new host is alive and has SSH open
nmap -sS -p 22 192.168.56.50
# Try each harvested credential against SSH on the new host
# -o StrictHostKeyChecking=no skips the SSH key fingerprint verification prompt
# so the command does not wait for manual confirmation of the host key
# exit immediately after connecting — we only need to confirm access, not explore
ssh -o StrictHostKeyChecking=no msfadmin@192.168.56.50 "whoami; hostname" 2>/dev/null
ssh -o StrictHostKeyChecking=no admin@192.168.56.50 "whoami; hostname" 2>/dev/null
--- nmap result --- PORT STATE SERVICE 22/tcp open ssh --- ssh msfadmin@192.168.56.50 --- msfadmin internalserver02 --- ssh admin@192.168.56.50 --- Permission denied (publickey,password)
Breaking it down:
The same credential that worked on Metasploitable also works on internalserver02. This is credential reuse — a single weak password on one system became access to a second system that was not even in the original DNS enumeration. The hostname "internalserver02" suggests there may be internalserver01 as well. A credential harvesting finding is now a lateral movement finding.
Running whoami and hostname confirms the connection worked and identifies what account you have and which machine you are on — without actually doing anything on the system beyond confirming access. In a report, this is how you demonstrate access was achieved: show the hostname and username, nothing more intrusive than that unless the scope explicitly covers further activity on that host.
Start from one host. Find credentials in three places — bash history, config file, MySQL history. Test them against a second host found in the same history. Gain access. The entire chain took less than fifteen minutes and required no exploitation of vulnerabilities — just careful reading of what the compromised system had stored.
In a real engagement: The discovery of 192.168.56.50 requires immediate scope confirmation before testing any credentials against it. It was not in the original scope document. Accessing a system outside your authorised scope — even with credentials you legitimately found — is unauthorised access. Stop, document the discovery, and confirm with the client whether the new host is in scope before proceeding.
Teacher's Note: Shell history files are one of the most underrated sources of intelligence in post-exploitation. In real engagements, bash_history and zsh_history have revealed VPN credentials, cloud provider API keys, internal IP addresses of other systems, and database passwords that cracking would have taken hours. Read it on every compromised host, every time.
Practice questions
Scenario:
Scenario:
Scenario:
Quiz
Scenario:
Scenario:
Scenario:
Up Next · Lesson 24
Exploiting Misconfigurations
The most common class of real-world vulnerability — services left in default states, permissions set too broadly, and infrastructure deployed without hardening.