This detection identifies adversaries establishing persistent backdoors by deploying PHP webshells that dynamically execute obfuscated code via the eval() function to evade signature-based analysis. Proactive hunting for this behavior in Azure Sentinel is critical because these stealthy entry points often serve as initial footholds for lateral movement and data exfiltration, requiring immediate investigation before attackers can fully compromise the environment.
rule WEBSHELL_PHP_OBFUSC_Fopo
{
meta:
description = "PHP webshell which eval()s obfuscated string"
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
hash = "fbcff8ea5ce04fc91c05384e847f2c316e013207"
hash = "6da57ad8be1c587bb5cc8a1413f07d10fb314b72"
hash = "a698441f817a9a72908a0d93a34133469f33a7b34972af3e351bdccae0737d99"
date = "2021/01/12"
modified = "2023-04-05"
id = "a298e99d-1ba8-58c8-afb9-fc988ea91e9a"
strings:
$payload = /(\beval[\t ]{0,500}\([^)]|\bassert[\t ]{0,500}\([^)])/ nocase wide ascii
// ;@eval(
$one1 = "7QGV2YWwo" wide ascii
$one2 = "tAZXZhbC" wide ascii
$one3 = "O0BldmFsK" wide ascii
$one4 = "sAQABlAHYAYQBsACgA" wide ascii
$one5 = "7AEAAZQB2AGEAbAAoA" wide ascii
$one6 = "OwBAAGUAdgBhAGwAKA" wide ascii
// ;@assert(
$two1 = "7QGFzc2VydC" wide ascii
$two2 = "tAYXNzZXJ0K" wide ascii
$two3 = "O0Bhc3NlcnQo" wide ascii
$two4 = "sAQABhAHMAcwBlAHIAdAAoA" wide ascii
$two5 = "7AEAAYQBzAHMAZQByAHQAKA" wide ascii
$two6 = "OwBAAGEAcwBzAGUAcgB0ACgA" wide ascii
//strings from private rule capa_php_old_safe
$php_short = "<?" wide ascii
// prevent xml and asp from hitting with the short tag
$no_xml1 = "<?xml version" nocase wide ascii
$no_xml2 = "<?xml-stylesheet" nocase wide ascii
$no_asp1 = "<%@LANGUAGE" nocase wide ascii
$no_asp2 = /<script language="(vb|jscript|c#)/ nocase wide ascii
$no_pdf = "<?xpacket"
// of course the new tags should also match
// already matched by "<?"
$php_new1 = /<\?=[^?]/ wide ascii
$php_new2 = "<?php" nocase wide ascii
$php_new3 = "<script language=\"php" nocase wide ascii
condition:
filesize < 3000KB and (
(
(
$php_short in (0..100) or
$php_short in (filesize-1000..filesize)
)
and not any of ( $no_* )
)
or any of ( $php_new* )
)
and $payload and
( any of ( $one* ) or any of ( $two* ) )
}
This YARA rule can be deployed in the following contexts:
This rule contains 22 string patterns in its detection logic.
Here are 5 specific false positive scenarios for the PHP webshell which eval()s obfuscated string detection rule, including suggested filters or exclusions:
Scenario: Automated Backup Script Execution via Cron
cron triggered) executes a PHP script (backup_handler.php) that dynamically constructs and evaluates an obfuscated SQL query string to log database changes. The script uses eval(base64_decode(...)) for modular configuration loading, which mimics webshell behavior.cron or systemd-timer AND the file path matches the known backup directory (e.g., /var/www/scripts/maintenance/backup_handler.php).Scenario: Legitimate CMS Plugin Updates
10.20.x.x) AND the file path contains /wp-content/plugins/advanced-cron/.Scenario: CI/CD Pipeline Deployment Artifacts
eval() on an obfuscated JSON string containing deployment metadata.jenkins-agent or gitlab-runner AND the execution time falls within the defined maintenance window (