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