├── README.md └── shell.php /README.md: -------------------------------------------------------------------------------- 1 | shell.php 2 | ========= 3 | 4 | Web based shell access using PHP file! 5 | -------------------------------------------------------------------------------- /shell.php: -------------------------------------------------------------------------------- 1 | 'secret_password'); // change this! 3 | $home = realpath('.'); // config 4 | 5 | function authenticate($u) { 6 | if (!isset($_SERVER['PHP_AUTH_USER'])) die(header('WWW-Authenticate: Basic realm="shell.php"',401)); 7 | if (!isset($u[$_SERVER['PHP_AUTH_USER']]) || $u[$_SERVER['PHP_AUTH_USER']]!=$_SERVER['PHP_AUTH_PW']) die(); 8 | if ($_SERVER['PHP_AUTH_PW']=='secret_password') die('change default password in line 2 of shell.php'); 9 | } 10 | authenticate($users); 11 | 12 | $commands = array('view','edit','upload','download','own'); 13 | $style = <<'cd \'~\'','upload'=>'upload')); 32 | $processUser = posix_getpwuid(posix_geteuid()); 33 | $prompt = ''.$processUser['name'].'@'.php_uname('n').':~$ '; 34 | echo << 36 | 39 | 121 |
122 | 
123 | 
$prompt
124 |
$suggestions
125 | 126 | END_OF_HTML; 127 | } 128 | 129 | function expand($home,$dir,$path) 130 | { preg_match('/^(~?)(\/?)(.*)$/',$path,$matches); 131 | if ($matches[1]) @$newdir = $home.$matches[2].$matches[3]; 132 | else if ($matches[2]) @$newdir = $matches[2].$matches[3]; 133 | else @$newdir = $dir.'/'.$matches[3]; 134 | if (file_exists($newdir)) return realpath($newdir); 135 | return $newdir; 136 | } 137 | 138 | function alt_stat($file) 139 | { clearstatcache(); 140 | $ss=@stat($file); 141 | if(!$ss) return false; //Couldnt stat file 142 | 143 | $ts=array( 144 | 0140000=>'ssocket', 145 | 0120000=>'llink', 146 | 0100000=>'-file', 147 | 0060000=>'bblock', 148 | 0040000=>'ddir', 149 | 0020000=>'cchar', 150 | 0010000=>'pfifo', 151 | ); 152 | 153 | $p=$ss['mode']; 154 | $t=decoct($ss['mode'] & 0170000); // File Encoding Bit 155 | 156 | $str =(array_key_exists(octdec($t),$ts))?$ts[octdec($t)]{0}:'u'; 157 | $str.=(($p&0x0100)?'r':'-').(($p&0x0080)?'w':'-'); 158 | $str.=(($p&0x0040)?(($p&0x0800)?'s':'x'):(($p&0x0800)?'S':'-')); 159 | $str.=(($p&0x0020)?'r':'-').(($p&0x0010)?'w':'-'); 160 | $str.=(($p&0x0008)?(($p&0x0400)?'s':'x'):(($p&0x0400)?'S':'-')); 161 | $str.=(($p&0x0004)?'r':'-').(($p&0x0002)?'w':'-'); 162 | $str.=(($p&0x0001)?(($p&0x0200)?'t':'x'):(($p&0x0200)?'T':'-')); 163 | 164 | $type = substr($ts[octdec($t)],1); 165 | $owner = posix_getpwuid($ss['uid']); 166 | $group = posix_getgrgid($ss['gid']); 167 | 168 | $s=array( 169 | 'human'=>$str, 170 | 'owner'=>$owner['name'], 171 | 'group'=>$group['name'], 172 | 'realpath'=>@realpath($file), 173 | 'dirname'=>@dirname($file), 174 | 'basename'=>@basename($file), 175 | 'type'=>$type, 176 | 'type_octal'=>sprintf("%07o", octdec($t)), 177 | 'is_file'=>@is_file($file), 178 | 'is_dir'=>@is_dir($file), 179 | 'is_link'=>@is_link($file), 180 | 'is_readable'=> @is_readable($file), 181 | 'is_writable'=> @is_writable($file), 182 | 'device'=>$ss['dev'], //Device 183 | 'device_number'=>$ss['rdev'], //Device number, if device. 184 | 'inode'=>$ss['ino'], //File serial number 185 | 'link_count'=>$ss['nlink'], //link count 186 | 'link_to'=>($type=='link') ? @readlink($file) : '', 187 | 'size'=>$ss['size'], //Size of file, in bytes. 188 | 'blocks'=>$ss['blocks'], //Number 512-byte blocks allocated 189 | 'block_size'=> $ss['blksize'], //Optimal block size for I/O. 190 | 'accessed'=>@date('Y-m-d H:i',$ss['atime']), 191 | 'modified'=>@date('Y-m-d H:i',$ss['mtime']), 192 | 'created'=>@date('Y-m-d H:i',$ss['ctime']), 193 | ); 194 | 195 | clearstatcache(); 196 | return $s; 197 | } 198 | 199 | function links($commands) 200 | { $output = ''; 201 | foreach ($commands as $text=>$href) 202 | { $h = addslashes($href); 203 | if ($text=='rm') $output.= "$text "; 204 | else $output.= "$text "; 205 | } 206 | return $output; 207 | } 208 | 209 | function action($sdir,$s) 210 | { $commands = array(); 211 | $user = posix_getpwuid(posix_getuid()); 212 | $username = $user['name']; 213 | if ($s['is_dir']) 214 | { $b = escapeshellarg($s['basename']); 215 | if ($s['is_readable']) 216 | { $commands['cd'] = "cd $b"; 217 | } 218 | if ($s['is_writable']) 219 | { if ($s['basename']=='.') 220 | { $r = escapeshellarg(basename($s['realpath'].'_'.date('YmdHi').'.zip')); 221 | $d = escapeshellarg('.'); 222 | $commands['zip'] = "zip -r $r $d"; 223 | } 224 | if ($s['basename']!='.' && $s['basename']!='..') 225 | { $commands['rm'] = "rm -R $b"; 226 | } 227 | } 228 | } 229 | else if ($s['is_file']) 230 | { $t = escapeshellarg($s['basename'].'.tmp'); 231 | $b = escapeshellarg($s['basename']); 232 | if ($s['is_readable']) 233 | { $commands['view'] = "view $b"; 234 | $commands['download'] = "download $b"; 235 | } 236 | if ($s['is_writable']) 237 | { $commands['edit'] = "edit $b"; 238 | } 239 | if ($sdir['is_writable']) 240 | { if ($s['owner']!=$username) 241 | { $commands['own'] = "mv $b $t; cp $t $b; rm $t"; 242 | } 243 | $commands['rm'] = "rm $b"; 244 | if (preg_match('/^(.*)\.zip$/',$s['basename'],$matches)) 245 | { $d = escapeshellarg($matches[1]); 246 | $commands['unzip'] = "unzip $b -d $d"; 247 | } 248 | } 249 | } 250 | return links($commands); 251 | } 252 | 253 | function ls($flags,$dir) 254 | { $files = scandir($dir); 255 | $data = array(); 256 | $all = strpos($flags,'a')!==false; 257 | if (strpos($flags,'l')===false) $columns = array('basename'=>'l','action'=>''); 258 | else $columns = array('human'=>'l','link_count'=>'r','owner'=>'l','group'=>'l','size'=>'r','modified'=>'l','basename'=>'l','action'=>''); 259 | foreach (array_keys($columns) as $column) $data[$column] = array(); 260 | $sdir = alt_stat($dir); 261 | foreach($files as $file) 262 | { if (substr($file,0,1)=='.' && !$all) continue; 263 | $s = alt_stat($dir.'/'.$file); 264 | foreach ($columns as $column=>$align) 265 | { if ($column != 'action') $data[$column][] = $s[$column]; 266 | else $data[$column][] = action($sdir,$s); 267 | } 268 | } 269 | $output=''; 270 | $lengths = array(); 271 | foreach ($columns as $column=>$align) 272 | { $length[$column]=0; 273 | foreach ($data[$column] as $s) 274 | { $length[$column]=max($length[$column],strlen($s)); 275 | } 276 | } 277 | $rmax = count($data[$column]); 278 | for ($r=0;$r<$rmax;$r++) 279 | { foreach ($columns as $column=>$align) 280 | { $d = $data[$column][$r]; 281 | if ($align=='l') $d = str_pad($d, $length[$column], " ", STR_PAD_RIGHT); 282 | if ($align=='r') $d = str_pad($d, $length[$column], " ", STR_PAD_LEFT); 283 | if ($align=='c') $d = str_pad($d, $length[$column], " ", STR_PAD_BOTH); 284 | if ($column=='basename') $output.= ''.$d.' '; 285 | else $output.= $d.' '; 286 | } 287 | $output.= "\n"; 288 | } 289 | return $output; 290 | } 291 | 292 | function command() 293 | { global $home; 294 | $command = false; 295 | $dir = $home; 296 | $output = false; 297 | $processUser = posix_getpwuid(posix_geteuid()); 298 | $prompt = ''.$processUser['name'].'@'.php_uname('n').':~$ '; 299 | if (isset($_GET['command'])) $command = $_GET['command']; 300 | if (isset($_GET['dir'])) $dir = $_GET['dir']; 301 | $olddir = $dir; 302 | if (substr($dir,0,1)=='~') $dir = $home.substr($dir,1); 303 | header('Content-Type: text/plain'); 304 | $output = ''; 305 | if (preg_match('/^cd (.*)$/',trim($command),$matches)) 306 | { $argument = $matches[1]; 307 | $real = false; 308 | if (preg_match('/^\'(.*)\'|([^\'].*)$/',$argument,$matches)) 309 | { if (isset($matches[1])) $argument = $matches[1]; 310 | if (isset($matches[2])) $argument = $matches[2]; 311 | $real = expand($home,$dir,$argument); 312 | } 313 | if (!$argument || !$real || !file_exists($real)) 314 | { $output.="bash: $command: No such file or directory\n"; 315 | } 316 | else if (!is_readable($real)) 317 | { $output.="bash: $command: can't cd to directory\n"; 318 | } 319 | else 320 | { $dir = $real; 321 | } 322 | } 323 | else if (preg_match('/^ls( -[a-zA-Z0-9]+)?( \'(.+)\')?/',$command,$matches)) 324 | { $flags = ''; 325 | if (isset($matches[1])) $flags = substr($matches[1],2); 326 | if (isset($matches[2])) $real = expand($home,$dir,$matches[3]); 327 | else $real = realpath($dir); 328 | if (!file_exists($real)) 329 | { $output.="bash: $command($real): No such file or directory\n"; 330 | } 331 | else 332 | { $output.=ls($flags,$real); 333 | } 334 | } 335 | else 336 | { chdir($dir); 337 | $output=myshellexec($command." 2>&1"); 338 | } 339 | if (substr($dir,0,strlen($home))==$home) $dir = '~'.substr($dir,strlen($home)); 340 | $output = $processUser['name'].'@'.php_uname('n').':'.$olddir.'$ '.$command."\n".$output; 341 | echo json_encode(array('dir'=>$dir,'output'=>$output)); 342 | } 343 | 344 | function myshellexec($cfe) 345 | { $res = ''; 346 | if (!empty($cfe)) 347 | { if(@function_exists('passthru')) 348 | { @ob_start(); 349 | @passthru($cfe); 350 | $res = @ob_get_contents(); 351 | @ob_end_clean(); 352 | } 353 | elseif(@function_exists('exec')) 354 | { @exec($cfe,$res); 355 | $res = join("\n",$res); 356 | } 357 | elseif(@function_exists('shell_exec')) 358 | { $res = @shell_exec($cfe); 359 | } 360 | elseif(@function_exists('system')) 361 | { @ob_start(); 362 | @system($cfe); 363 | $res = @ob_get_contents(); 364 | @ob_end_clean(); 365 | } 366 | elseif(@is_resource($f = @popen($cfe,"r"))) 367 | { $res = ""; 368 | if (@function_exists('fread') &&@function_exists('feof')) 369 | { while(!@feof($f)) {$res .= @fread($f,1024);} 370 | } 371 | elseif(@function_exists('fgets') &&@function_exists('feof')) 372 | { while(!@feof($f)) {$res .= @fgets($f,1024);} 373 | } 374 | @pclose($f); 375 | } 376 | elseif(@is_resource($f = @proc_open($cfe,array(1 =>array("pipe","w")),$pipes))) 377 | { $res = ""; 378 | if(@function_exists('fread') &&@function_exists('feof')) 379 | { while(!@feof($pipes[1])) {$res .= @fread($pipes[1],1024);} 380 | } 381 | elseif(@function_exists('fgets') &&@function_exists('feof')) 382 | { while(!@feof($pipes[1])) {$res .= @fgets($pipes[1],1024);} 383 | } 384 | @proc_close($f); 385 | } 386 | // see: https://github.com/mm0r1/exploits/blob/master/php-filter-bypass/exploit.php 387 | elseif(@function_exists('pwn')) 388 | { @ob_start(); 389 | pwn($cfe); 390 | $res = @ob_get_contents(); 391 | @ob_end_clean(); 392 | } 393 | } 394 | return $res; 395 | } 396 | 397 | function view() 398 | { global $home; 399 | if (!isset($_GET['directory'])) error_exit(false,'no directory specified'); 400 | if (!isset($_GET['argument'])) error_exit(false,'no argument specified'); 401 | $directory = $_GET['directory']; 402 | $argument = $_GET['argument']; 403 | $file = expand($home,$directory,$argument); 404 | $basename = basename($file); 405 | if (!file_exists($file)) error_exit(false,'cannot find file'); 406 | if (!is_file($file)) error_exit(false,'argument must be a file'); 407 | $content = file_get_contents($file); 408 | if (strpos($content,"\0")===false) 409 | { header('Content-Type: text/plain'); 410 | echo $content; 411 | } 412 | else if ($size = getimagesize($file)) 413 | { header('Content-Type: '.$size['mime']); 414 | echo $content; 415 | } 416 | else 417 | { header("Pragma: public"); // required 418 | header("Expires: 0"); 419 | header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); 420 | header("Cache-Control: private",false); // required for certain browsers 421 | header("Content-Type: ".mime_content_type($basename)); 422 | header("Content-Disposition: attachment; filename=\"$basename\""); 423 | header("Content-Transfer-Encoding: binary"); 424 | header("Content-Length: ".strlen($content)); 425 | ob_clean(); 426 | flush(); 427 | echo $content; 428 | } 429 | } 430 | 431 | function download() 432 | { global $home; 433 | if (!isset($_GET['directory'])) error_exit(false,'no directory specified'); 434 | if (!isset($_GET['argument'])) error_exit(false,'no argument specified'); 435 | $directory = $_GET['directory']; 436 | $argument = $_GET['argument']; 437 | $file = expand($home,$directory,$argument); 438 | $basename = basename($file); 439 | if (!file_exists($file)) error_exit(false,'cannot find file'); 440 | header("Pragma: public"); // required 441 | header("Expires: 0"); 442 | header("Cache-Control: must-revalidate, post-check=0, pre-check=0"); 443 | header("Cache-Control: private",false); // required for certain browsers 444 | header("Content-Type: ".mime_content_type($basename)); 445 | header("Content-Disposition: attachment; filename=\"$basename\""); 446 | header("Content-Transfer-Encoding: binary"); 447 | header("Content-Length: ".filesize($file)); 448 | ob_clean(); 449 | flush(); 450 | readfile($file); 451 | } 452 | 453 | function edit() 454 | { global $home; 455 | global $style; 456 | global $microAjax; 457 | if (!isset($_GET['directory'])) error_exit(false,'no directory specified'); 458 | if (!isset($_GET['argument'])) error_exit(false,'no argument specified'); 459 | $directory = $_GET['directory']; 460 | $argument = $_GET['argument']; 461 | $file = expand($home,$directory,$argument); 462 | $basename = basename($file); 463 | if (!file_exists($file)) error_exit(false,'cannot find file'); 464 | if (!is_file($file)) error_exit(false,'argument must be a file'); 465 | if (isset($_POST['text'])) 466 | { $text = $_POST['text']; 467 | if (file_put_contents($file,$text)) die('file saved'); 468 | else die('save failed'); 469 | } 470 | $content = file_get_contents($file); 471 | if (strpos($content,"\0")!==false) error_exit(false,'binary file detected'); 472 | $content = json_encode($content); 473 | echo << 475 | 478 | 495 | 496 |
497 | 498 | END_OF_HTML; 499 | } 500 | 501 | function error_exit($success,$message) 502 | { global $style; 503 | $result = $success?'SUCCEEDED':'FAILED'; 504 | $back = isset($_POST['overwrite'])?2:1; 505 | echo <<
507 | $result: $message
508 | 
509 | 
510 | END_OF_HTML; 511 | exit; 512 | } 513 | 514 | function upload() 515 | { global $home; 516 | global $style; 517 | if (!isset($_GET['directory'])) error_exit(false,'no directory specified'); 518 | $directory = $_GET['directory']; 519 | if (!is_writable($directory)) error_exit(false,'target directory not writable'); 520 | if (isset($_POST['overwrite'])) 521 | { $overwrite = $_POST['overwrite']=='yes'; 522 | $error = $_FILES["file"]["error"]; 523 | if ($error > 0) 524 | { switch($error) 525 | { case 1: error_exit(false,'file exceeds the upload_max_filesize'); 526 | case 2: error_exit(false,'file exceeds the MAX_FILE_SIZE'); 527 | case 3: error_exit(false,'file was only partially uploaded'); 528 | case 4: error_exit(false,'no file was uploaded'); 529 | case 5: error_exit(false,'missing a temporary folder'); 530 | case 6: error_exit(false,'no file was uploaded'); 531 | case 7: error_exit(false,'failed to write file to disk'); 532 | case 8: error_exit(false,'file upload stopped by extension'); 533 | default: error_exit(false,'upload failed'); 534 | } 535 | } 536 | $basename = $_FILES["file"]["name"]; 537 | $file = expand($home,$directory,$basename); 538 | if (file_exists($file) && !$overwrite) error_exit(false,'file already exists'); 539 | $tmp = $_FILES["file"]["tmp_name"]; 540 | if (!move_uploaded_file($tmp,$file)) error_exit(false,'file cannot be moved'); 541 | error_exit(true,'file uploaded'); 542 | } 543 | echo << 545 |
546 | 547 | 548 | 549 | 550 | 551 | 552 | yes 553 | no 554 | 555 | 556 | 557 |
558 | 559 | END_OF_HTML; 560 | exit; 561 | } 562 | 563 | $application = 'bash'; 564 | $applications = array_merge($commands,array()); 565 | $applications[] = 'bash'; 566 | $applications[] = 'command'; 567 | if (isset($_GET['application'])) $application = $_GET['application']; 568 | if (in_array($application,$applications)) call_user_func($application); 569 | 570 | --------------------------------------------------------------------------------