HTTP backdoor using POSIX file capabilities and PHP

Use POSIX file capabilities and PHP to create a backdoor that opens a root back-channel to the attacker’s PC on port TCP 53 when a PHP page is called with a special url.

Article published on 18 June 2010
last modification on 29 May 2016

by Emeric Nasi

Note: In order to understand this document it is strongly recommended you already red POSIX file capabilities, the dark side
Also the author suppose the reader have a good base about GNU Linux and security.
License : Copyright Emeric Nasi, some rights reserved
This work is licensed under a Creative Commons Attribution 4.0 International License.
Creative Commons License

Introduction

I wrote an example of a tiny backdoor exploiting capabilities in my article
POSIX file capabilities, the dark side.
This backdoor was only a local backdoor that needed a local access shell to be launched.
I decided to create a more dangerous one that can be activated by a distant attacker via the Internet.

I decided this backdoor target would be web-servers.
The goal is to create a backdoor that opens a root back-channel to the attacker’s PC on port TCP 53 when a PHP page is called with a special URL.
I choose the port 53 because distant connexion to DNS servers are generally authorized by firewalls.
The backdoor binary will be hidden among the website images and unless the admin monitors the file-system
for suspect file capabilities, it will be very difficult to detect the backdoor.

Note : Remember this is only a backdoor, it supposed the attacker already gained root access.

I Create the backdoor

Now we imagine that we gained root access on a Linux web-server (I used Debian5 to run my tests).
How do you know the victim OS is vulnerable ?
grep -x "CONFIG_SECURITY_FILE_CAPABILITIES=y" /boot/config-<span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+Y2F0IC9wcm9jL3ZlcnNpb24gfCBjdXQgLWQgJnF1b3Q7ICZxdW90OyAtZiAzPC9jb2RlPg=="></span>
Should return : "CONFIG_SECURITY_FILE_CAPABILITIES=y"
OK we can now create the backdoor.

I.1 The binary

Our binary will be the smallest possible and do two things :

  • Escalate privileges to become root
  • Use netcat to create a back-channel

Create a file called backdoor.c and paste next code :

Note : The backdoor will only run if it is called with two arguments, the backdoor password (please), and the ip address nc will connect to.

Compile the backdoor and name it "02.png" :
gcc backdoor.c -o 02.png
Copy or compile the backdoor on the victim server. In our case we place it in the folder /var/www/ex/IMG.
Give execute permission to others (so that Apache can execute the backdoor) :
chmod 755 02.png
The user running apache under Debian is www_data. He will be the owner of the process and won’t be able to do the setuid(0) part...
Unless we use POSIX file capabilities! The particular capability we need here is the same as in the local backdoor described in the article
POSIX file capabilities, the dark side , the cap_setuid capability. A binary with this capability will be
able to run the setuid(0) function, thus any user running the binary can become a superuser (root with all capabilities enabled).
If libcap2-bin is installed on the web-server we can use setcap :
setcap cap_setuid=ep 02.png
If not (like in my case) you can upload the setcap binary from your system and it should work (Remember to remove the setcap binary after you used it).

I.2 The PHP code

We will use the PHP exec() function to call the backdoor. The next code can be hidden in any PHP file already existing on the web-server.
In our case we will place it at the beginning of the file /var/www/ex/test2.php.

Note : For the attacker, the drawback of this technique is that he has to control the PC accessing the web-server. If he passes trough a proxy there the backdoor will try to connect to the proxy instead. This could be fixed by sending the ip address in a POST field.

I.3 The remote channel server

On the attacker machine, we need to open a server listening on the port 53.
For more simplicity we will use (again!) netcat.
Open a file called nc53.sh and paste next code :

This little script keeps spawning netcat sessions listening on port 53. If you run this script, you will have to kill the nc53.sh and all nc process
to terminate it. If the attacker is using a Microsoft Windows system, a simple nc -L -p 53 command should be enough.

II Test the backdoor

I run my tests using VirtualBox. In my test, the attacker IP is 192.168.56.11, the victim web-server IP address is 192.168.56.4.
First, run the netcat server. On the attacker’s machine do :
./nc53.sh
The machine is now listening on port 53.

Next we call the backdoor. Just open Firefox and paste the next URL :
http://192.168.56.4/ex/test2.php?polite=please
If the backdoor install was successful, you should see the page indefinitely loading.
That is because of the PHP exec() function that won’t return before the binary has finished running. We do not care about it anymore, the connection is already done. Close Firefox.

Note : If you call test2.php without the polite=please values, the page will load as usual. The only one that can use the backdoor is the attacker. The backdoor is transparent to others.

Go back to the terminal where you ran the nc53.sh script.
Type the next command :
whoami
-> root
We gained a root shell on the web-server!!

Now we can do whatever we want.
For example, verify the latest apache logs :
tail /var/log/apache2/error.log

Note : Every error generated in the sh session will be logged in this file.

tail /var/log/apache2/access.log
... 192.168.56.11 - - [18/Jun/2010:22:19:22 +1000] "GET /ex/test2.php?polite=please HTTP/1.1" ...
This is our connection log (it can be deleted using sed)
We have others logs to check :
tail /var/log/auth.log
... Jun 18 22:39:01 debian-apache CRON[2710]: pam_unix(cron:session): session opened for user root by (uid=0)
etc etc

Note : The file /root/.bash_history will not contain anything as we do not use bash.

Detect the backdoor
The backdoor is a back-channel, that means that no server are listening on the victim machine.
Detecting the backdoor via opened sockets is only possible when
it is handled by the attacker. When it is the case you can detect the connection by doing :

We can see here that a process called sh and run by root is connected to 192.168.56.11 on port 53.
After the attacker typed "exit" in his shell, the connection is closed and there is no way to find the backdoor using port scanners or netstat/lsof.
To detect the backdoor the admin has to monitor the logs (providing that they weren’t erase). A better solution is to scan the file-system for dangerous file capabilities.

Conclusion

This backdoor is a proof of concept that could be improved (ssh back-channel, log cleaning, distant command, bot behavior, etc).
We showed that with a few lines of C and PHP code and the help of file capabilities, we can create a simple backdoor triggered via HTTP
that is very difficult to detect because it is hidden among the website’s common files.
Prevent that kind of backdoor is however very simple. Be sure you have the getcap tool on your server then download and install
Glyptodon to run regular file-system scans (including file capabilities scans).