11 min read

Post-Exploitation

Cleanup & Covering Tracks

Proper cleanup ensures client systems are returned to their original state. This is a professional requirement, not evasion - document everything and remove all artifacts.

Danger

CRITICAL: Cleanup is mandatory for legitimate penetration testing. Leaving backdoors creates liability and security risks. Track every change during the engagement to ensure complete remediation.

Cleanup runs in a fixed order, and the order is the point: the engagement log is the only record of what you have to remove, and evidence has to be preserved before anything is deleted. Work the list from the top; skipping step 5 is how a finding loses its proof.

  1. Read the engagement log — it lists every change, so nothing is removed from memory.
  2. Identify the artefacts — match each log entry to a file, key, task, service or ACE on a host.
  3. Remove persistence first — a mechanism can recreate the files you just deleted.
  4. Delete files and tools — payloads, uploaded binaries, staging directories.
  5. Preserve the evidence — the removal output and the before/after state, captured before the artefacts are gone.
  6. Verify each removal — query for the artefact and show it absent, rather than trusting the delete command.
  7. Hand off to the client — cleanup report, credential-reset list, access timeline.

Cleanup Checklist

Before you remove anything

  • ☐ Review the engagement log for every change made
  • ☐ Identify all systems accessed, and the account used on each
  • ☐ List every persistence mechanism installed, with its exact location
  • ☐ Document all files uploaded or created, including the ones that failed
  • ☐ Note all accounts created, modified or added to a group
  • ☐ Record all firewall, ACL and delegation changes
  • ☐ List every scheduled task, service and cron job created

Before you hand back

  • ☐ Verify each artefact on the list is gone — not disabled, gone
  • ☐ Confirm each persistence mechanism can no longer run
  • ☐ Validate that original configurations were restored, not replaced
  • ☐ Test that the backdoors you created are inaccessible
  • ☐ Give the client the cleanup report and the credential-reset list

Windows Cleanup

Remove Registry Persistence

remove-registry-persistence.ps1
# Run Keys
reg delete "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "MaliciousEntry" /f
reg delete "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v "MaliciousEntry" /f

# PowerShell
Remove-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "MaliciousEntry"

# Verify removal
reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Run"
reg query "HKLM\Software\Microsoft\Windows\CurrentVersion\Run"

Remove Scheduled Tasks

remove-scheduled-tasks.ps1
# List tasks (find pentest tasks)
schtasks /query /fo LIST

# Delete specific task
schtasks /delete /tn "TaskName" /f

# PowerShell
Unregister-ScheduledTask -TaskName "TaskName" -Confirm:$false

# Verify
Get-ScheduledTask | Where-Object {$_.TaskName -like "*suspicious*"}

Remove Services

remove-services.ps1
# Stop and delete service
sc stop "ServiceName"
sc delete "ServiceName"

# PowerShell
Stop-Service -Name "ServiceName" -Force
Remove-Service -Name "ServiceName"

# Verify
Get-Service | Where-Object {$_.Name -like "*pentest*"}

Remove WMI Persistence

remove-wmi-persistence.ps1
# List WMI subscriptions
Get-WMIObject -Namespace root\Subscription -Class __EventFilter
Get-WMIObject -Namespace root\Subscription -Class __EventConsumer
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding

# Remove specific subscription
Get-WMIObject -Namespace root\Subscription -Class __EventFilter -Filter "Name='MaliciousFilter'" | Remove-WMIObject
Get-WMIObject -Namespace root\Subscription -Class CommandLineEventConsumer -Filter "Name='MaliciousConsumer'" | Remove-WMIObject
Get-WMIObject -Namespace root\Subscription -Class __FilterToConsumerBinding | Where-Object {$_.Filter -like "*MaliciousFilter*"} | Remove-WMIObject

Delete Files & Tools

delete-files-and-tools.ps1
# Remove uploaded tools
Remove-Item -Path "C:\Users\Public\payload.exe" -Force
Remove-Item -Path "C:\Windows\Temp\mimikatz.exe" -Force
Remove-Item -Path "C:\Temp\*" -Recurse -Force

# Remove from startup folder
Remove-Item -Path "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\malicious.lnk" -Force

# Secure delete (overwrite before deletion)
cipher /w:C:\Temp

# Find and remove tools
Get-ChildItem -Path C:\ -Recurse -Include "mimikatz*","rubeus*","beacon*" -ErrorAction SilentlyContinue | Remove-Item -Force

Remove Created Users

remove-created-users.ps1
# Local users
net user pentestuser /delete

# PowerShell
Remove-LocalUser -Name "pentestuser"

# Domain users (requires DA)
Remove-ADUser -Identity "pentestuser" -Confirm:$false

# Verify
Get-LocalUser
Get-ADUser -Filter {Name -like "*pentest*"}

Linux Cleanup

Remove SSH Keys

remove-ssh-keys.sh
# Remove added SSH keys
# First identify your key (compare with engagement notes)
cat /root/.ssh/authorized_keys
cat /home/*/.ssh/authorized_keys

# Remove specific key
sed -i '/pentest-key-comment/d' /root/.ssh/authorized_keys

# Or remove all and restore from backup
# (coordinate with client)

Remove Cron Jobs

remove-cron-jobs.sh
# List and remove crontab entries
crontab -l
crontab -e  # Remove malicious entries

# Remove from cron directories
rm /etc/cron.daily/pentest-script
rm /etc/cron.d/malicious

# Check /etc/crontab
grep -v "malicious" /etc/crontab > /tmp/crontab.clean
mv /tmp/crontab.clean /etc/crontab

Remove Systemd Services

remove-systemd-services.sh
# Stop and disable service
systemctl stop pentest-service
systemctl disable pentest-service

# Remove service file
rm /etc/systemd/system/pentest-service.service

# Reload daemon
systemctl daemon-reload

# Verify
systemctl list-units --type=service | grep pentest

Remove Backdoor Users

remove-backdoor-users.sh
# Remove user
userdel -r pentestuser

# If user has processes running
pkill -u pentestuser
userdel -rf pentestuser

# Verify
grep pentest /etc/passwd
grep pentest /etc/shadow

Remove Files & Tools

remove-files-and-tools.sh
# Remove uploaded tools
rm -rf /tmp/linpeas.sh
rm -rf /dev/shm/beacon
rm -rf /var/tmp/tools/

# Find and remove
find / -name "linpeas*" -o -name "pspy*" -o -name "beacon*" 2>/dev/null | xargs rm -f

# Secure delete
shred -vfz -n 5 /tmp/sensitive_file

Remove LD_PRELOAD Backdoors

remove-ld-preload-backdoors.sh
# Check for LD_PRELOAD hijacking
cat /etc/ld.so.preload
ls -la /etc/ld.so.preload

# Remove malicious entries
vim /etc/ld.so.preload  # Remove malicious .so paths

# Remove the malicious library
rm /usr/local/lib/evil.so

# Refresh library cache
ldconfig

Active Directory Cleanup

Reset Compromised Credentials

Warning

Coordinate password resets with the client. Forced resets can cause service outages. Document which accounts were compromised for client notification.
reset-compromised-credentials.ps1
# Document compromised accounts for client
# DO NOT reset without client coordination

# If authorized, reset krbtgt (invalidates Golden Tickets)
# Must be done TWICE with replication time between
# Reset 1
Set-ADAccountPassword -Identity krbtgt -Reset -NewPassword (ConvertTo-SecureString "NewPassword1!" -AsPlainText -Force)
# Wait for replication (varies by environment)
# Reset 2
Set-ADAccountPassword -Identity krbtgt -Reset -NewPassword (ConvertTo-SecureString "NewPassword2!" -AsPlainText -Force)

# Note: Client should perform these resets

Remove ACL Modifications

remove-acl-modifications.ps1
# Remove DCSync rights added during engagement
Import-Module ActiveDirectory
$Domain = Get-ADDomain
$DomainDN = $Domain.DistinguishedName
$UserSID = (Get-ADUser pentestuser).SID

$ACL = Get-Acl "AD:\$DomainDN"
# Find and remove the ACE we added
$ACL.Access | Where-Object {$_.IdentityReference -match "pentestuser"} | ForEach-Object {
    $ACL.RemoveAccessRule($_)
}
Set-Acl "AD:\$DomainDN" $ACL

# Remove AdminSDHolder modifications
$AdminSDHolder = "AD:\CN=AdminSDHolder,CN=System,$DomainDN"
$ACL = Get-Acl $AdminSDHolder
$ACL.Access | Where-Object {$_.IdentityReference -match "pentestuser"} | ForEach-Object {
    $ACL.RemoveAccessRule($_)
}
Set-Acl $AdminSDHolder $ACL

Revoke Delegation

revoke-delegation.ps1
# Remove RBCD configurations
Import-Module PowerView
Set-ADComputer -Identity "TargetComputer" -Clear 'msDS-AllowedToActOnBehalfOfOtherIdentity'

# Remove created computer accounts
Remove-ADComputer -Identity "EVILPC$" -Confirm:$false

Log Management

Information

Logs are evidence, not residue. Cleaning up an artefact is authorised work; deleting the record of it is a separate control test that needs its own written objective — the same boundary Covert Operations draws. Absent that authorisation, export the relevant window for the client and leave the logs in place.

Windows Event Logs (Reference Only)

win-event-logs-reference-only.ps1
# VIEW logs to document your activity (for reporting)
# DO NOT clear without client authorization

# View Security logs
Get-WinEvent -LogName Security -MaxEvents 100 | Where-Object {$_.TimeCreated -gt (Get-Date).AddHours(-24)}

# Export specific timeframe for client
wevtutil epl Security C:\engagement_logs\security.evtx /q:"*[System[TimeCreated[@SystemTime>='2024-01-15T00:00:00' and @SystemTime<='2024-01-16T00:00:00']]]"

# Key Event IDs to document:
# 4624 - Logon
# 4625 - Failed logon  
# 4672 - Special privileges
# 4688 - Process creation
# 4698/4699 - Scheduled task created/deleted

Linux Logs (Reference Only)

linux-logs-reference-only.sh
# VIEW logs to document activity (for reporting)

# Auth logs
cat /var/log/auth.log | grep "pentest_period"
cat /var/log/secure | grep "pentest_period"

# Command history - document but leave for client
cat ~/.bash_history

# Key log files:
# /var/log/auth.log - Authentication
# /var/log/syslog - System events
# /var/log/apache2/access.log - Web access
# ~/.bash_history - Command history

Cleanup Documentation

cleanup-documentation.md
# Cleanup Report Template

## Engagement Cleanup Summary
**Date:** [Date]
**Tester:** [Name]
**Client:** [Client Name]

## Systems Accessed
| Hostname | IP Address | Access Level | Duration |
|----------|------------|--------------|----------|
| DC01 | 10.10.10.1 | Domain Admin | 48 hours |
| WEB01 | 10.10.10.20 | Local Admin | 24 hours |

## Artifacts Removed
| Type | Location | Status |
|------|----------|--------|
| Scheduled Task | DC01: "WindowsUpdate" | ✅ Removed |
| Registry Key | WEB01: HKCU\Run\Update | ✅ Removed |
| Uploaded File | DC01: C:\Temp\mimikatz.exe | ✅ Deleted |
| User Account | corp.local\pentestadmin | ✅ Deleted |

## Credentials Compromised (For Client Remediation)
| Account | Hash Type | Recommendation |
|---------|-----------|----------------|
| Administrator | NTLM | Reset password |
| svc_sql | NTLM | Reset password |
| krbtgt | NTLM | Double reset required |

## Verification Steps Completed
□ All persistence mechanisms removed
□ All uploaded tools deleted
□ Created accounts removed
□ Registry modifications reverted
□ Client notified of compromised accounts

## Notes
[Any additional information for client]

Client Handoff

The handoff is where cleanup becomes auditable. Provide five things, in writing, and then walk the client through them: the cleanup report, the list of credentials that need resetting, the access timeline for their log correlation, the detection improvements your findings imply, and a statement that each artefact is confirmed gone.

Book the meeting rather than emailing the report: the questions that matter are the ones about where persistence was found and how to verify it is gone, and those get asked live. Their verification steps are the last item on the agenda, because the engagement is not closed until the client has confirmed them.

Evidence Collection

Before/after state: The configuration or ACL as you found it, and as you left it — for every object you touched.

Removal proof: Command output showing the artefact gone (a query that returns nothing is stronger than the delete command itself).

Artefact register: Host, exact path or distinguished name, account, timestamp created, timestamp removed.

Credential exposure list: Every account whose hash or password you obtained, because the client decides what to reset and when.

Timeline: Access windows per host, so the client can correlate their own logs instead of taking your word for it.

False Positive Identification

  • A file the client put there: A tool name in a temp directory is not proof you left it. Compare against your artefact register before reporting a leftover.
  • Event log entries after your deletion: Windows records the deletion itself. Log entries for the mechanism are expected residue, not a failed cleanup.
  • A disabled service still listed: Removing a service requires a reboot before the registry entry and event logs agree. Verify after the reboot, not before.
  • An ACL that looks unchanged: AdminSDHolder ACEs are re-applied by SDProp on an hourly cycle; confirm the source object is clean rather than reading a stale copy.
  • A password that still works: A credential can authenticate after cleanup because the client has not reset it yet. That is a handoff item, not a leftover — unless you created the account.
  • A scheduled task from the deployment tooling: Task names recur across estates. Match on the action path and author, not the name, before calling it yours.

Remediation & Handoff

Cleanup is not finished until the client can verify it without you.

Restore and prove it

  • • Revert every artefact in the register to its captured before-state, then re-query it. The query is the proof — the deletion command is not.
  • • Reboot once after removing a service, driver or scheduled task, so the registry, the service manager and the event logs agree.
  • • Remove any certificate, ACE or delegation right you added as its own named change, with its own verification step.

Hand off what you cannot fix

  • • Every credential you extracted belongs on a reset list with an owner and a deadline — you cannot rotate it for the client.
  • • Say plainly which artefacts are deliberately left in place (engagement records, evidence copies) and where they live.
  • • Give the client your access windows and the artefact register so their own logs can corroborate the report.