This detection identifies potential webshell deployments by analyzing incoming traffic for characteristic command execution patterns and suspicious string signatures often associated with remote access tools. Proactively hunting for these indicators in Azure Sentinel is critical to uncovering early-stage post-exploitation activities that adversaries use to establish persistent footholds within the network before escalating their impact.
rule WEBSHELL_Generic_OS_Strings : FILE {
meta:
description = "typical webshell strings"
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"
date = "2021/01/12"
modified = "2024-12-09"
score = 50
hash = "d5bfe40283a28917fcda0cefd2af301f9a7ecdad"
hash = "fd45a72bda0a38d5ad81371d68d206035cb71a14"
hash = "b4544b119f919d8cbf40ca2c4a7ab5c1a4da73a3"
hash = "569259aafe06ba3cef9e775ee6d142fed6edff5f"
hash = "48909d9f4332840b4e04b86f9723d7427e33ac67"
hash = "0353ae68b12b8f6b74794d3273967b530d0d526f"
id = "ea85e415-4774-58ac-b063-0f5eb535ec49"
strings:
$fp1 = "http://evil.com/" wide ascii
$fp2 = "denormalize('/etc/shadow" wide ascii
$fp3 = "vim.org>"
//strings from private rule capa_asp
$tagasp_short1 = /<%[^"]/ wide ascii
// also looking for %> to reduce fp (yeah, short atom but seldom since special chars)
$tagasp_short2 = "%>" wide ascii
// classids for scripting host etc
$tagasp_classid1 = "72C24DD5-D70A-438B-8A42-98424B88AFB8" nocase wide ascii
$tagasp_classid2 = "F935DC22-1CF0-11D0-ADB9-00C04FD58A0B" nocase wide ascii
$tagasp_classid3 = "093FF999-1EA0-4079-9525-9614C3504B74" nocase wide ascii
$tagasp_classid4 = "F935DC26-1CF0-11D0-ADB9-00C04FD58A0B" nocase wide ascii
$tagasp_classid5 = "0D43FE01-F093-11CF-8940-00A0C9054228" nocase wide ascii
$tagasp_long10 = "<%@ " wide ascii
// <% eval
$tagasp_long11 = /<% \w/ nocase wide ascii
$tagasp_long12 = "<%ex" nocase wide ascii
$tagasp_long13 = "<%ev" nocase wide ascii
// <%@ LANGUAGE = VBScript.encode%>
// <%@ Language = "JScript" %>
// <%@ WebHandler Language="C#" class="Handler" %>
// <%@ WebService Language="C#" Class="Service" %>
// <%@Page Language="Jscript"%>
// <%@ Page Language = Jscript %>
// <%@PAGE LANGUAGE=JSCRIPT%>
// <%@ Page Language="Jscript" validateRequest="false" %>
// <%@ Page Language = Jscript %>
// <%@ Page Language="C#" %>
// <%@ Page Language="VB" ContentType="text/html" validaterequest="false" AspCompat="true" Debug="true" %>
// <script runat="server" language="JScript">
// <SCRIPT RUNAT=SERVER LANGUAGE=JSCRIPT>
// <SCRIPT RUNAT=SERVER LANGUAGE=JSCRIPT>
// <msxsl:script language="JScript" ...
$tagasp_long20 = /<(%|script|msxsl:script).{0,60}language="?(vb|jscript|c#)/ nocase wide ascii
$tagasp_long32 = /<script\s{1,30}runat=/ wide ascii
$tagasp_long33 = /<SCRIPT\s{1,30}RUNAT=/ wide ascii
// avoid hitting php
$php1 = "<?php"
$php2 = "<?="
// avoid hitting jsp
$jsp1 = "=\"java." wide ascii
$jsp2 = "=\"javax." wide ascii
$jsp3 = "java.lang." wide ascii
$jsp4 = "public" fullword wide ascii
$jsp5 = "throws" fullword wide ascii
$jsp6 = "getValue" fullword wide ascii
$jsp7 = "getBytes" fullword wide ascii
$perl1 = "PerlScript" fullword
//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
//strings from private rule capa_jsp_safe
$cjsp_short1 = "<%" ascii wide
$cjsp_short2 = "%>" wide ascii
$cjsp_long1 = "<jsp:" ascii wide
$cjsp_long2 = /language=[\"']java[\"\']/ ascii wide
// JSF
$cjsp_long3 = "/jstl/core" ascii wide
$cjsp_long4 = "<%@p" nocase ascii wide
$cjsp_long5 = "<%@ " nocase ascii wide
$cjsp_long6 = "<% " ascii wide
$cjsp_long7 = "< %" ascii wide
//strings from private rule capa_os_strings
// windows = nocase
$w1 = "net localgroup administrators" nocase wide ascii
$w2 = "net user" nocase wide ascii
$w3 = "/add" nocase wide ascii
// linux stuff, case sensitive:
$l1 = "/etc/shadow" wide ascii
$l2 = "/etc/ssh/sshd_config" wide ascii
$take_two1 = "net user" nocase wide ascii
$take_two2 = "/add" nocase wide ascii
condition:
filesize < 70KB and
( (
(
any of ( $tagasp_long* ) or
// TODO : yara_push_private_rules.py doesn't do private rules in private rules yet
any of ( $tagasp_classid* ) or
(
$tagasp_short1 and
$tagasp_short2 in ( filesize-100..filesize )
) or (
$tagasp_short2 and (
$tagasp_short1 in ( 0..1000 ) or
$tagasp_short1 in ( filesize-1000..filesize )
)
)
) and not (
(
any of ( $perl* ) or
$php1 at 0 or
$php2 at 0
) or (
( #jsp1 + #jsp2 + #jsp3 ) > 0 and ( #jsp4 + #jsp5 + #jsp6 + #jsp7 ) > 0
)
)
)
or (
(
(
$php_short in (0..100) or
$php_short in (filesize-1000..filesize)
)
and not any of ( $no_* )
)
or any of ( $php_new* )
)
or (
$cjsp_short1 at 0 or
any of ( $cjsp_long* ) or
($cjsp_short1 and $cjsp_short2 in ( filesize-100..filesize )) or
(
$cjsp_short2 and (
$cjsp_short1 in ( 0..1000 ) or
$cjsp_short1 in ( filesize-1000..filesize )
)
)
)
) and (
filesize < 300KB and
not uint16(0) == 0x5a4d and (
all of ( $w* ) or
all of ( $l* ) or
2 of ( $take_two* )
)
)
and not any of ( $fp* )
}
This YARA rule can be deployed in the following contexts:
This rule contains 52 string patterns in its detection logic.
Here are 5 specific false positive scenarios for the “typical webshell strings” detection rule, including suggested filters and exclusions:
Automated Backup Scripts Executing via Cron
/var/www/html, C:\inetpub\wwwroot) containing standard webshell signatures like <?php system($_GET['cmd']); ?> within their log processing or status reporting modules.*backup_agent*.py, *status_report.php) and restrict the rule to trigger only on files created outside of defined maintenance windows (e.g., 02:00–04:00).CI/CD Pipeline Artifact Deployment
eval($_POST['code'])) which are part of the deployment manifest rather than malicious uploads.svc-jenkins, ci-deploy-bot) and exclude file extensions typically used for build artifacts like .jar, .war, or specific directories named /deploy-artifacts or \builds.Web Application Framework Auto-Generated Files