From de6c8f52f283bc4ee14c8c9199ff54b7e95789e2 Mon Sep 17 00:00:00 2001 From: Raul Sampedro <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:01:02 +0100 Subject: [PATCH 01/11] improve registration performance. Add poll time config --- src/burp/BurpExtender.java | 117 ++++++++++++--------- src/burp/gui/Config.java | 9 ++ src/burp/listeners/InteractshListener.java | 86 +++++++-------- src/interactsh/Client.java | 67 +++++++----- 4 files changed, 160 insertions(+), 119 deletions(-) diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java index aaf4eb6..fc66804 100644 --- a/src/burp/BurpExtender.java +++ b/src/burp/BurpExtender.java @@ -1,38 +1,53 @@ package burp; -import burp.api.montoya.ui.contextmenu.ContextMenuEvent; -import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider; -import burp.listeners.InteractshListener; -import burp.listeners.PollTimeListener; -import interactsh.Client; -import interactsh.InteractEntry; -import layout.SpringUtilities; - -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; -import javax.swing.*; + +import javax.swing.BoxLayout; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JMenuItem; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; +import javax.swing.JTabbedPane; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.JTextField; +import javax.swing.SpringLayout; +import javax.swing.SwingConstants; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableModel; import burp.api.montoya.BurpExtension; import burp.api.montoya.MontoyaApi; import burp.api.montoya.extension.ExtensionUnloadingHandler; - +import burp.api.montoya.ui.contextmenu.ContextMenuEvent; +import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider; +import burp.gui.Config; +import burp.listeners.InteractshListener; +import burp.listeners.PollTimeListener; +import interactsh.InteractEntry; +import layout.SpringUtilities; public class BurpExtender implements BurpExtension, ContextMenuItemsProvider, ExtensionUnloadingHandler { public static MontoyaApi api; public static int pollTime = 60; public static InteractshTab tab; - private static ArrayList clients = new ArrayList(); - private InteractshListener listener = new InteractshListener(); + private InteractshListener listener; @Override public void initialize(MontoyaApi api) { this.api = api; + this.listener = new InteractshListener(); + api.extension().setName("Interactsh Collaborator"); api.userInterface().registerContextMenuItemsProvider(this); api.extension().registerUnloadingHandler(this); @@ -40,7 +55,7 @@ public void initialize(MontoyaApi api) { api.logging().logToOutput("Starting Interactsh Collaborator!"); burp.gui.Config.generateConfig(); - tab = new InteractshTab(api, listener, clients); + tab = new InteractshTab(api, listener); burp.gui.Config.loadConfig(); api.userInterface().registerSuiteTab("Interactsh", tab); @@ -55,26 +70,13 @@ public void extensionUnloaded() { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { } - for (int i = 0; i < listener.pollers.size(); i++) { - listener.pollers.get(i).interrupt(); - } - // Tell all clients to deregister - for (int i = 0; i < clients.size(); i++) { - clients.get(i).deregister(); - } + listener.pollNowAll(); + listener.cleanup(); } api.logging().logToOutput("Thanks for collaborating!"); } - public ArrayList getClients() { - return clients; - } - - public static void addClient(Client c) { - clients.add(c); - } - public static int getPollTime() { try { return Integer.parseInt(tab.getPollField().getText()); @@ -99,7 +101,7 @@ public static void addToTable(InteractEntry i) { public List provideMenuItems(ContextMenuEvent event) { List menuList = new ArrayList(); JMenuItem item = new JMenuItem("Generate Interactsh url"); - item.addActionListener(new InteractshListener()); + item.addActionListener(e -> listener.generateCollaborator()); menuList.add(item); return menuList; @@ -116,14 +118,13 @@ public class InteractshTab extends JComponent { private static JTextField serverText; private static JTextField portText; private static JTextField authText; + private static JTextField pollText; private static JCheckBox tlsBox; private List log = new ArrayList(); private InteractshListener listener; - private ArrayList clients; - public InteractshTab(MontoyaApi api, InteractshListener listener, ArrayList clients) { + public InteractshTab(MontoyaApi api, InteractshListener listener) { this.listener = listener; - this.clients = clients; setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); @@ -142,14 +143,18 @@ public InteractshTab(MontoyaApi api, InteractshListener listener, ArrayList this.listener.generateCollaborator()); + RefreshButton.addActionListener(e -> listener.pollNowAll()); panel.add(CollaboratorButton); panel.add(pollLabel); panel.add(pollField); + panel.add(RefreshButton); splitPane.setTopComponent(panel); // Configuration pane @@ -159,13 +164,14 @@ public InteractshTab(MontoyaApi api, InteractshListener listener, ArrayList burp.gui.Config.updateConfig()); innerConfig.add(updateConfigButton); // Add a blank panel so that SpringUtilities can make a well shaped grid innerConfig.add(new JPanel()); SpringUtilities.makeCompactGrid(innerConfig, - 5, 2, //rows, cols - 6, 6, //initX, initY - 6, 6); //xPad, yPad + 6, 2, // rows, cols + 6, 6, // initX, initY + 6, 6); // xPad, yPad JPanel documentationPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel help = new JLabel("Check out https://github.com/projectdiscovery/interactsh for an up to date list of public Interactsh servers", SwingConstants.LEFT); + JLabel help = new JLabel( + "Check out https://github.com/projectdiscovery/interactsh for an up to date list of public Interactsh servers", + SwingConstants.LEFT); documentationPanel.setAlignmentY(Component.TOP_ALIGNMENT); documentationPanel.add(help); configPanel.add(documentationPanel); @@ -233,10 +242,18 @@ public static String getAuthText() { return authText.getText(); } + public static String getPollText() { + return pollText.getText(); + } + public static void setAuthText(String text) { authText.setText(text); } + public static void setPollText(String text) { + pollText.setText(text); + } + public static String getTlsBox() { return Boolean.toString(tlsBox.isSelected()); } @@ -272,11 +289,11 @@ public void changeSelection(int row, int col, boolean toggle, boolean extend) { InteractEntry ie = log.get(row); resultsPanel.removeAll(); // Refresh pane - resultsPanel.setLayout(new BorderLayout()); //give your JPanel a BorderLayout + resultsPanel.setLayout(new BorderLayout()); // give your JPanel a BorderLayout JTextArea text = new JTextArea(ie.details); - JScrollPane scroll = new JScrollPane(text); //place the JTextArea in a scroll pane - resultsPanel.add(scroll, BorderLayout.CENTER); //add the JScrollPane to the panel + JScrollPane scroll = new JScrollPane(text); // place the JTextArea in a scroll pane + resultsPanel.add(scroll, BorderLayout.CENTER); // add the JScrollPane to the panel tableSplitPane.revalidate(); super.changeSelection(row, col, toggle, extend); diff --git a/src/burp/gui/Config.java b/src/burp/gui/Config.java index 7cb90c4..be61620 100644 --- a/src/burp/gui/Config.java +++ b/src/burp/gui/Config.java @@ -16,6 +16,7 @@ public static void generateConfig() { preferences.setString("interactsh-server", "oast.pro"); preferences.setString("interactsh-port", "443"); preferences.setString("interactsh-authorization", ""); + preferences.setString("interactsh-poll-time", "60"); preferences.setString("interactsh-uses-tls", Boolean.toString(true)); } } @@ -26,11 +27,13 @@ public static void loadConfig() { String port = preferences.getString("interactsh-port"); String tls = preferences.getString("interactsh-uses-tls"); String authorization = preferences.getString("interactsh-authorization"); + String pollinterval = preferences.getString("interactsh-poll-time"); // Update each of the text boxes on the Configuration pane burp.BurpExtender.tab.setServerText(server); burp.BurpExtender.tab.setPortText(port); burp.BurpExtender.tab.setAuthText(authorization); + burp.BurpExtender.tab.setPollText(pollinterval); burp.BurpExtender.tab.setTlsBox(Boolean.parseBoolean(tls)); } @@ -41,11 +44,13 @@ public static void updateConfig() { String server = burp.BurpExtender.tab.getServerText(); String port = burp.BurpExtender.tab.getPortText(); String authorization = burp.BurpExtender.tab.getAuthText(); + String pollinterval = burp.BurpExtender.tab.getPollText(); String tls = burp.BurpExtender.tab.getTlsBox(); preferences.setString("interactsh-server", server); preferences.setString("interactsh-port", port); preferences.setString("interactsh-uses-tls", tls); + preferences.setString("interactsh-poll-time", pollinterval); preferences.setString("interactsh-authorization", authorization); } @@ -64,6 +69,10 @@ public static boolean getScheme() { public static String getAuth() { return burp.BurpExtender.api.persistence().preferences().getString("interactsh-authorization"); } + + public static String getPollInterval() { + return burp.BurpExtender.api.persistence().preferences().getString("interactsh-poll-time"); + } } diff --git a/src/burp/listeners/InteractshListener.java b/src/burp/listeners/InteractshListener.java index ec710b1..d8a7036 100644 --- a/src/burp/listeners/InteractshListener.java +++ b/src/burp/listeners/InteractshListener.java @@ -1,60 +1,60 @@ package burp.listeners; -import java.awt.*; +import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.ArrayList; +import java.security.NoSuchAlgorithmException; import java.util.concurrent.TimeUnit; -import burp.BurpExtender; import interactsh.Client; -public class InteractshListener implements ActionListener { - public ArrayList pollers = new ArrayList(); +public class InteractshListener { + public Thread poller; public boolean running = true; + private Client client; public InteractshListener() { - } - @Override - public void actionPerformed(ActionEvent e) { - burp.BurpExtender.api.logging().logToOutput("Generating new Interactsh client"); - Client c = new Client(); try { - c.generateKeys(); - - Thread polling = new Thread(new Runnable() { - public void run() { - try { - if (c.registerClient()) { - burp.BurpExtender.addClient(c); - while (running == true) { - if (!c.poll()) { - return; - } - TimeUnit.SECONDS.sleep(burp.BurpExtender.getPollTime()); - } - } else { - burp.BurpExtender.api.logging().logToOutput("Error registering client"); + client = new Client(); + client.register(); + } catch (NoSuchAlgorithmException ex) { + burp.BurpExtender.api.logging().logToError(ex.getMessage()); + } + this.poller = new Thread(new Runnable() { + public void run() { + try { + while (running == true) { + client.poll(); + + try { + TimeUnit.SECONDS.sleep(burp.BurpExtender.getPollTime()); + } catch (InterruptedException ie) { + // Ignore interrupt (re evaluate running and polling) } - } catch (InterruptedException ie) { - } catch (Exception ex) { - burp.BurpExtender.api.logging().logToError(ex.getMessage()); } + } catch (Exception ex) { + burp.BurpExtender.api.logging().logToError(ex.getMessage()); } - }); - pollers.add(polling); - polling.start(); - - TimeUnit.SECONDS.sleep(1); - // Set clipboard with new interactsh domain - String domain = c.getInteractDomain(); - burp.BurpExtender.api.logging().logToOutput("New domain is: " + domain); - StringSelection stringSelection = new StringSelection(domain); - Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null); - } catch (Exception ex) { - burp.BurpExtender.api.logging().logToError(ex.getMessage()); - } + } + }); + this.poller.start(); + } + + public void pollNowAll() { + this.poller.interrupt(); + } + + public void generateCollaborator() { + burp.BurpExtender.api.logging().logToOutput("Generating new Interactsh client"); + + String interactDomain = client.getInteractDomain(); + burp.BurpExtender.api.logging().logToOutput("New domain is: " + interactDomain); + StringSelection stringSelection = new StringSelection(interactDomain); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null); + } + + public void cleanup() { + this.client.deregister(); } + } \ No newline at end of file diff --git a/src/interactsh/Client.java b/src/interactsh/Client.java index 82984db..8c130ef 100644 --- a/src/interactsh/Client.java +++ b/src/interactsh/Client.java @@ -1,53 +1,62 @@ package interactsh; -import burp.api.montoya.http.message.requests.HttpRequest; -import burp.api.montoya.http.message.responses.HttpResponse; -import burp.api.montoya.http.HttpService; +import java.nio.charset.StandardCharsets; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.MGF1ParameterSpec; +import java.util.Arrays; +import java.util.Base64; +import java.util.Random; +import java.util.UUID; -import javax.crypto.*; -import javax.crypto.spec.*; +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.PSource; +import javax.crypto.spec.SecretKeySpec; -import com.github.shamil.Xid; import org.json.JSONArray; import org.json.JSONObject; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.security.spec.MGF1ParameterSpec; -import java.security.*; -import java.util.*; +import com.github.shamil.Xid; + +import burp.api.montoya.http.HttpService; +import burp.api.montoya.http.message.requests.HttpRequest; +import burp.api.montoya.http.message.responses.HttpResponse; public class Client { public PrivateKey privateKey; private PublicKey publicKey; - private Xid xid; private String secretKey; - private String correlationId; // Defaults private String host = "oast.pro"; private int port = 443; private boolean scheme = true; private String authorization = null; + private String pubKey; + private String correlationId; + + public Client() throws NoSuchAlgorithmException { + this.generateKeys(); + this.correlationId = Xid.get().toString(); - public Client() { host = burp.gui.Config.getHost(); scheme = burp.gui.Config.getScheme(); authorization = burp.gui.Config.getAuth(); + secretKey = UUID.randomUUID().toString(); + pubKey = Base64.getEncoder().encodeToString(getPublicKey().getBytes(StandardCharsets.UTF_8)); try { port = Integer.parseInt(burp.gui.Config.getPort()); - } catch (NumberFormatException ne) { port = 443; } } - public boolean registerClient() throws Exception { - String pubKey = Base64.getEncoder().encodeToString(getPublicKey().getBytes(StandardCharsets.UTF_8)); - secretKey = UUID.randomUUID().toString(); - xid = Xid.get(); - correlationId = xid.toString(); - + public boolean register() { try { JSONObject registerData = new JSONObject(); registerData.put("public-key", pubKey); @@ -70,14 +79,17 @@ public boolean registerClient() throws Exception { if (resp.statusCode() == 200) { return true; + } else { + burp.BurpExtender.api.logging().logToError("Register correlation " + correlationId + + " was unsuccessful. Status Code: " + resp.statusCode()); } } catch (Exception ex) { - burp.BurpExtender.api.logging().logToError(ex.getMessage()); + burp.BurpExtender.api.logging().logToError(ex); } return false; } - public boolean poll() throws IOException, InterruptedException { + public boolean poll() { String request = "GET /poll?id=" + correlationId + "&secret=" + secretKey + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "User-Agent: Interact.sh Client\r\n"; @@ -89,7 +101,8 @@ public boolean poll() throws IOException, InterruptedException { HttpRequest httpRequest = HttpRequest.httpRequest(HttpService.httpService(host, port, scheme), request); HttpResponse resp = burp.BurpExtender.api.http().sendRequest(httpRequest).response(); if (resp.statusCode() != 200) { - burp.BurpExtender.api.logging().logToOutput("Poll for " + correlationId + " was unsuccessful: " + resp.statusCode()); + burp.BurpExtender.api.logging() + .logToOutput("Poll for " + correlationId + " was unsuccessful: " + resp.statusCode()); return false; } @@ -97,7 +110,7 @@ public boolean poll() throws IOException, InterruptedException { try { JSONObject jsonObject = new JSONObject(responseBody); String aesKey = jsonObject.getString("aes_key"); - String key = decryptAesKey(aesKey); + String key = this.decryptAesKey(aesKey); if (!jsonObject.isNull("data")) { JSONArray data = jsonObject.getJSONArray("data"); @@ -153,6 +166,7 @@ public String getInteractDomain() { while (fullDomain.length() < 33) { fullDomain += (char) (random.nextInt(26) + 'a'); } + fullDomain += "." + host; return fullDomain; } @@ -181,7 +195,8 @@ private String decryptAesKey(String encrypted) throws Exception { byte[] cipherTextArray = Base64.getDecoder().decode(encrypted); Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding"); - OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT); + OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), + PSource.PSpecified.DEFAULT); cipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParams); byte[] decrypted = cipher.doFinal(cipherTextArray); From 57241991aeb86ace5483d806a966eb825fde6aff Mon Sep 17 00:00:00 2001 From: Raul Sampedro <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:06:34 +0100 Subject: [PATCH 02/11] fix warnings --- src/burp/BurpExtender.java | 2 -- src/burp/gui/Config.java | 21 +++++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java index fc66804..b4281f9 100644 --- a/src/burp/BurpExtender.java +++ b/src/burp/BurpExtender.java @@ -276,11 +276,9 @@ public void addToTable(InteractEntry i) { // private class Table extends JTable { - public TableModel tableModel; public Table(TableModel tableModel) { super(tableModel); - this.tableModel = tableModel; } @Override diff --git a/src/burp/gui/Config.java b/src/burp/gui/Config.java index be61620..e7bc4cd 100644 --- a/src/burp/gui/Config.java +++ b/src/burp/gui/Config.java @@ -1,5 +1,6 @@ package burp.gui; +import burp.BurpExtender.InteractshTab; import burp.api.montoya.persistence.Preferences; public class Config { @@ -30,22 +31,22 @@ public static void loadConfig() { String pollinterval = preferences.getString("interactsh-poll-time"); // Update each of the text boxes on the Configuration pane - burp.BurpExtender.tab.setServerText(server); - burp.BurpExtender.tab.setPortText(port); - burp.BurpExtender.tab.setAuthText(authorization); - burp.BurpExtender.tab.setPollText(pollinterval); - burp.BurpExtender.tab.setTlsBox(Boolean.parseBoolean(tls)); + InteractshTab.setServerText(server); + InteractshTab.setPortText(port); + InteractshTab.setAuthText(authorization); + InteractshTab.setPollText(pollinterval); + InteractshTab.setTlsBox(Boolean.parseBoolean(tls)); } public static void updateConfig() { Preferences preferences = burp.BurpExtender.api.persistence().preferences(); // Read each of the text boxes on the Configuration pane - String server = burp.BurpExtender.tab.getServerText(); - String port = burp.BurpExtender.tab.getPortText(); - String authorization = burp.BurpExtender.tab.getAuthText(); - String pollinterval = burp.BurpExtender.tab.getPollText(); - String tls = burp.BurpExtender.tab.getTlsBox(); + String server = InteractshTab.getServerText(); + String port = InteractshTab.getPortText(); + String authorization = InteractshTab.getAuthText(); + String pollinterval = InteractshTab.getPollText(); + String tls = InteractshTab.getTlsBox(); preferences.setString("interactsh-server", server); preferences.setString("interactsh-port", port); From 9cd7bd1eeb6d4b0079f097f0efa702052f87ac8d Mon Sep 17 00:00:00 2001 From: Raul Sampedro <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:37:56 +0100 Subject: [PATCH 03/11] allow table selection --- src/burp/BurpExtender.java | 279 +------------------------------- src/burp/gui/Config.java | 1 - src/burp/gui/InteractshTab.java | 266 ++++++++++++++++++++++++++++++ 3 files changed, 271 insertions(+), 275 deletions(-) create mode 100644 src/burp/gui/InteractshTab.java diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java index b4281f9..1157f39 100644 --- a/src/burp/BurpExtender.java +++ b/src/burp/BurpExtender.java @@ -1,41 +1,20 @@ package burp; -import java.awt.BorderLayout; import java.awt.Component; -import java.awt.Dimension; -import java.awt.FlowLayout; import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComponent; -import javax.swing.JLabel; import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JTabbedPane; -import javax.swing.JTable; -import javax.swing.JTextArea; -import javax.swing.JTextField; -import javax.swing.SpringLayout; -import javax.swing.SwingConstants; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.TableModel; import burp.api.montoya.BurpExtension; import burp.api.montoya.MontoyaApi; import burp.api.montoya.extension.ExtensionUnloadingHandler; import burp.api.montoya.ui.contextmenu.ContextMenuEvent; import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider; -import burp.gui.Config; +import burp.gui.InteractshTab; import burp.listeners.InteractshListener; -import burp.listeners.PollTimeListener; import interactsh.InteractEntry; -import layout.SpringUtilities; public class BurpExtender implements BurpExtension, ContextMenuItemsProvider, ExtensionUnloadingHandler { public static MontoyaApi api; @@ -45,7 +24,7 @@ public class BurpExtender implements BurpExtension, ContextMenuItemsProvider, Ex @Override public void initialize(MontoyaApi api) { - this.api = api; + BurpExtender.api = api; this.listener = new InteractshListener(); api.extension().setName("Interactsh Collaborator"); @@ -66,12 +45,12 @@ public void extensionUnloaded() { if (listener != null) { // Get all threads and stop them. listener.running = false; + listener.pollNowAll(); + try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { } - - listener.pollNowAll(); listener.cleanup(); } api.logging().logToOutput("Thanks for collaborating!"); @@ -90,7 +69,7 @@ public static void updatePollTime(int poll) { } public static void addToTable(InteractEntry i) { - tab.addToTable(i); + BurpExtender.tab.addToTable(i); } // @@ -106,252 +85,4 @@ public List provideMenuItems(ContextMenuEvent event) { return menuList; } - - public class InteractshTab extends JComponent { - private JTabbedPane mainPane; - private JSplitPane splitPane; - private JScrollPane scrollPane; - private JSplitPane tableSplitPane; - private JPanel resultsPanel; - private JTextField pollField; - private Table logTable; - private static JTextField serverText; - private static JTextField portText; - private static JTextField authText; - private static JTextField pollText; - private static JCheckBox tlsBox; - private List log = new ArrayList(); - private InteractshListener listener; - - public InteractshTab(MontoyaApi api, InteractshListener listener) { - this.listener = listener; - - setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); - - mainPane = new JTabbedPane(); - splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); - mainPane.addTab("Logs", splitPane); - - resultsPanel = new JPanel(); - tableSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); - logTable = new Table(new LogTable()); - scrollPane = new JScrollPane(logTable); - - tableSplitPane.setTopComponent(scrollPane); - tableSplitPane.setBottomComponent(resultsPanel); - splitPane.setBottomComponent(tableSplitPane); - - JPanel panel = new JPanel(); - JButton CollaboratorButton = new JButton("Generate Interactsh url"); - JButton RefreshButton = new JButton("Refresh"); - - JLabel pollLabel = new JLabel("Poll Time: "); - pollField = new JTextField(Config.getPollInterval(), 4); - pollField.getDocument().addDocumentListener(new PollTimeListener()); - - CollaboratorButton.addActionListener(e -> this.listener.generateCollaborator()); - RefreshButton.addActionListener(e -> listener.pollNowAll()); - panel.add(CollaboratorButton); - panel.add(pollLabel); - panel.add(pollField); - panel.add(RefreshButton); - splitPane.setTopComponent(panel); - - // Configuration pane - JPanel configPanel = new JPanel(); - configPanel.setLayout(new BoxLayout(configPanel, BoxLayout.Y_AXIS)); - JPanel subConfigPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - mainPane.addTab("Configuration", configPanel); - configPanel.add(subConfigPanel); - JPanel innerConfig = new JPanel(); - subConfigPanel.setMaximumSize(new Dimension(configPanel.getMaximumSize().width, 250)); - innerConfig.setLayout(new SpringLayout()); - subConfigPanel.add(innerConfig); - - serverText = new JTextField("oast.pro", 20); - portText = new JTextField("443", 20); - authText = new JTextField("", 20); - pollText = new JTextField("60", 20); - tlsBox = new JCheckBox("", true); - - JLabel server = new JLabel("Server: "); - innerConfig.add(server); - server.setLabelFor(serverText); - innerConfig.add(serverText); - - JLabel port = new JLabel("Port: "); - innerConfig.add(port); - port.setLabelFor(portText); - innerConfig.add(portText); - - JLabel auth = new JLabel("Authorization: "); - innerConfig.add(auth); - auth.setLabelFor(authText); - innerConfig.add(authText); - - JLabel poll = new JLabel("Poll Interval (sec): "); - innerConfig.add(poll); - poll.setLabelFor(pollText); - innerConfig.add(pollText); - - JLabel tls = new JLabel("TLS: "); - innerConfig.add(tls); - tls.setLabelFor(tlsBox); - innerConfig.add(tlsBox); - - JButton updateConfigButton = new JButton("Update Settings"); - updateConfigButton.addActionListener(e -> burp.gui.Config.updateConfig()); - innerConfig.add(updateConfigButton); - - // Add a blank panel so that SpringUtilities can make a well shaped grid - innerConfig.add(new JPanel()); - - SpringUtilities.makeCompactGrid(innerConfig, - 6, 2, // rows, cols - 6, 6, // initX, initY - 6, 6); // xPad, yPad - - JPanel documentationPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); - JLabel help = new JLabel( - "Check out https://github.com/projectdiscovery/interactsh for an up to date list of public Interactsh servers", - SwingConstants.LEFT); - documentationPanel.setAlignmentY(Component.TOP_ALIGNMENT); - documentationPanel.add(help); - configPanel.add(documentationPanel); - - add(mainPane); - } - - public static String getServerText() { - return serverText.getText(); - } - - public static void setServerText(String t) { - serverText.setText(t); - } - - public static String getPortText() { - return portText.getText(); - } - - public static void setPortText(String text) { - portText.setText(text); - } - - public static String getAuthText() { - return authText.getText(); - } - - public static String getPollText() { - return pollText.getText(); - } - - public static void setAuthText(String text) { - authText.setText(text); - } - - public static void setPollText(String text) { - pollText.setText(text); - } - - public static String getTlsBox() { - return Boolean.toString(tlsBox.isSelected()); - } - - public static void setTlsBox(boolean value) { - tlsBox.setSelected(value); - } - - public JTextField getPollField() { - return pollField; - } - - public void addToTable(InteractEntry i) { - log.add(i); - logTable.revalidate(); - } - - // - // extend JTable to handle cell selection - // - - private class Table extends JTable { - - public Table(TableModel tableModel) { - super(tableModel); - } - - @Override - public void changeSelection(int row, int col, boolean toggle, boolean extend) { - // show the log entry for the selected row - InteractEntry ie = log.get(row); - - resultsPanel.removeAll(); // Refresh pane - resultsPanel.setLayout(new BorderLayout()); // give your JPanel a BorderLayout - - JTextArea text = new JTextArea(ie.details); - JScrollPane scroll = new JScrollPane(text); // place the JTextArea in a scroll pane - resultsPanel.add(scroll, BorderLayout.CENTER); // add the JScrollPane to the panel - tableSplitPane.revalidate(); - - super.changeSelection(row, col, toggle, extend); - } - } - - // - // implement AbstractTableModel - // - - private class LogTable extends AbstractTableModel { - - @Override - public int getRowCount() { - return log.size(); - } - - @Override - public int getColumnCount() { - return 4; - } - - @Override - public String getColumnName(int columnIndex) { - switch (columnIndex) { - case 0: - return "Entry"; - case 1: - return "Type"; - case 2: - return "Address"; - case 3: - return "Time"; - default: - return ""; - } - } - - @Override - public Class getColumnClass(int columnIndex) { - return String.class; - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - InteractEntry ie = log.get(rowIndex); - - switch (columnIndex) { - case 0: - return ie.uid; - case 1: - return ie.protocol; - case 2: - return ie.address; - case 3: - return ie.timestamp; - default: - return ""; - } - } - } - } } \ No newline at end of file diff --git a/src/burp/gui/Config.java b/src/burp/gui/Config.java index e7bc4cd..ddfc72d 100644 --- a/src/burp/gui/Config.java +++ b/src/burp/gui/Config.java @@ -1,6 +1,5 @@ package burp.gui; -import burp.BurpExtender.InteractshTab; import burp.api.montoya.persistence.Preferences; public class Config { diff --git a/src/burp/gui/InteractshTab.java b/src/burp/gui/InteractshTab.java new file mode 100644 index 0000000..ee29a98 --- /dev/null +++ b/src/burp/gui/InteractshTab.java @@ -0,0 +1,266 @@ +package burp.gui; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.util.ArrayList; + +import javax.swing.*; +import javax.swing.table.*; + +import burp.api.montoya.MontoyaApi; +import burp.listeners.InteractshListener; +import burp.listeners.PollTimeListener; +import layout.SpringUtilities; +import interactsh.InteractEntry; + +public class InteractshTab extends JComponent { + private JTabbedPane mainPane; + private JSplitPane splitPane; + private JScrollPane scrollPane; + private JSplitPane tableSplitPane; + private JPanel resultsPanel; + private JTextField pollField; + private Table logTable; + private static JTextField serverText; + private static JTextField portText; + private static JTextField authText; + private static JTextField pollText; + private static JCheckBox tlsBox; + private ArrayList log = new ArrayList(); + private InteractshListener listener; + + public InteractshTab(MontoyaApi api, InteractshListener listener) { + this.listener = listener; + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + + mainPane = new JTabbedPane(); + splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + mainPane.addTab("Logs", splitPane); + + resultsPanel = new JPanel(); + tableSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); + logTable = new Table(new LogTable()); + logTable.setRowSelectionAllowed(true); + logTable.setColumnSelectionAllowed(true); + scrollPane = new JScrollPane(logTable); + + tableSplitPane.setTopComponent(scrollPane); + tableSplitPane.setBottomComponent(resultsPanel); + splitPane.setBottomComponent(tableSplitPane); + + JPanel panel = new JPanel(); + JButton CollaboratorButton = new JButton("Generate Interactsh url"); + JButton RefreshButton = new JButton("Refresh"); + + JLabel pollLabel = new JLabel("Poll Time: "); + pollField = new JTextField(Config.getPollInterval(), 4); + pollField.getDocument().addDocumentListener(new PollTimeListener()); + + CollaboratorButton.addActionListener(e -> this.listener.generateCollaborator()); + RefreshButton.addActionListener(e -> listener.pollNowAll()); + panel.add(CollaboratorButton); + panel.add(pollLabel); + panel.add(pollField); + panel.add(RefreshButton); + splitPane.setTopComponent(panel); + + // Configuration pane + JPanel configPanel = new JPanel(); + configPanel.setLayout(new BoxLayout(configPanel, BoxLayout.Y_AXIS)); + JPanel subConfigPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + mainPane.addTab("Configuration", configPanel); + configPanel.add(subConfigPanel); + JPanel innerConfig = new JPanel(); + subConfigPanel.setMaximumSize(new Dimension(configPanel.getMaximumSize().width, 250)); + innerConfig.setLayout(new SpringLayout()); + subConfigPanel.add(innerConfig); + + serverText = new JTextField("oast.pro", 20); + portText = new JTextField("443", 20); + authText = new JTextField("", 20); + pollText = new JTextField("60", 20); + tlsBox = new JCheckBox("", true); + + JLabel server = new JLabel("Server: "); + innerConfig.add(server); + server.setLabelFor(serverText); + innerConfig.add(serverText); + + JLabel port = new JLabel("Port: "); + innerConfig.add(port); + port.setLabelFor(portText); + innerConfig.add(portText); + + JLabel auth = new JLabel("Authorization: "); + innerConfig.add(auth); + auth.setLabelFor(authText); + innerConfig.add(authText); + + JLabel poll = new JLabel("Poll Interval (sec): "); + innerConfig.add(poll); + poll.setLabelFor(pollText); + innerConfig.add(pollText); + + JLabel tls = new JLabel("TLS: "); + innerConfig.add(tls); + tls.setLabelFor(tlsBox); + innerConfig.add(tlsBox); + + JButton updateConfigButton = new JButton("Update Settings"); + updateConfigButton.addActionListener(e -> burp.gui.Config.updateConfig()); + innerConfig.add(updateConfigButton); + + // Add a blank panel so that SpringUtilities can make a well shaped grid + innerConfig.add(new JPanel()); + + SpringUtilities.makeCompactGrid(innerConfig, + 6, 2, // rows, cols + 6, 6, // initX, initY + 6, 6); // xPad, yPad + + JPanel documentationPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JLabel help = new JLabel( + "Check out https://github.com/projectdiscovery/interactsh for an up to date list of public Interactsh servers", + SwingConstants.LEFT); + documentationPanel.setAlignmentY(Component.TOP_ALIGNMENT); + documentationPanel.add(help); + configPanel.add(documentationPanel); + + add(mainPane); + } + + public static String getServerText() { + return serverText.getText(); + } + + public static void setServerText(String t) { + serverText.setText(t); + } + + public static String getPortText() { + return portText.getText(); + } + + public static void setPortText(String text) { + portText.setText(text); + } + + public static String getAuthText() { + return authText.getText(); + } + + public static String getPollText() { + return pollText.getText(); + } + + public static void setAuthText(String text) { + authText.setText(text); + } + + public static void setPollText(String text) { + pollText.setText(text); + } + + public static String getTlsBox() { + return Boolean.toString(tlsBox.isSelected()); + } + + public static void setTlsBox(boolean value) { + tlsBox.setSelected(value); + } + + public JTextField getPollField() { + return pollField; + } + + public void addToTable(InteractEntry i) { + log.add(i); + logTable.revalidate(); + } + + // + // extend JTable to handle cell selection + // + private class Table extends JTable { + + public Table(TableModel tableModel) { + super(tableModel); + } + + @Override + public void changeSelection(int row, int col, boolean toggle, boolean extend) { + // show the log entry for the selected row + InteractEntry ie = log.get(row); + + resultsPanel.removeAll(); // Refresh pane + resultsPanel.setLayout(new BorderLayout()); // give your JPanel a BorderLayout + + JTextArea text = new JTextArea(ie.details); + JScrollPane scroll = new JScrollPane(text); // place the JTextArea in a scroll pane + resultsPanel.add(scroll, BorderLayout.CENTER); // add the JScrollPane to the panel + tableSplitPane.revalidate(); + + super.changeSelection(row, col, toggle, extend); + } + } + + // + // implement AbstractTableModel + // + + private class LogTable extends AbstractTableModel { + + @Override + public int getRowCount() { + return log.size(); + } + + @Override + public int getColumnCount() { + return 4; + } + + @Override + public String getColumnName(int columnIndex) { + switch (columnIndex) { + case 0: + return "Entry"; + case 1: + return "Type"; + case 2: + return "Address"; + case 3: + return "Time"; + default: + return ""; + } + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + InteractEntry ie = log.get(rowIndex); + + switch (columnIndex) { + case 0: + return ie.uid; + case 1: + return ie.protocol; + case 2: + return ie.address; + case 3: + return ie.timestamp; + default: + return ""; + } + } + } +} + From 0fb44be099c5cc73375e4912ed4e2b926f3614eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Sampedro?= <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:49:29 +0100 Subject: [PATCH 04/11] Create main.yml --- .github/workflows/main.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/main.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..e0b5ab2 --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,28 @@ +--- +name: "pre-release" + +on: + push: + branches: + - "master" + +jobs: + release: + name: "Release" + runs-on: "ubuntu-latest" + + steps: + # ... + - name: "Build & test" + run: | + mvn package + + - uses: "marvinpinto/action-automatic-releases@latest" + with: + repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: "latest" + prerelease: true + title: "Development Build" + files: | + README.md + target/*jar-with-dependencies.jar From d64ecf03b45d7c935bed4b18c7aafcd0909063f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Sampedro?= <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:53:40 +0100 Subject: [PATCH 05/11] Update main.yml --- .github/workflows/main.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e0b5ab2..a2a35ad 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,12 +12,14 @@ jobs: runs-on: "ubuntu-latest" steps: - # ... - - name: "Build & test" + - name: Checkout + uses: actions/checkout@v4.1.1 + - name: Build run: | mvn package - - uses: "marvinpinto/action-automatic-releases@latest" + - name: Upload Release + uses: "marvinpinto/action-automatic-releases@latest" with: repo_token: "${{ secrets.GITHUB_TOKEN }}" automatic_release_tag: "latest" From b1e8826dba8befa09a5912bb669088536647d4a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Sampedro?= <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:31:49 +0100 Subject: [PATCH 06/11] Update main.yml --- .github/workflows/main.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a2a35ad..0baf1b6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -16,6 +16,7 @@ jobs: uses: actions/checkout@v4.1.1 - name: Build run: | + java -version && mvn package - name: Upload Release From fa55a4c5b2af84d99588b9bb14781de3798c4a32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Sampedro?= <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:34:09 +0100 Subject: [PATCH 07/11] Update main.yml --- .github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0baf1b6..152395d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,6 +14,11 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4.1.1 + - name: Set up JDK 17 + uses: actions/setup-java@v3 + with: + java-version: '17' + distribution: 'adopt' - name: Build run: | java -version && From a1660dc1b721eb67e03c529c5081865f3ffd6bfb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ra=C3=BAl=20Sampedro?= <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:35:41 +0100 Subject: [PATCH 08/11] Update main.yml --- .github/workflows/main.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 152395d..8c3042a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,5 @@ --- -name: "pre-release" +name: "release" on: push: @@ -29,8 +29,7 @@ jobs: with: repo_token: "${{ secrets.GITHUB_TOKEN }}" automatic_release_tag: "latest" - prerelease: true - title: "Development Build" + title: "Latest Build" files: | README.md target/*jar-with-dependencies.jar From 135e97a3160218c578759470eebd1b5da79f8731 Mon Sep 17 00:00:00 2001 From: Raul Sampedro <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:36:09 +0100 Subject: [PATCH 09/11] update pom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c3861c0..4e04b9e 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ net.portswigger.burp.extensions montoya-api - LATEST + 2023.2 org.json From abf3880f36b40fa8d48ebc99fb65592d9fbd8e60 Mon Sep 17 00:00:00 2001 From: Raul Sampedro <5142014+rsrdesarrollo@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:42:08 +0100 Subject: [PATCH 10/11] update pom --- .gitignore | 1 + pom.xml | 2 +- src/burp/BurpExtender.java | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 2f7896d..64ee209 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target/ +.vscode/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 4e04b9e..ce0cd19 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ net.portswigger.burp.extensions montoya-api - 2023.2 + 2023.12.1 org.json diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java index 1157f39..5d61040 100644 --- a/src/burp/BurpExtender.java +++ b/src/burp/BurpExtender.java @@ -46,11 +46,12 @@ public void extensionUnloaded() { // Get all threads and stop them. listener.running = false; listener.pollNowAll(); - + try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { } + listener.cleanup(); } api.logging().logToOutput("Thanks for collaborating!"); From b71b776b8ad7bd32d6a147fc9fe4666da12be608 Mon Sep 17 00:00:00 2001 From: Raul Sampedro <5142014+rsrdesarrollo@users.noreply.github.com> Date: Thu, 29 Feb 2024 17:58:51 +0100 Subject: [PATCH 11/11] refactor client --- src/burp/BurpExtender.java | 25 ++-------- src/burp/gui/InteractshTab.java | 22 +++++++-- src/burp/listeners/InteractshListener.java | 54 ++++++++++++---------- src/interactsh/Client.java | 30 ++++++++---- 4 files changed, 74 insertions(+), 57 deletions(-) diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java index 5d61040..7fa7432 100644 --- a/src/burp/BurpExtender.java +++ b/src/burp/BurpExtender.java @@ -3,7 +3,6 @@ import java.awt.Component; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; import javax.swing.JMenuItem; @@ -13,19 +12,16 @@ import burp.api.montoya.ui.contextmenu.ContextMenuEvent; import burp.api.montoya.ui.contextmenu.ContextMenuItemsProvider; import burp.gui.InteractshTab; -import burp.listeners.InteractshListener; import interactsh.InteractEntry; public class BurpExtender implements BurpExtension, ContextMenuItemsProvider, ExtensionUnloadingHandler { public static MontoyaApi api; public static int pollTime = 60; public static InteractshTab tab; - private InteractshListener listener; @Override public void initialize(MontoyaApi api) { BurpExtender.api = api; - this.listener = new InteractshListener(); api.extension().setName("Interactsh Collaborator"); api.userInterface().registerContextMenuItemsProvider(this); @@ -34,7 +30,7 @@ public void initialize(MontoyaApi api) { api.logging().logToOutput("Starting Interactsh Collaborator!"); burp.gui.Config.generateConfig(); - tab = new InteractshTab(api, listener); + BurpExtender.tab = new InteractshTab(api); burp.gui.Config.loadConfig(); api.userInterface().registerSuiteTab("Interactsh", tab); @@ -42,24 +38,13 @@ public void initialize(MontoyaApi api) { @Override public void extensionUnloaded() { - if (listener != null) { - // Get all threads and stop them. - listener.running = false; - listener.pollNowAll(); - - try { - TimeUnit.SECONDS.sleep(1); - } catch (InterruptedException e) { - } - - listener.cleanup(); - } - api.logging().logToOutput("Thanks for collaborating!"); + BurpExtender.tab.cleanup(); + BurpExtender.api.logging().logToOutput("Thanks for collaborating!"); } public static int getPollTime() { try { - return Integer.parseInt(tab.getPollField().getText()); + return Integer.parseInt(BurpExtender.tab.getPollField().getText()); } catch (Exception ex) { } return 60; @@ -81,7 +66,7 @@ public static void addToTable(InteractEntry i) { public List provideMenuItems(ContextMenuEvent event) { List menuList = new ArrayList(); JMenuItem item = new JMenuItem("Generate Interactsh url"); - item.addActionListener(e -> listener.generateCollaborator()); + item.addActionListener(e -> BurpExtender.tab.getListener().generateCollaborator()); menuList.add(item); return menuList; diff --git a/src/burp/gui/InteractshTab.java b/src/burp/gui/InteractshTab.java index ee29a98..f4f5164 100644 --- a/src/burp/gui/InteractshTab.java +++ b/src/burp/gui/InteractshTab.java @@ -31,8 +31,8 @@ public class InteractshTab extends JComponent { private ArrayList log = new ArrayList(); private InteractshListener listener; - public InteractshTab(MontoyaApi api, InteractshListener listener) { - this.listener = listener; + public InteractshTab(MontoyaApi api) { + this.listener = new InteractshListener(); setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); @@ -60,7 +60,7 @@ public InteractshTab(MontoyaApi api, InteractshListener listener) { pollField.getDocument().addDocumentListener(new PollTimeListener()); CollaboratorButton.addActionListener(e -> this.listener.generateCollaborator()); - RefreshButton.addActionListener(e -> listener.pollNowAll()); + RefreshButton.addActionListener(e -> this.listener.pollNowAll()); panel.add(CollaboratorButton); panel.add(pollLabel); panel.add(pollField); @@ -110,7 +110,12 @@ public InteractshTab(MontoyaApi api, InteractshListener listener) { innerConfig.add(tlsBox); JButton updateConfigButton = new JButton("Update Settings"); - updateConfigButton.addActionListener(e -> burp.gui.Config.updateConfig()); + updateConfigButton.addActionListener(e -> { + burp.gui.Config.updateConfig(); + // Re generate client listener and register again + listener.close(); + this.listener = new InteractshListener(); + }); innerConfig.add(updateConfigButton); // Add a blank panel so that SpringUtilities can make a well shaped grid @@ -132,6 +137,10 @@ public InteractshTab(MontoyaApi api, InteractshListener listener) { add(mainPane); } + public InteractshListener getListener() { + return this.listener; + } + public static String getServerText() { return serverText.getText(); } @@ -262,5 +271,8 @@ public Object getValueAt(int rowIndex, int columnIndex) { } } } -} + public void cleanup() { + listener.close(); + } +} diff --git a/src/burp/listeners/InteractshListener.java b/src/burp/listeners/InteractshListener.java index d8a7036..7476098 100644 --- a/src/burp/listeners/InteractshListener.java +++ b/src/burp/listeners/InteractshListener.java @@ -2,59 +2,65 @@ import java.awt.Toolkit; import java.awt.datatransfer.StringSelection; -import java.security.NoSuchAlgorithmException; import java.util.concurrent.TimeUnit; import interactsh.Client; public class InteractshListener { - public Thread poller; - public boolean running = true; + private Thread poller; + private boolean running = true; private Client client; public InteractshListener() { - - try { - client = new Client(); - client.register(); - } catch (NoSuchAlgorithmException ex) { - burp.BurpExtender.api.logging().logToError(ex.getMessage()); - } this.poller = new Thread(new Runnable() { public void run() { + client = new Client(); try { - while (running == true) { - client.poll(); - - try { - TimeUnit.SECONDS.sleep(burp.BurpExtender.getPollTime()); - } catch (InterruptedException ie) { - // Ignore interrupt (re evaluate running and polling) + if(client.register()){ + while (running == true) { + client.poll(); + + try { + TimeUnit.SECONDS.sleep(burp.BurpExtender.getPollTime()); + } catch (InterruptedException ie) { + // Ignore interrupt (re evaluate running and polling) + } } + } else { + burp.BurpExtender.api.logging().logToError("Unable to register interactsh client"); } + + } catch (Exception ex) { burp.BurpExtender.api.logging().logToError(ex.getMessage()); } + + if (client.isRegistered()){ + client.deregister(); + } } }); this.poller.start(); } + public void close() { + this.running = false; + this.poller.interrupt(); + try { + this.poller.join(); + } catch (InterruptedException ex) { + burp.BurpExtender.api.logging().logToError(ex.getMessage()); + } + } + public void pollNowAll() { this.poller.interrupt(); } public void generateCollaborator() { - burp.BurpExtender.api.logging().logToOutput("Generating new Interactsh client"); - String interactDomain = client.getInteractDomain(); burp.BurpExtender.api.logging().logToOutput("New domain is: " + interactDomain); StringSelection stringSelection = new StringSelection(interactDomain); Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null); } - - public void cleanup() { - this.client.deregister(); - } - } \ No newline at end of file diff --git a/src/interactsh/Client.java b/src/interactsh/Client.java index 8c130ef..ed295e6 100644 --- a/src/interactsh/Client.java +++ b/src/interactsh/Client.java @@ -36,12 +36,14 @@ public class Client { private String host = "oast.pro"; private int port = 443; private boolean scheme = true; + private boolean is_registered = false; private String authorization = null; private String pubKey; private String correlationId; - public Client() throws NoSuchAlgorithmException { + public Client() { this.generateKeys(); + this.correlationId = Xid.get().toString(); host = burp.gui.Config.getHost(); @@ -56,7 +58,12 @@ public Client() throws NoSuchAlgorithmException { } } + public boolean isRegistered(){ + return this.is_registered; + } + public boolean register() { + burp.BurpExtender.api.logging().logToOutput("Registering " + correlationId); try { JSONObject registerData = new JSONObject(); registerData.put("public-key", pubKey); @@ -78,6 +85,7 @@ public boolean register() { HttpResponse resp = burp.BurpExtender.api.http().sendRequest(httpRequest).response(); if (resp.statusCode() == 200) { + this.is_registered = true; return true; } else { burp.BurpExtender.api.logging().logToError("Register correlation " + correlationId @@ -172,13 +180,19 @@ public String getInteractDomain() { } } - public void generateKeys() throws NoSuchAlgorithmException { - KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); - kpg.initialize(2048); - KeyPair kp = kpg.generateKeyPair(); - - publicKey = kp.getPublic(); - privateKey = kp.getPrivate(); + public void generateKeys(){ + KeyPairGenerator kpg; + try { + kpg = KeyPairGenerator.getInstance("RSA"); + kpg.initialize(2048); + KeyPair kp = kpg.generateKeyPair(); + + publicKey = kp.getPublic(); + privateKey = kp.getPrivate(); + } catch (NoSuchAlgorithmException e) { + burp.BurpExtender.api.logging().logToError("Unable to generate client key pair"); + burp.BurpExtender.api.logging().logToError(e); + } } private String getPublicKey() {