大家好,我是 Sukali,首次在信安之路上投稿,并获得免费加入信安之路知识星球的机会,同时解锁了信安之路成长平台、文库以及 POC 管理系统的使用权限,今天来为大家分享一下自己挖掘的一个 RCE 0day 的审计过程。
RCE 是远程代码执行或者远程命令执行的缩写,在案例讲解之前,先来聊聊 java 代码审计的一些基础知识:
Java 提供多个执行系统命令的方法,如果使用不当,会造成远程命令执行漏洞(RCE)。以下是 Java 常见的高危命令执行 API:
危险 API | 描述 | 漏洞等级 |
---|---|---|
Runtime.getRuntime().exec(cmd) | 直接执行 cmd,如果 cmd 由用户输入控制,可能导致 RCE。 | 高 |
ProcessBuilder.start() | 启动进程并执行命令,如果参数未严格过滤,可能被利用。 | 高 |
ScriptEngine.eval(script) | 执行 JavaScript 代码,可能导致远程代码执行。 | 高 |
GroovyShell.evaluate(script) | 执行 Groovy 代码,如果 script 可控,则可能被攻击者利用。 | 高 |
在通过对其手工代码审计发现在dbBackUp方法中存在命令执行的功能。并将sb数组作为参数传入执行。Sb数组中在没有过滤的情况下添加了pathSql变量,该变量由backPath+backName组成。
从图片中的代码可以看到
String pathSql = backPath + backName;
sb.append(" " + pathSql);
Process process = runtime.exec("cmd /c " + sb.toString());
Process process = runtime.exec("/home/mysql/mysql/bin/" + sb.toString());
通过查找 dbBackUp 函数的调用链可以发现在 process 方法中调用了 dbBackUp 方法并给其提供了fileUrl 以及 backName 参数,backName 参数是直接生成了一个以时间命名的 .sql 文件,我们关注 fileUrl 参数即可,fileUrl 是由 MappingCache.getValue 获取 FILE_LOCATION 得到:
String fileUrl = MappingCache.getValue(DOMAIN_COMMON, FILE_LOCATION);
问题:如果FILE_LOCATION变量的值可被攻击者控制,攻击者可以构造恶意路径或命令,导致远程命令执行(RCE)。
String[] split = val.split("&");
split("&") 解析用户输入,可能导致未受控的数据流,如果 val 由攻击者控制,也可能影响执行的 SQL 备份命令。
BackupDatabaseTemplate.dbBackUp(userName, password, databaseName, fileUrl, backName, port);
追踪 getValue 发现内容都是从 redis 中获取,现在只需要寻找在哪里写入 redis 中的即可
连接 Redis
redis = getJedis();
getJedis() 方法用于获取 Redis 连接。
这意味着数据存储在 Redis,getValue 只是读取 Redis 里的数据。
拼接 Redis Key
redis.get((domain + key + _SUFFIX_MAPPING).getBytes());
domain + key + _SUFFIX_MAPPING 组成 Redis键名。
通过 get() 方法从 Redis 获取数据。
反序列化数据
Object object = SerializeUtil.unserialize(redis.get(...));
代码使用 SerializeUtil.unserialize() 反序列化数据。
如果 Redis 存储的是序列化对象,那么这里会将其还原为 Java 对象。
返回数据
Mapping mapping = (Mapping) object;
return mapping.getValue();
反序列化的数据被转换为 Mapping 类型,并返回 getValue()。
在前端寻找 FILE_LOCATION 发现在通用配置中可以配置 FILE_LOCATION 内容。
回到 process 方法我们查看调用链发现 startTask 中引用了 process,继续跟进
发现在 job.runJob 服务中的 doCmd 引用了 startTask 方法
继续查找调用可以找到 invokeListener 方法中引用 doCmd 方法
继续跟进上一个调用函数则是 multicastEvent 方法
省略其他冗余的调用方法追踪,最后是在 Service 的 post 请求方法下调用含有漏洞的
方法链
完整调用链
tmp/ || calc.exe || 保存到
调用 job.runJob 服务成功命令执行
成功执行
ProcessBuilder pb = new ProcessBuilder(
"mysqldump",
"-h", "3306",
"-u", "root",
"-p", "password",
"-r", "/safe/path/backup.sql"
);
pb.start();
if (!backPath.startsWith("/var/backups/")) {
throw new SecurityException("非法备份路径!");
}
if (!backName.matches("[a-zA-Z0-9_-]+\\.sql")) {
throw new IllegalArgumentException("非法文件名!");
}
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有