Ethical Hacking Lesson 23 – Credential Harvesting | Dataplexa
System & Network Attacks · Lesson 23

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"

Breaking it down:

mysql -u root -p toor in bash history
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.
ssh admin@192.168.56.50 — a new target
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.
/var/www/dvwa/config/config.inc.php
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

Breaking it down:

db_password = 'toor' — confirms the bash_history finding
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.
update users set password=md5('newpassword') — a critical finding
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

Breaking it down:

msfadmin:msfadmin worked on a second host
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.
whoami; hostname — the one-command access test
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:

A pen tester gains a low-privilege shell on a Linux web server. Within the first few minutes they find a database connection string including plaintext credentials — not by reading any config file, but by looking at a file that records every command the system administrator has previously typed in their terminal session. The file contains commands like "mysql -u root -pSecretPass123" entered months ago. What file did the pen tester read to find these credentials?


Scenario:

During post-exploitation credential harvesting on an authorised target, a pen tester reads bash_history and discovers SSH connections being made to 10.10.5.22 — an IP address not listed anywhere in the scope document. The tester believes the credentials they found would also work on this new host and that access would demonstrate significant lateral movement capability. What must happen before they attempt any connection to 10.10.5.22?


Scenario:

A pen tester finds the credentials admin:Winter2024! in a config file on a compromised web server. They test those same credentials against the organisation's VPN portal, the internal wiki, the HR system, and the cloud management console — and find the credentials work on all four. No vulnerability was exploited on any of those systems. The access was obtained purely by trying the same username and password. What specific security weakness does this finding demonstrate?


Quiz

Scenario:

A pen tester reads bash_history on a compromised Linux server and finds the command "mysql -u root -p toor" — revealing both that a password was typed in plaintext into the terminal (which saved it to history) and that the password itself is "toor" — trivially weak. The tester debates whether this is one finding or two. How should it be reported?

Scenario:

A junior pen tester gains shell access to a web server and runs grep to search for files containing the word "password." They find a PHP configuration file — config.inc.php — in the web root and are surprised to find the database username and password stored in plaintext inside it. They assumed web application credentials would be encrypted or hashed. Why are these credentials stored in plaintext and why does this make config files a reliable credential source during post-exploitation?

Scenario:

A pen tester has compromised one server and harvested four sets of credentials from config files and shell history. They have documented the finding and moved on to other hosts in scope. Their team lead reviews the work and says a critical next step was skipped that could significantly expand the impact of the engagement. What should the pen tester have done with the harvested credentials before moving on?

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.