This detection identifies adversaries establishing webshells on Azure-hosted web servers by leveraging VBScript or JScript with .Encode obfuscation to conceal malicious payloads containing suspicious strings. Proactive hunting for this behavior is critical in an Azure Sentinel environment to uncover stealthy post-exploitation access that often evades standard signature-based defenses, allowing the SOC team to isolate compromised endpoints before lateral movement occurs.
rule WEBSHELL_ASP_Encoded
{
meta:
description = "Webshell in VBscript or JScript encoded using *.Encode plus a suspicious 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
date = "2021/03/14"
modified = "2023-07-05"
hash = "1bc7327f9d3dbff488e5b0b69a1b39dcb99b3399"
hash = "9885ee1952b5ad9f84176c9570ad4f0e32461c92"
hash = "27a020c5bc0dbabe889f436271df129627b02196"
hash = "f41f8c82b155c3110fc1325e82b9ee92b741028b"
hash = "af40f4c36e3723236c59dc02f28a3efb047d67dd"
id = "67c0e1f6-6da5-569c-ab61-8b8607429471"
strings:
$encoded1 = "VBScript.Encode" nocase wide ascii
$encoded2 = "JScript.Encode" nocase wide ascii
$data1 = "#@~^" wide ascii
$sus1 = "shell" nocase wide ascii
$sus2 = "cmd" fullword wide ascii
$sus3 = "password" fullword wide ascii
$sus4 = "UserPass" fullword 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:
filesize < 500KB 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
)
)
)
and any of ( $encoded* ) and any of ( $data* ) and
( any of ( $sus* ) or
( filesize < 20KB and #data1 > 4 ) or
( filesize < 700 and #data1 > 0 ) )
}
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 in VBscript or JScript encoded using .Encode plus a suspicious string detection rule, including suggested filters and exclusions:
Scenario: Automated Backup Script Execution via PowerShell
cscript.exe or wscript.exe to run VBScript/JScript logic. These scripts frequently use System.Text.Encoding.UTF8.GetString(Convert.ToBase64String(...)) patterns which trigger the “Encode” signature, while containing internal strings like “BackupID” or “JobStatus” that match the “suspicious string” criteria.ParentProcessName is Veeam.Backup.Service.exe or Commvault.Client.Agent.exe. Additionally, filter out events where the command line contains specific backup keywords (e.g., -BackupID, -RestorePoint) and the file path resides within a known backup directory (e.g., C:\Program Files\Veeam\...).Scenario: Microsoft SCCM/Intune Application Deployment
ProcessName is ccmsetup.exe, WUAHandler.exe, or msiexec.exe. Apply a filter for command lines containing specific SCCM identifiers, such as SMS_CLIENT or IntuneManagementExtension, and restrict the scope to known