Credential Harvesting from Web Configs
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:
.envfiles with database passwords, API keys, and mail credentials- PHP config files and WordPress
wp-config.phpwith hardcoded database constants - Django
settings.pyand Railsdatabase.ymlwith 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.
/var/www/html/.env /var/www/html/config/database.yml /opt/app/settings.py
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.
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...
$db_host = 'localhost'; $db_user = 'root'; $db_pass = 'r00tpassword!'; $api_key = 'sk-prod-abc123xyz';
define('DB_NAME', 'wordpress');
define('DB_USER', 'wp_user');
define('DB_PASSWORD', 'wp_password123');
define('DB_HOST', 'localhost');
SECRET_KEY = 'django-insecure-abc123'
DATABASES = {'default': {'PASSWORD': 'db_password_here'}}
Bulk Credential Search
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.
/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.
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:
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.
/var/www/.ssh/id_rsa /home/developer/.ssh/id_rsa
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
-
Automated secret scanning across filesystems and git history