1
2
3
4
5
6
7
8
9
10
11 package com.jsql.view.swing.tab;
12
13 import com.formdev.flatlaf.extras.FlatSVGIcon;
14 import com.jsql.model.bean.database.AbstractElementDatabase;
15 import com.jsql.util.I18nUtil;
16 import com.jsql.util.LogLevelUtil;
17 import com.jsql.util.StringUtil;
18 import com.jsql.util.reverse.ModelReverse;
19 import com.jsql.view.swing.action.ActionCloseTabResult;
20 import com.jsql.view.swing.action.HotkeyUtil;
21 import com.jsql.view.swing.popupmenu.JPopupMenuText;
22 import com.jsql.view.swing.tab.dnd.DnDTabbedPane;
23 import com.jsql.view.swing.tab.dnd.TabTransferHandler;
24 import com.jsql.view.swing.table.PanelTable;
25 import com.jsql.view.swing.terminal.AbstractExploit;
26 import com.jsql.view.swing.terminal.ExploitReverseShell;
27 import com.jsql.view.swing.text.JPopupTextArea;
28 import com.jsql.view.swing.text.JTextFieldPlaceholder;
29 import com.jsql.view.swing.util.MediatorHelper;
30 import com.jsql.view.swing.util.RadioItemPreventClose;
31 import com.jsql.view.swing.util.UiStringUtil;
32 import com.jsql.view.swing.util.UiUtil;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.logging.log4j.LogManager;
35 import org.apache.logging.log4j.Logger;
36
37 import javax.swing.*;
38 import javax.swing.event.HyperlinkEvent;
39 import java.awt.*;
40 import java.awt.event.*;
41 import java.io.IOException;
42 import java.net.MalformedURLException;
43 import java.net.URISyntaxException;
44 import java.util.Arrays;
45 import java.util.List;
46 import java.util.UUID;
47 import java.util.function.BiConsumer;
48 import java.util.function.IntConsumer;
49
50
51
52
53 public class TabResults extends DnDTabbedPane {
54
55
56
57
58 private static final Logger LOGGER = LogManager.getRootLogger();
59
60 public static final String TAB_EXPLOIT_FAILURE_INCORRECT_URL = "Tab exploit failure: incorrect URL";
61 public static final String RCE_SHELL = "RCE shell";
62 public static final String SQL_SHELL = "sqlShell";
63 public static final String WEB_SHELL = "webShell";
64 public static final String REV_SHELL = "revShell";
65 public static final String REVERSE_SHELL = "Reverse shell";
66
67
68
69
70 public TabResults() {
71 this.setName("tabResults");
72 this.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
73 this.setTransferHandler(new TabTransferHandler());
74 this.putClientProperty("JTabbedPane.tabClosable", true);
75 this.putClientProperty("JTabbedPane.tabCloseCallback", (IntConsumer) ActionCloseTabResult::perform);
76 UIManager.put("TabbedPane.closeHoverForeground", LogLevelUtil.COLOR_RED);
77 HotkeyUtil.addShortcut(this);
78 this.addMouseWheelListener(new TabbedPaneMouseWheelListener());
79 MediatorHelper.register(this);
80 }
81
82 public void addFileTab(String label, String content, String path) {
83 JTextArea fileText = new JPopupTextArea().getProxy();
84 fileText.setText(content);
85 fileText.setFont(new Font(UiUtil.FONT_NAME_MONO_NON_ASIAN, Font.PLAIN, 14));
86 fileText.setCaretPosition(0);
87 this.addTextTab(label, path, fileText, UiUtil.DOWNLOAD.getIcon());
88 MediatorHelper.tabManagersCards().addToLists(path, label);
89 }
90
91 public void addReportTab(String content) {
92 JEditorPane editorPane = new JEditorPane();
93 editorPane.setContentType("text/html");
94 editorPane.setText("<html><span style=\"white-space: nowrap; font-family:'"+ UiUtil.FONT_NAME_MONO_NON_ASIAN +"'\">" + content + "</span></html>");
95 editorPane.setFont(UIManager.getFont("TextArea.font"));
96 editorPane.setDragEnabled(true);
97 editorPane.setEditable(false);
98 editorPane.setCaretPosition(0);
99 editorPane.getCaret().setBlinkRate(0);
100 editorPane.setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR));
101 editorPane.setComponentPopupMenu(new JPopupMenuText(editorPane));
102 editorPane.addHyperlinkListener(linkEvent -> {
103 if (HyperlinkEvent.EventType.ACTIVATED.equals(linkEvent.getEventType())) {
104 try {
105 Desktop.getDesktop().browse(linkEvent.getURL().toURI());
106 } catch (IOException | URISyntaxException | UnsupportedOperationException e) {
107 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, "Failing to browse Url", e);
108 }
109 }
110 });
111 editorPane.addFocusListener(new FocusAdapter() {
112 @Override
113 public void focusGained(FocusEvent focusEvent) {
114 editorPane.getCaret().setVisible(true);
115 editorPane.getCaret().setSelectionVisible(true);
116 editorPane.getCaret().setBlinkRate(0);
117 }
118 });
119 UiUtil.init(editorPane);
120
121 this.addTextTab("Vulnerability report", "Analysis report with all payloads detected", editorPane, UiUtil.APP_ICON.getIcon());
122 }
123
124 public void addTextTab(String label, String toolTipText, JComponent componentText, FlatSVGIcon icon) {
125 var scroller = new JScrollPane(componentText);
126 this.addTab(label + StringUtils.SPACE, scroller);
127 this.setSelectedComponent(scroller);
128 this.setToolTipTextAt(this.indexOfComponent(scroller), toolTipText);
129 var header = new TabHeader(label, icon);
130 this.setTabComponentAt(this.indexOfComponent(scroller), header);
131
132 this.updateUI();
133 }
134
135 public void addTabExploitWeb(String url) {
136 try {
137 var terminalID = UUID.randomUUID();
138 var terminal = new AbstractExploit(terminalID, url, "web") {
139 @Override
140 public void action(String command, UUID terminalID, String urlShell, String... arg) {
141 MediatorHelper.model().getResourceAccess().runWebShell(command, terminalID, urlShell);
142 }
143 };
144 terminal.setName(TabResults.WEB_SHELL);
145 MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);
146
147 JPanel panelTerminalWithReverse = this.getTerminalWithMenu(terminal);
148 this.addTab("Web shell", panelTerminalWithReverse);
149 this.setSelectedComponent(panelTerminalWithReverse);
150
151 var header = new TabHeader("Web shell", UiUtil.TERMINAL.getIcon());
152 this.setTabComponentAt(this.indexOfComponent(panelTerminalWithReverse), header);
153 terminal.requestFocusInWindow();
154
155 this.updateUI();
156 } catch (MalformedURLException | URISyntaxException e) {
157 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
158 }
159 }
160
161 public void addTabExploitReverseShell(String port) {
162 try {
163 var terminalID = UUID.randomUUID();
164 var terminal = new ExploitReverseShell(terminalID, port);
165 terminal.setName(TabResults.REV_SHELL);
166 MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);
167
168 JScrollPane scroller = new JScrollPane(terminal);
169 this.addTab(TabResults.REVERSE_SHELL, scroller);
170 this.setSelectedComponent(scroller);
171
172 var header = new TabHeader(TabResults.REVERSE_SHELL, UiUtil.TERMINAL.getIcon());
173 this.setTabComponentAt(this.indexOfComponent(scroller), header);
174 terminal.requestFocusInWindow();
175
176 this.updateUI();
177 } catch (URISyntaxException | IOException e) {
178 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
179 }
180 }
181
182 public void addTabExploitRce(BiConsumer<String, UUID> biConsumerRunCmd) {
183 try {
184 var terminalID = UUID.randomUUID();
185 var terminal = new AbstractExploit(terminalID, null, "rce") {
186 @Override
187 public void action(String command, UUID terminalID, String urlShell, String... arg) {
188 biConsumerRunCmd.accept(command, terminalID);
189 }
190 };
191 MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);
192
193 JPanel panelTerminalWithReverse = this.getTerminalWithMenu(terminal);
194 this.addTab(TabResults.RCE_SHELL, panelTerminalWithReverse);
195 this.setSelectedComponent(panelTerminalWithReverse);
196
197 var header = new TabHeader(TabResults.RCE_SHELL, UiUtil.TERMINAL.getIcon());
198 this.setTabComponentAt(this.indexOfComponent(panelTerminalWithReverse), header);
199 terminal.requestFocusInWindow();
200
201 this.updateUI();
202 } catch (MalformedURLException | URISyntaxException e) {
203 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
204 }
205 }
206
207 public void addTabExploitSql(String url, String user, String pass) {
208 try {
209 var terminalID = UUID.randomUUID();
210 var terminal = new AbstractExploit(terminalID, url, "sql") {
211 @Override
212 public void action(String cmd, UUID terminalID, String wbhPath, String... arg) {
213 MediatorHelper.model().getResourceAccess().runSqlShell(cmd, terminalID, wbhPath, arg[0], arg[1]);
214 }
215 };
216 terminal.setName(TabResults.SQL_SHELL);
217 terminal.setLoginPassword(new String[]{ user, pass });
218 MediatorHelper.frame().getMapUuidShell().put(terminalID, terminal);
219
220 JScrollPane scroller = new JScrollPane(terminal);
221 this.addTab("SQL shell", scroller);
222 this.setSelectedComponent(scroller);
223
224 var header = new TabHeader("SQL shell", UiUtil.TERMINAL.getIcon());
225 this.setTabComponentAt(this.indexOfComponent(scroller), header);
226 terminal.requestFocusInWindow();
227
228 this.updateUI();
229 } catch (MalformedURLException | URISyntaxException e) {
230 LOGGER.log(LogLevelUtil.CONSOLE_ERROR, TabResults.TAB_EXPLOIT_FAILURE_INCORRECT_URL, e);
231 }
232 }
233
234 public void addTabValues(String[][] data, String[] columnNames, AbstractElementDatabase table) {
235 var panelTable = new PanelTable(data, columnNames);
236
237 this.addTab(StringUtil.detectUtf8(table.toString()), panelTable);
238 panelTable.setComponentOrientation(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()));
239
240 this.setSelectedComponent(panelTable);
241
242 var header = new TabHeader(UiStringUtil.detectUtf8Html(table.toString()), UiUtil.TABLE_BOLD.getIcon());
243 this.setTabComponentAt(this.indexOfComponent(panelTable), header);
244
245 this.updateUI();
246 }
247
248 private JPanel getTerminalWithMenu(AbstractExploit terminal) {
249 JPanel panelTerminalWithReverse = new JPanel() {
250 @Override
251 public boolean isOptimizedDrawingEnabled() {
252 return false;
253 }
254 };
255 OverlayLayout overlay = new OverlayLayout(panelTerminalWithReverse);
256 panelTerminalWithReverse.setLayout(overlay);
257
258 var panelReverseMargin = new JPanel();
259 panelReverseMargin.setLayout(new BoxLayout(panelReverseMargin, BoxLayout.LINE_AXIS));
260 panelReverseMargin.setOpaque(false);
261 panelReverseMargin.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 15));
262
263 var menuReverse = new JLabel(TabResults.REVERSE_SHELL, UiUtil.ARROW_DOWN.getIcon(), SwingConstants.LEFT);
264 menuReverse.addMouseListener(new MouseAdapter() {
265 @Override
266 public void mousePressed(MouseEvent e) {
267 var popupMenu = TabResults.this.showMenu(terminal);
268 popupMenu.updateUI();
269 popupMenu.show(e.getComponent(), e.getComponent().getX(),5 + e.getComponent().getY() + e.getComponent().getHeight());
270 popupMenu.setLocation(e.getComponent().getLocationOnScreen().x,5 + e.getComponent().getLocationOnScreen().y + e.getComponent().getHeight());
271 }
272 });
273 menuReverse.setMaximumSize(menuReverse.getPreferredSize());
274 JScrollPane scrollerTerminal = new JScrollPane(terminal);
275 scrollerTerminal.setAlignmentX(1f);
276 scrollerTerminal.setAlignmentY(0f);
277 panelReverseMargin.setAlignmentX(1f);
278 panelReverseMargin.setAlignmentY(0f);
279 panelReverseMargin.add(menuReverse);
280 panelTerminalWithReverse.add(panelReverseMargin);
281 panelTerminalWithReverse.add(scrollerTerminal);
282
283 return panelTerminalWithReverse;
284 }
285
286 private JPopupMenu showMenu(AbstractExploit terminal) {
287 JPopupMenu menuReverse = new JPopupMenu();
288
289 var menuListen = new JMenu("Listen");
290 menuListen.setComponentOrientation(
291 ComponentOrientation.RIGHT_TO_LEFT.equals(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()))
292 ? ComponentOrientation.LEFT_TO_RIGHT
293 : ComponentOrientation.RIGHT_TO_LEFT
294 );
295 var panelPublicAddress = new JPanel(new BorderLayout());
296 panelPublicAddress.add(new JLabel("<html><b>Your public address (listener) :</b></html>"));
297 menuListen.add(panelPublicAddress);
298 menuListen.add(new JSeparator());
299 var address = new JTextFieldPlaceholder("Local IP/domain", "10.0.2.2");
300 menuListen.add(address);
301 var port = new JTextFieldPlaceholder("Local port", "4444");
302 menuListen.add(port);
303
304 var panelServerConnection = new JPanel(new BorderLayout());
305 panelServerConnection.add(new JLabel("<html><b>Server method (connector) :</b></html>"));
306 menuListen.add(panelServerConnection);
307 menuListen.add(new JSeparator());
308 var buttonGroup = new ButtonGroup();
309 List<ModelReverse> commandsReverse = MediatorHelper.model().getMediatorUtils().getPreferencesUtil().getCommandsReverse();
310 commandsReverse.forEach(modelReverse -> {
311 var radio = new RadioItemPreventClose(modelReverse.getName());
312 radio.setActionCommand(modelReverse.getName());
313 radio.setSelected("bash".equals(modelReverse.getName()));
314 buttonGroup.add(radio);
315 menuListen.add(radio);
316 });
317
318 Runnable runnableReverse = () -> {
319 try {
320 Thread.sleep(2500);
321 MediatorHelper.model().getMediatorUtils().getPreferencesUtil().getCommandsReverse().stream()
322 .filter(modelReverse -> modelReverse.getName().equals(buttonGroup.getSelection().getActionCommand()))
323 .findFirst()
324 .ifPresent(modelReverse -> MediatorHelper.model().getResourceAccess().runWebShell(
325
326 String.format(modelReverse.getCommand(), address.getText(), port.getText()),
327 null,
328 terminal.getUrlShell(),
329 true
330 ));
331 } catch (InterruptedException e) {
332 LOGGER.log(LogLevelUtil.IGNORE, e, e);
333 Thread.currentThread().interrupt();
334 }
335 };
336
337 var panelOpenIn = new JPanel(new BorderLayout());
338 panelOpenIn.add(new JLabel("<html><b>Open In :</b></html>"));
339 menuListen.add(panelOpenIn);
340 menuListen.add(new JSeparator());
341
342 var menuBuiltInShell = new RadioItemPreventClose("Built-in shell", true);
343 var menuExternalShell = new RadioItemPreventClose("External listening shell");
344 var buttonTypeShell = new ButtonGroup();
345 buttonTypeShell.add(menuBuiltInShell);
346 buttonTypeShell.add(menuExternalShell);
347 menuListen.add(menuBuiltInShell);
348 menuListen.add(menuExternalShell);
349 menuListen.add(new JSeparator());
350 var panelCreate = new JPanel(new BorderLayout());
351 panelCreate.add(new JButton(new AbstractAction("Create reverse shell") {
352 @Override
353 public void actionPerformed(ActionEvent e) {
354 if (menuBuiltInShell.isSelected()) {
355 SwingUtilities.invokeLater(() -> MediatorHelper.tabResults().addTabExploitReverseShell(port.getText()));
356 }
357 new Thread(runnableReverse).start();
358 menuReverse.setVisible(false);
359 }
360 }));
361 menuListen.add(panelCreate);
362
363 var menuConnect = new JMenu("Connect");
364 menuConnect.setComponentOrientation(
365 ComponentOrientation.RIGHT_TO_LEFT.equals(ComponentOrientation.getOrientation(I18nUtil.getCurrentLocale()))
366 ? ComponentOrientation.LEFT_TO_RIGHT
367 : ComponentOrientation.RIGHT_TO_LEFT
368 );
369 var panelServerPublicAddress = new JPanel(new BorderLayout());
370 panelServerPublicAddress.add(new JLabel("<html><b>Server public address (listener) :</b></html>"));
371 menuConnect.add(panelServerPublicAddress);
372 menuConnect.add(new JSeparator());
373 menuConnect.add(new JTextFieldPlaceholder("Target IP/domain"));
374 menuConnect.add(new JTextFieldPlaceholder("Target port"));
375 menuConnect.add(new JSeparator());
376
377 var panelServerListeningConnection = new JPanel(new BorderLayout());
378 panelServerListeningConnection.add(new JLabel("<html><b>Server listening method :</b></html>"));
379 menuConnect.add(panelServerListeningConnection);
380 var buttonGroupListening = new ButtonGroup();
381 Arrays.asList("netcat").forEach(method -> {
382 var radio = new JRadioButtonMenuItem(method) {
383 @Override
384 protected void processMouseEvent(MouseEvent evt) {
385 if (evt.getID() == MouseEvent.MOUSE_RELEASED && this.contains(evt.getPoint())) {
386 this.doClick();
387 this.setArmed(true);
388 } else {
389 super.processMouseEvent(evt);
390 }
391 }
392 };
393 radio.setSelected("netcat".equals(method));
394 buttonGroupListening.add(radio);
395 menuConnect.add(radio);
396 });
397 menuConnect.add(new JSeparator());
398 menuConnect.add(new JMenuItem("Create"));
399
400 menuReverse.add(menuListen);
401 menuReverse.add(menuConnect);
402
403 return menuReverse;
404 }
405 }