This rule detects webshells that execute dynamic code through HTTP GET requests using eval or assert functions, a technique often used to bypass standard POST-based detection mechanisms and establish persistent command-and-control channels. Proactively hunting for this behavior in Azure Sentinel is critical because these lightweight GET-based payloads frequently evade traditional signature rules, allowing adversaries to maintain stealthy access while executing arbitrary commands on compromised web servers.
rule WEBSHELL_PHP_Function_Via_Get
{
meta:
description = "Webshell which sends eval/assert via GET"
license = "Detection Rule License 1.1 https://github.com/Neo23x0/signature-base/blob/master/LICENSE"
author = "Arnim Rupp (https://github.com/ruppde)"
reference = "Internal Research"
score = 75
date = "2021/01/09"
modified = "2023-04-05"
hash = "ce739d65c31b3c7ea94357a38f7bd0dc264da052d4fd93a1eabb257f6e3a97a6"
hash = "d870e971511ea3e082662f8e6ec22e8a8443ca79"
hash = "73fa97372b3bb829835270a5e20259163ecc3fdbf73ef2a99cb80709ea4572be"
id = "5fef1063-2f9f-516e-86f6-cfd98bb05e6e"
strings:
$sr0 = /\$_GET\s?\[.{1,30}\]\(\$_GET\s?\[/ wide ascii
$sr1 = /\$_POST\s?\[.{1,30}\]\(\$_GET\s?\[/ wide ascii
$sr2 = /\$_POST\s?\[.{1,30}\]\(\$_POST\s?\[/ wide ascii
$sr3 = /\$_GET\s?\[.{1,30}\]\(\$_POST\s?\[/ wide ascii
$sr4 = /\$_REQUEST\s?\[.{1,30}\]\(\$_REQUEST\s?\[/ wide ascii
$sr5 = /\$_SERVER\s?\[HTTP_.{1,30}\]\(\$_SERVER\s?\[HTTP_/ wide ascii
//strings from private rule php_false_positive
// try to use only strings which would be flagged by themselves as suspicious by other rules, e.g. eval
// a good choice is a string with good atom quality = ideally 4 unusual characters next to each other
$gfp1 = "eval(\"return [$serialised_parameter" // elgg
$gfp2 = "$this->assert(strpos($styles, $"
$gfp3 = "$module = new $_GET['module']($_GET['scope']);"
$gfp4 = "$plugin->$_POST['action']($_POST['id']);"
$gfp5 = "$_POST[partition_by]($_POST["
$gfp6 = "$object = new $_REQUEST['type']($_REQUEST['id']);"
$gfp7 = "The above example code can be easily exploited by passing in a string such as" // ... ;)
$gfp8 = "Smarty_Internal_Debug::start_render($_template);"
$gfp9 = "?p4yl04d=UNION%20SELECT%20'<?%20system($_GET['command']);%20?>',2,3%20INTO%20OUTFILE%20'/var/www/w3bsh3ll.php"
$gfp10 = "[][}{;|]\\|\\\\[+=]\\|<?=>?"
$gfp11 = "(eval (getenv \"EPROLOG\")))"
$gfp12 = "ZmlsZV9nZXRfY29udGVudHMoJ2h0dHA6Ly9saWNlbnNlLm9wZW5jYXJ0LWFwaS5jb20vbGljZW5zZS5waHA/b3JkZXJ"
condition:
filesize < 500KB and not (
any of ( $gfp* )
)
and any of ( $sr* )
}
This YARA rule can be deployed in the following contexts:
This rule contains 20 string patterns in its detection logic.
Here are 3-5 specific false positive scenarios for the “Webshell which sends eval/assert via GET” detection rule, including recommended filters and exclusions:
Scenario: CMS Plugin Updates via REST API
GET request to an endpoint containing serialized configuration data, which triggers the detection logic when the backend uses PHP’s eval() function to parse the incoming JSON payload on the fly.User-Agent: WordPress/6.x, Host: *.wp-admin.com) where the URL path contains /update-check or /api/config. Additionally, filter out requests where the query string length is less than 500 characters to avoid small configuration payloads.Scenario: Scheduled Health Check Jobs
eval() on the server side.10.20.x.x). Furthermore, exclude requests where the HTTP method is GET and the URL path matches /health, /status, or /ping, as these are standard maintenance endpoints unlikely to be malicious webshells.Scenario: Legacy Reporting Dashboard Queries