Introduction

Now that we have made a stealthy infector that is able to infect any ELF binary present on our system, we now have to make it useful. Being able to propagate is a good thing but we want to make something out of it. A backdoor allowing remote access on the infected machine would be a great idea. How do we do that ? This actually quite simple. Here we won’t really take care about stealthiness but I might write an article about it at some point. The purpose of this backdoor will be to have an almost-permanent remote access on the machine. For that, we will assume that enough binaries are infected so that when the backdoor is closed, it will be reopened when the infected machine will run a command. I won’t show any code for this article but if you want to get a very similar backdoor ASM source code, you can find it here in the Assembly files

How to run background ?

First, what we have to do is making sure tht the backdoor will be running in background at any time. For that, we have to launch it via the viral code but we also want to make its execution continue after the virus/command has been executed. We can use the daemonization principle to do that (man 7 daemon). A daemon is simply a process that runs in background. To make our program a daemon, we will first have to fork to detach from the main process to let it do its thing. Once we have done that, we will fork, make the child the session leader and then fork again without forgetting to kill the parent processes (except for the main thread of course). A last thing to do for our backdoor is to check that there is only one instance running (checking that before daemonizing would be great but it can be done afterwards). To check that the process is not already running, we can use UNIX socket. We will create one in /var/lock because that is the right place to do it. Once it is created, we can try to connect to it. If we cannot, it means that another instance of the backdoor is running.

What about RCE ?

We now have the ability to run a single instance of the program in background and make it do what we want so what do we want it to do ? To allow remote code execution, the best solution is to use TCP socket. Those are used to open a port and listen for an incoming connection. Since we want to be able to connect to it, we have to specify the port and not let the system decide about it. That would also work to check that we have a single instance running since we cannot use a port several times unless we modify the socket options but that would not work if we want to make our backdoor a bit fancier and add some functionalities like multi-client handling. The advantage of that is that the listen syscall will only return once it has received a connection so the backdoor will run indefinitely in background. Once this connection returns, it means a client has connected. Since our backdoor doesn’t do any fancy stuff like network traffic encoding for now, we don’t have to actually code a client and we can just use the netcat command. Giving RCE to our new client will be very easy once this one is connected. We will redirect all the standard fds (stdin, stdout and stderr) to the socket using the dup2 syscall and once that is done, we will substitute our process by /bin/sh using execve. Do not forget to specify the -i argument to /bin/sh to make the process interactive so that the client receives a prompt.

Conclusion

Good job, we made our very simple but also very effective backdoor. I might write another article later about how to make a more evolved backdoor that includes network-traffic encoding, ICMP exfiltration and other fancy features that will make it stealthier. Now that we have a proper malicious payload in our infector, let’s imagine that a reverse-engineer wants to try to check it out, it would be great to make its task harder with obfuscation. You can check that here.