This detection identifies adversaries who deploy Java Server Pages (JSP) webshells leveraging reflection to dynamically execute untrusted user input, a technique often used to establish persistent command-and-control channels on compromised servers. Proactive hunting for this behavior in Azure Sentinel is critical because reflective execution can bypass traditional signature-based defenses, allowing attackers to maintain stealthy access and escalate privileges within the organization’s Java application infrastructure.
rule WEBSHELL_JSP_Generic_Reflection
{
meta:
description = "Generic JSP webshell which uses reflection to execute user input"
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/07"
modified = "2024-12-09"
hash = "62e6c6065b5ca45819c1fc049518c81d7d165744"
hash = "bf0ff88cbb72c719a291c722ae3115b91748d5c4920afe7a00a0d921d562e188"
id = "806ffc8b-1dc8-5e28-ae94-12ad3fee18cd"
strings:
$ws_exec = "invoke" fullword wide ascii
$ws_class = "Class" fullword wide ascii
$fp1 = "SOAPConnection"
$fp2 = "/CORBA/"
//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_jsp_input
// request.getParameter
$input1 = "getParameter" fullword ascii wide
// request.getHeaders
$input2 = "getHeaders" fullword ascii wide
$input3 = "getInputStream" fullword ascii wide
$input4 = "getReader" fullword ascii wide
$req1 = "request" fullword ascii wide
$req2 = "HttpServletRequest" fullword ascii wide
$req3 = "getRequest" fullword ascii wide
$cj_encoded1 = "\"java.util.Base64$Decoder\"" ascii wide
condition:
//any of them or
all of ( $ws_* ) and (
$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 not any of ( $fp* ) and
(
// either some kind of code input from the a web request ...
filesize < 10KB and
(
any of ( $input* ) and
any of ( $req* )
)
or
(
// ... or some encoded payload (which might get code input from a web request)
filesize < 30KB and
any of ( $cj_encoded* ) and
// base64 :
// ignore first and last 500bytes because they usually contain code for decoding and executing
math.entropy(500, filesize-500) >= 5.5 and
// encoded text has a higher mean than text or code because it's missing the spaces and special chars with the low numbers
math.mean(500, filesize-500) > 80 and
// deviation of base64 is ~20 according to CyberChef_v9.21.0.html#recipe=Generate_Lorem_Ipsum(3,'Paragraphs')To_Base64('A-Za-z0-9%2B/%3D')To_Charcode('Space',10)Standard_Deviation('Space')
// lets take a bit more because it might not be pure base64 also include some xor, shift, replacement, ...
// 89 is the mean of the base64 chars
math.deviation(500, filesize-500, 89.0) < 23
)
)
}
This YARA rule can be deployed in the following contexts:
This rule contains 21 string patterns in its detection logic.
Scenario: Automated Build and Deployment Pipelines
.war files to the Tomcat/JBoss container. During the initialization phase, these pipelines may utilize Java reflection (e.g., java.lang.reflect.Method.invoke) to dynamically load configuration properties or execute post-deployment scripts based on user-defined parameters in the build YAML/DSL.10.20.30.x for Jenkins) and filter events where the HTTP User-Agent contains specific pipeline identifiers like Jenkins/2.4xx, GitLab-Runner, or Azure-Pipelines.Scenario: Scheduled Enterprise Backup and Reporting Jobs
/admin/report/generate or /backup/initiate.Scenario: Legacy Admin Portals with Dynamic Feature Toggles