Spot the Wolf in Sheep’s Clothing: Tips for Identifying Malicious Webshells

Stroz Friedberg is a specialized risk management firm built to help clients solve the complex challenges prevalent in today’s digital, connected, and regulated business world

It’s getting [even] harder to protect web servers that house public-facing services. Early detection of intruders is essential to preventing damage, but the enemy is becoming more difficult to spot. Already, organizations struggle to distinguish between an erratic user and one with malicious intent. Today’s Webshells are making this even more challenging.

Web servers have long been a very attractive attack surface. In the past couple of years there has been a significant increase in web attacks. For an attacker, web servers have five specific advantages:

  • The server is always available: You can’t block traffic to your public web server, and most have few explicit rules for blocking activity.
  • It’s easy to blend in: High-traffic, public websites are ideal environments for low and slow attacks. Well-crafted intrusions can often evade WAF and IPS appliances.
  • There are many potential exploits: As web stacks have gotten larger, attackers have more opportunities to find an open door. Even if the OS and web service are completely patched, it’s nearly impossible to combat poor coding practices.
  • Third-party hosting doesn’t mean you’re safe: Service providers make mistakes too, and your company is still on the hook for the damage.
  • Web servers are both an entrance and an exit: For an attacker, your web server is just as good for taking data out of your environment as it is for getting inside.

Webshells have been one of the most common methods used by attackers to establish and maintain a foothold on web servers. Over time, attackers have shared, sold, and combined Webshells to improve and customize their toolkits. Moreover, because of the dynamic nature of Webshells and the performance hindrance on a web server, antivirus is poorly suited to identify them.

But this doesn’t mean there’s nothing that can be done to identify them. Malicious Webshells can be spotted in two ways:

  • Searches for risky code that enable remote file inclusions or arbitrary file uploads.
  • Searches for common methods and techniques used in Webshells.

Below is a list of recommended searches for both means of identification. Compiling these searches into a script and running them weekly can help you detect malicious files. Because Apache/PHP is the most common web stack, I’ll recommend searches relevant to this environment.

Please note: Many of the functions and variables I recommend searching here also have valid uses. There is nothing wrong with using these so long as the inputs are properly sanitized.  Finding these strings doesn’t necessarily indicate an issue in your environment, but it may warrant a closer look.

Similarly, this list is not exhaustive and doesn’t account for many of the more complicated or obfuscated Webshells. If you don’t find any of these strings, it doesn’t guarantee your environment is free of vulnerabilities or malicious code.

If you think you’ve found a Webshell on your server, take your hands off the keyboard and contact your information security office immediately. The more action you take on a compromised server, the more evidence you destroy.

If there’s anything you think should be on this list, drop me an email:

Searches for Risky Code

Function\String Purpose Malicious use Grep
eval() Runs PHP code passed into the function. Can be used to run arbitrary PHP code. “eval\(“
assert() Used for testing for true\false cases, but can be used to execute PHP code the same as eval. Can be used to run arbitrary PHP code. “assert\(“
popen() Pipes a command into a new process. Can be used to execute shell commands. “popen\(“
proc_open() Similar to popen(), but with more options and allows two-way communication with the spawned process. Can be used to execute shell commands. “proc_open\(“
system() Executes a given command and clears the output buffer after each line of output. Can be used to execute shell commands. “system\(“
passthru() Similar to system, but the output is not cleared. Can be used to execute shell commands. “passthru\(“
shell_exec() Executes a command via shell and returns the output as a string. Can be used to execute shell commands. “shell_exec\(“
phpinfo() Outputs detailed information about PHP’s configuration. Can be used to get patch information and environment variables. “phpinfo\(“
$_FILES[] Super Global Variable used to upload files. Uploading files is very core to web servers, so this will likely have false positives.  However, you should always check to make sure only legitimate users can upload files and the file does not contain executable code or cannot be executed remotely. “\$_FILES\[\s*\$”
include()include_once()require()require_once() Includes and evaluates (executes) a specified file.  Failure to include a file will cause a warning.require() is similar to include(), but will cause a fatal error if the file cannot be found.include_path in php.ini can be configured to restrict from where files can be included. Including files is very core to PHP, so this will likely have false positives.  Make sure your include_path is specified and is as restrictive as possible.  Avoid passing an include as a variable. “(include|require)(_once)?\(“

Common Shell Methods and Functions

Function\String Purpose Malicious Use Grep
getenv() Used to get the value of an environment variable. Attackers need to know the value of certain environment variable to determine what actions they can perform on a system. “getenv\(“
ini_get()ini_get_all()ini_set() Gets the value of a configuration option.  ini_get_all() can be used to return all configuration options as an array.It is also possible to set configuration options. Attackers use this to get and set configuration information. “ini_get\(““ini_get_all\(\)”“ini_set\(“
get_current_user() Get the name of the owner of the currently running PHP script. Sometimes this command can tell the attacker what permissions he has (e.g. if PHP is running as root) “get_current_user\(\)”
set_time_limit() Sets the maximum execution for a PHP script.  Doesn’t include any time spent on external commands.The default is 30 seconds or as set in the php.ini file using max_execution_time. Attackers often attempt to disable the script execution time limit to avoid script interruption “set_time_limit\(“Or specifically for disables “set_time_limit\(0\)”
php_uname() Returns the operating system PHP is running on. Attackers use this to determine what commands to run and files to search for. “php_uname\(“
phpversion() Returns the version of the currently running PHP parser. Attackers use this to determine what vulnerabilities may exist and what commands may be available. “php_version\(“
error_reporting() Sets the error reporting level. Attackers often use this to prevent web shells from logging errors that may hint at their existence. “error_reporting\(“ or more specifically “error_reporting\(0\)”
gzinflate() Inflates a string compressed with DEFLATE. Commonly used obfuscate shells or to include additional exploit packages. “gzinfalte\(“
Base64 Encoding Base64 encoding is used to maintain binary data even when the transmission medium is textual.  Base64 is commonly used for image, file names that may have special localization, file uploads, and avoid delimiter collision. Attackers use Base64 to obfuscate webshells and encode additional exploit packages included within webshells.Likely to have false positives due to the heavy usage of Base64 encoding in web. ^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$

Additional String Searches

Strings Purpose Grep
$cmd$exec Attackers aren’t always creative.  Many shells use these variables to pass commands. “\$cmd”“\$exec”
c99c99shc99shellc99php c99 is one of the most popular and wide-spread shells.  It has numerous forks and changes.  Most variants still include some sort of signature in it. “c99(shell|sh|php)?”


Our lawyers don’t want to miss out on the fun and would like you to know that all of the posts are the opinions of the individual authors and don’t necessarily reflect the opinions or positions of Stroz Friedberg. The ideas and strategies discussed herein may not be appropriate for any one reader’s situation and are not meant to be construed as advice.

Risk Areas: Cyber

I am: Super-technical

Tags: cyber threats, Webshells, Web servers



Commentary, new discoveries, and innovative ideas right to your inbox.

Stroz Friedberg

Sorry! You are using an older browser which is not supported by this website.

Please download one of these free browsers to enjoy all our website has to offer:
Firefox, Chrome or Internet Explorer.