Business Directory Plugin for WordPress — Unauthenticated Time-Based Blind SQL Injection (CVE-2026-2576)
by SowatKheang · 2026-07-05
- Severity
- High
- CVE
- CVE-2026-2576
- Category
- web
- Affected product
- Business Directory Plugin (Easy Listing Directories) for WordPress
- Affected versions
- All versions <= 6.4.21 (patched in 6.4.22)
- Disclosed
- 2026-07-05
- Patch status
- patched
Tags
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-03 |
| Author / Researcher | SowatKheang |
| CVE / Advisory | CVE-2026-2576 |
| Category | web |
| Severity | High |
| CVSS Score | 7.5 (NVD) / 9.3 (Wordfence) |
| Status | Weaponized |
| Tags | wordpress, sqli, time-based-blind, business-directory-plugin, unauthenticated, cwe-89, wpdb, docker-lab |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | Business Directory Plugin (Easy Listing Directories) for WordPress |
| Versions Affected | All versions <= 6.4.21 (patched in 6.4.22) |
| Language / Platform | Python 3 (PoC) targeting PHP/WordPress + MySQL |
| Authentication Required | No |
| Network Access Required | Yes |
Summary
The Business Directory Plugin’s ORM query builder (class-db-query-set.php) safely parameterizes scalar filter values with $wpdb->prepare(), but falls back to raw string concatenation whenever a filter value is an array. The plugin’s checkout controller reads the payment request parameter and forwards it into this ORM layer, and because PHP automatically turns a payment[]=value query string into an array, an attacker can force the vulnerable array branch simply by using bracket notation. This allows an unauthenticated attacker to inject a boolean/time-based SQL payload into the payment_key filter and infer database contents through response timing. The included PoC is a full extraction tool (detection, table listing, table dumping, and arbitrary sub-query extraction) plus a Dockerized vulnerable WordPress lab for safe reproduction.
Vulnerability Details
Root Cause
In includes/db/class-db-query-set.php::filter_args(), array-typed filter values are concatenated directly into the SQL IN (...) clause ("$f IN ('" . implode("','", $v) . "')") without escaping, whereas scalar values go through $wpdb->prepare(). The checkout controller passes the payment request parameter directly into this filter.
Attack Vector
- Attacker sends
GET /?page_id=<bd_page>&wpbdp_view=checkout&payment[]=<payload>— the[]notation forces PHP to parsepaymentas an array. - The checkout controller passes the array value to
WPBDP_Payment::objects()->get(['payment_key' => $payment_id]). filter_args()detects the array type and builds the query via raw string concatenation instead of$wpdb->prepare().- A payload such as
key') AND IF((<condition>),SLEEP(N),0)-- -closes the string/parenthesis, introduces a conditionalSLEEP, and comments out the trailing SQL, creating a boolean/time oracle. Because the ORM executes the built query twice per request, delays are doubled (SLEEP(1) ≈ 2s observed). - Repeating the request with varying conditions/character positions (as automated by
poc.py) extracts arbitrary database content, including thewp_userstable.
Impact
Unauthenticated remote extraction of arbitrary database contents (WordPress credentials/password hashes, payment records, PII) via blind SQL injection.
Environment / Lab Setup
Target: WordPress + Business Directory Plugin 6.4.21 (Docker: WordPress, MySQL, phpMyAdmin — see docker-compose.yml / setup.sh / init-db.sql)
Attacker: Python 3.9+, `pip3 install requests colorama`
Proof of Concept
PoC Script
See
poc.py(extraction tool) andpatch_diff.py(vulnerable vs. patched version diff helper) in this folder. Lab bring-up files:docker-compose.yml,init-db.sql,setup.sh,uploads.ini.
| |
The script confirms the time-based oracle, then uses parallelized character-by-character boolean extraction (via IF(...,SLEEP(N),0)) to enumerate tables and dump arbitrary table contents or custom SQL sub-query results from the target database.
Detection & Indicators of Compromise
Signs of compromise:
- Repeated checkout-page requests with
payment[]=parameters containing SQL keywords (SLEEP,IF,UNION,--) - Consistent, incrementally-delayed response times from the same source IP against the checkout endpoint
- WAF/IDS alerts for SQL injection signatures on WordPress
wpbdp_view=checkoutrequests
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade Business Directory Plugin to version 6.4.22 or later, which applies esc_sql() to array-typed filter values in filter_args() |
| Interim mitigation | Block/alert on payment[]= (array-notation) query parameters at the WAF; disable or restrict the plugin’s checkout view until patched |
References
Notes
Mirrored from https://github.com/SowatKheang/CVE_2026_2576_PoC on 2026-07-05.
| |