1 package com.jsql.view.swing.terminal;
2
3 import com.jsql.util.LogLevelUtil;
4 import org.apache.commons.lang3.StringUtils;
5 import org.apache.logging.log4j.LogManager;
6 import org.apache.logging.log4j.Logger;
7
8 import java.io.BufferedReader;
9 import java.io.DataOutputStream;
10 import java.io.IOException;
11 import java.io.InputStreamReader;
12 import java.net.Socket;
13
14 public class ServerInputConnection {
15
16 private static final Logger LOGGER = LogManager.getRootLogger();
17
18 private final BufferedReader bufferedReader;
19 private final Socket clientSocket;
20 private final ServerInput serverInput;
21 private final ExploitReverseShell exploitReverseShell;
22 private boolean running = true;
23 private String command;
24
25 public ServerInputConnection(ExploitReverseShell exploitReverseShell, Socket clientSocket, ServerInput serverInput) throws IOException {
26 this.clientSocket = clientSocket;
27 this.exploitReverseShell = exploitReverseShell;
28 this.serverInput = serverInput;
29 LOGGER.log(LogLevelUtil.CONSOLE_SUCCESS, "Reverse established by {}", clientSocket);
30 LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Type 'exit' in reverse shell to close the connection");
31 this.bufferedReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
32 }
33
34 public void run() throws IOException {
35 try (DataOutputStream dataOutputStream = new DataOutputStream(this.clientSocket.getOutputStream())) {
36 Thread readerThread = new Thread(() -> {
37 try {
38 this.handleSocketReading();
39 } catch (IOException e) {
40 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Error reading from socket: {}", e.getMessage());
41 } finally {
42 this.closeResources();
43 }
44 });
45 readerThread.start();
46
47 while (this.running) {
48 this.processAndSendCommand(dataOutputStream);
49 }
50
51 try {
52 readerThread.join(2000);
53 } catch (InterruptedException e) {
54 Thread.currentThread().interrupt();
55 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Reader thread interrupted");
56 }
57 }
58 }
59
60 private void processAndSendCommand(DataOutputStream dataOutputStream) throws IOException {
61 if (StringUtils.isNotEmpty(this.command)) {
62 var commandWithoutPrompt = this.command.replaceAll("[^$]*\\$\\s*", "");
63 this.command = null;
64 dataOutputStream.writeBytes(commandWithoutPrompt + "\n");
65 }
66 }
67
68 private void handleSocketReading() throws IOException {
69 int length = 1024;
70 char[] buffer = new char[length];
71 int charsRead;
72 while (this.running) {
73 charsRead = this.bufferedReader.read(buffer, 0, length);
74 if (charsRead != -1) {
75 String result = new String(buffer, 0, charsRead);
76 this.exploitReverseShell.append(result.matches("\\$$") ? result +" " : result);
77 this.exploitReverseShell.reset(false);
78 } else {
79 break;
80 }
81 }
82 }
83
84 private void closeResources() {
85 try {
86 LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Reverse connection closed");
87 this.running = false;
88 this.serverInput.close();
89 } catch (IOException e) {
90 LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, "Error closing resources: {}", e.getMessage());
91 }
92 }
93
94 public void setCommand(String command) {
95 this.command = command;
96 }
97 }