This hunt hypothesis targets adversaries deploying C# webshells to establish persistent remote access and execute arbitrary commands on compromised servers. Proactive hunting for these artifacts within Azure Sentinel is critical because C# webshells often evade standard signature-based detection, allowing attackers to maintain stealthy control over the environment before initiating lateral movement or data exfiltration.
rule WEBSHELL_CSHARP_Generic
{
meta:
description = "Webshell in c#"
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 = "b6721683aadc4b4eba4f081f2bc6bc57adfc0e378f6d80e2bfa0b1e3e57c85c7"
date = "2021/01/11"
modified = "2023-07-05"
hash = "4b365fc9ddc8b247a12f4648cd5c91ee65e33fae"
hash = "019eb61a6b5046502808fb5ab2925be65c0539b4"
hash = "620ee444517df8e28f95e4046cd7509ac86cd514"
hash = "a91320483df0178eb3cafea830c1bd94585fc896"
id = "6d38a6b0-b1d2-51b0-9239-319f1fea7cae"
strings:
$input_http = "Request." nocase wide ascii
$input_form1 = "<asp:" nocase wide ascii
$input_form2 = ".text" nocase wide ascii
$exec_proc1 = "new Process" nocase wide ascii
$exec_proc2 = "start(" nocase wide ascii
$exec_shell1 = "cmd.exe" nocase wide ascii
$exec_shell2 = "powershell.exe" nocase wide ascii
//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
condition:
(
(
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
)
)
)
and filesize < 300KB and
( $input_http or all of ( $input_form* ) ) and all of ( $exec_proc* ) and any of ( $exec_shell* )
}
This YARA rule can be deployed in the following contexts:
This rule contains 31 string patterns in its detection logic.
Here are 5 specific false positive scenarios for the WEBSHELL_CSHARP_Generic detection rule, including targeted filters and exclusions:
Scenario: Automated Build & Deployment Pipelines
.dll assemblies to web servers. These processes often involve the creation of temporary C# scripts (*.cs) or compiled executables in IIS directories that mimic webshell behavior.C:\Program Files\Azure DevOps Agent\_work\* or D:\Jenkins\workspace\builds\) and filter out processes spawned by the specific service accounts used for deployment (e.g., NT SERVICE\BuildAgent).Scenario: Scheduled Health Check & Reporting Scripts
C:\inetpub\wwwroot) and create temporary .cs files, triggering the rule’s logic for remote code execution artifacts.SchTasks.exe or specific scheduled task names containing keywords like “HealthCheck” or “ReportGen”. Additionally, filter out file creations occurring strictly during maintenance windows (e.g., 02:00–04:00 UTC).Scenario: Legitimate Admin Maintenance via PowerShell
powershell.exe to