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