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