diff --git a/pom.xml b/pom.xml
index f4b3566..c3861c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,16 +5,15 @@
interactsh
collaborator
- 1.0.1-dev
+ 1.0.2-dev
jar
- net.portswigger.burp.extender
- burp-extender-api
- 2.2
- provided
+ net.portswigger.burp.extensions
+ montoya-api
+ LATEST
org.json
@@ -63,7 +62,7 @@
UTF-8
- 11
- 11
+ 17
+ 17
\ No newline at end of file
diff --git a/src/burp/BurpExtender.java b/src/burp/BurpExtender.java
index aeab013..aaf4eb6 100644
--- a/src/burp/BurpExtender.java
+++ b/src/burp/BurpExtender.java
@@ -1,5 +1,7 @@
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;
@@ -16,227 +18,86 @@
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableModel;
-public class BurpExtender extends AbstractTableModel implements IBurpExtender, IContextMenuFactory, ITab, IExtensionStateListener
-{
+import burp.api.montoya.BurpExtension;
+import burp.api.montoya.MontoyaApi;
+import burp.api.montoya.extension.ExtensionUnloadingHandler;
+
+
+public class BurpExtender implements BurpExtension, ContextMenuItemsProvider, ExtensionUnloadingHandler {
+ public static MontoyaApi api;
public static int pollTime = 60;
- private static IBurpExtenderCallbacks callbacks;
- private static IExtensionHelpers helpers;
-
- private JTabbedPane mainPane;
- private JSplitPane splitPane;
- private JScrollPane scrollPane;
- private JSplitPane tableSplitPane;
- private JPanel resultsPanel;
- private static JTextField pollField;
- private static Table logTable;
- public static JTextField serverText;
- public static JTextField portText;
- public static JTextField authText;
- public static JCheckBox tlsBox;
- private static List log = new ArrayList();
+ public static InteractshTab tab;
private static ArrayList clients = new ArrayList();
- private InteractshListener listener;
-
- //
- // implement IBurpExtender
- //
+ private InteractshListener listener = new InteractshListener();
@Override
- public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks)
- {
- // keep a reference to our callbacks object
- this.callbacks = callbacks;
+ public void initialize(MontoyaApi api) {
+ this.api = api;
+ api.extension().setName("Interactsh Collaborator");
+ api.userInterface().registerContextMenuItemsProvider(this);
+ api.extension().registerUnloadingHandler(this);
- // obtain an extension helpers object
- helpers = callbacks.getHelpers();
+ api.logging().logToOutput("Starting Interactsh Collaborator!");
- // set our extension name
- callbacks.setExtensionName("Interactsh Collaborator");
- callbacks.printOutput("Starting Interactsh Collaborator!");
-
- // Save settings
burp.gui.Config.generateConfig();
+ tab = new InteractshTab(api, listener, clients);
+ burp.gui.Config.loadConfig();
- // Register this as a IExtensionStateListener
- callbacks.registerExtensionStateListener(BurpExtender.this);
-
- // Register this as a IContextMenuFactory
- callbacks.registerContextMenuFactory(BurpExtender.this);
-
- // create our UI
- SwingUtilities.invokeLater(new Runnable()
- {
- @Override
- public void run()
- {
- 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(BurpExtender.this);
- scrollPane = new JScrollPane(logTable);
-
- tableSplitPane.setTopComponent(scrollPane);
- tableSplitPane.setBottomComponent(resultsPanel);
- splitPane.setBottomComponent(tableSplitPane);
-
- JPanel panel = new JPanel();
- JButton CollaboratorButton = new JButton("Generate Interactsh url");
- JLabel pollLabel = new JLabel("Poll Time: ");
- pollField = new JTextField("60", 4);
- pollField.getDocument().addDocumentListener(new PollTimeListener());
-
- listener = new InteractshListener();
- CollaboratorButton.addActionListener(listener);
- panel.add(CollaboratorButton);
- panel.add(pollLabel);
- panel.add(pollField);
- splitPane.setTopComponent(panel);
-
- // Configuration pane
- JPanel configPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
- mainPane.addTab("Configuration", configPanel);
- JPanel innerConfig = new JPanel();
- innerConfig.setSize(new Dimension(80, 150));
- innerConfig.setLayout(new SpringLayout());
- configPanel.add(innerConfig);
-
- serverText = new JTextField("interact.sh", 20);
- portText = new JTextField("443", 20);
- authText = new JTextField("", 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 tls = new JLabel("TLS: ");
- innerConfig.add(tls);
- tls.setLabelFor(tlsBox);
- innerConfig.add(tlsBox);
-
- JButton updateConfigButton = new JButton("Update Settings");
- updateConfigButton.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent 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,
- 5, 2, //rows, cols
- 6, 6, //initX, initY
- 6, 6); //xPad, yPad
-
- burp.gui.Config.loadConfig();
-
-
- // customize our UI components
- callbacks.customizeUiComponent(mainPane);
- callbacks.customizeUiComponent(resultsPanel);
- callbacks.customizeUiComponent(tableSplitPane);
- callbacks.customizeUiComponent(splitPane);
- callbacks.customizeUiComponent(logTable);
- callbacks.customizeUiComponent(scrollPane);
- callbacks.customizeUiComponent(configPanel);
- callbacks.customizeUiComponent(innerConfig);
- callbacks.customizeUiComponent(CollaboratorButton);
-
- // add the custom tab to Burp's UI
- callbacks.addSuiteTab(BurpExtender.this);
- }
- });
- }
-
- public static IBurpExtenderCallbacks getCallbacks() {
- return callbacks;
- }
-
- public static IExtensionHelpers getHelpers() {
- return helpers;
+ api.userInterface().registerSuiteTab("Interactsh", tab);
}
@Override
public void extensionUnloaded() {
- // Get all threads and stop them.
- listener.running = false;
- try {
- TimeUnit.SECONDS.sleep(1);
- } catch (InterruptedException e) {}
- for (int i = 0; i < listener.pollers.size(); i++){
- listener.pollers.get(i).stop();
- }
+ if (listener != null) {
+ // Get all threads and stop them.
+ listener.running = false;
+ try {
+ 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();
+ // Tell all clients to deregister
+ for (int i = 0; i < clients.size(); i++) {
+ clients.get(i).deregister();
+ }
}
- callbacks.printOutput("Thanks for collaborating!");
+ api.logging().logToOutput("Thanks for collaborating!");
}
- public static ArrayList getClients(){
+ public ArrayList getClients() {
return clients;
}
- public static void addClient(Client c){
+ public static void addClient(Client c) {
clients.add(c);
}
- public static int getPollTime(){
- try{
- return Integer.parseInt(pollField.getText());
- }catch (Exception ex) {}
+ public static int getPollTime() {
+ try {
+ return Integer.parseInt(tab.getPollField().getText());
+ } catch (Exception ex) {
+ }
return 60;
}
- public static void updatePollTime(int poll){
+ public static void updatePollTime(int poll) {
pollTime = poll;
}
- public static void addToTable(InteractEntry i){
- log.add(i);
- logTable.revalidate();
- }
-
- //
- // implement ITab
- //
-
- @Override
- public String getTabCaption()
- {
- return "Interactsh";
- }
-
- @Override
- public Component getUiComponent()
- {
- return mainPane;
+ public static void addToTable(InteractEntry i) {
+ tab.addToTable(i);
}
//
- // extend IContextMenuFactory
+ // implement ContextMenuItemsProvider
//
@Override
- public List createMenuItems(IContextMenuInvocation invocation) {
- List menuList = new ArrayList();
+ public List provideMenuItems(ContextMenuEvent event) {
+ List menuList = new ArrayList();
JMenuItem item = new JMenuItem("Generate Interactsh url");
item.addActionListener(new InteractshListener());
menuList.add(item);
@@ -244,94 +105,238 @@ public List createMenuItems(IContextMenuInvocation invocation) {
return menuList;
}
- //
- // extend AbstractTableModel
- //
+ 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 JCheckBox tlsBox;
+ private List log = new ArrayList();
+ private InteractshListener listener;
+ private ArrayList clients;
+
+ public InteractshTab(MontoyaApi api, InteractshListener listener, ArrayList clients) {
+ this.listener = listener;
+ this.clients = clients;
+
+ 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");
+ JLabel pollLabel = new JLabel("Poll Time: ");
+ pollField = new JTextField("60", 4);
+ pollField.getDocument().addDocumentListener(new PollTimeListener());
+
+ CollaboratorButton.addActionListener(listener);
+ panel.add(CollaboratorButton);
+ panel.add(pollLabel);
+ panel.add(pollField);
+ 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, 150));
+ innerConfig.setLayout(new SpringLayout());
+ subConfigPanel.add(innerConfig);
+
+ serverText = new JTextField("oast.pro", 20);
+ portText = new JTextField("443", 20);
+ authText = new JTextField("", 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 tls = new JLabel("TLS: ");
+ innerConfig.add(tls);
+ tls.setLabelFor(tlsBox);
+ innerConfig.add(tlsBox);
+
+ JButton updateConfigButton = new JButton("Update Settings");
+ updateConfigButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent 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,
+ 5, 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);
+ }
- @Override
- public int getRowCount()
- {
- return log.size();
- }
+ public static String getServerText() {
+ return serverText.getText();
+ }
- @Override
- public int getColumnCount()
- {
- return 4;
- }
+ public static void setServerText(String t) {
+ serverText.setText(t);
+ }
- @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 "";
+ public static String getPortText() {
+ return portText.getText();
}
- }
- @Override
- public Class> getColumnClass(int columnIndex)
- {
- return String.class;
- }
+ public static void setPortText(String text) {
+ portText.setText(text);
+ }
- @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 "";
+ public static String getAuthText() {
+ return authText.getText();
}
- }
- //
- // extend JTable to handle cell selection
- //
+ public static void setAuthText(String text) {
+ authText.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;
+ }
- private class Table extends JTable
- {
- public TableModel tableModel;
- public Table(TableModel tableModel)
- {
- super(tableModel);
- this.tableModel = tableModel;
+ public void addToTable(InteractEntry i) {
+ log.add(i);
+ logTable.revalidate();
}
- @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);
+ //
+ // extend JTable to handle cell selection
+ //
+
+ private class Table extends JTable {
+ public TableModel tableModel;
+
+ public Table(TableModel tableModel) {
+ super(tableModel);
+ this.tableModel = 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
+ 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();
+ 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);
+ 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 4787301..7cb90c4 100644
--- a/src/burp/gui/Config.java
+++ b/src/burp/gui/Config.java
@@ -1,82 +1,68 @@
package burp.gui;
-import burp.IBurpExtenderCallbacks;
-
-import javax.swing.*;
+import burp.api.montoya.persistence.Preferences;
public class Config {
- public static void generateConfig(){
- IBurpExtenderCallbacks callbacks = burp.BurpExtender.getCallbacks();
+ public static void generateConfig() {
+ Preferences preferences = burp.BurpExtender.api.persistence().preferences();
- String server = callbacks.loadExtensionSetting("interactsh-server");
- String port = callbacks.loadExtensionSetting("interactsh-port");
+ String server = preferences.getString("interactsh-server");
+ String port = preferences.getString("interactsh-port");
if ((server == null || server.isEmpty()) ||
- (port == null || port.isEmpty())){
- callbacks.saveExtensionSetting("interactsh-server", "interact.sh");
- callbacks.saveExtensionSetting("interactsh-port", "443");
- callbacks.saveExtensionSetting("interactsh-uses-tls", Boolean.toString(true));
+ (port == null || port.isEmpty()) ||
+ !preferences.stringKeys().contains("interactsh-authorization") ||
+ !preferences.stringKeys().contains("interactsh-uses-tls")) {
+ preferences.setString("interactsh-server", "oast.pro");
+ preferences.setString("interactsh-port", "443");
+ preferences.setString("interactsh-authorization", "");
+ preferences.setString("interactsh-uses-tls", Boolean.toString(true));
}
}
- public static void loadConfig(){
- IBurpExtenderCallbacks callbacks = burp.BurpExtender.getCallbacks();
- String server = callbacks.loadExtensionSetting("interactsh-server");
- String port = callbacks.loadExtensionSetting("interactsh-port");
- boolean tls = Boolean.parseBoolean(callbacks.loadExtensionSetting("interactsh-uses-tls"));
- String authorization = callbacks.loadExtensionSetting("interactsh-authorization");
+ public static void loadConfig() {
+ Preferences preferences = burp.BurpExtender.api.persistence().preferences();
+ String server = preferences.getString("interactsh-server");
+ String port = preferences.getString("interactsh-port");
+ String tls = preferences.getString("interactsh-uses-tls");
+ String authorization = preferences.getString("interactsh-authorization");
// Update each of the text boxes on the Configuration pane
- burp.BurpExtender.serverText.setText(server);
- burp.BurpExtender.portText.setText(port);
- burp.BurpExtender.authText.setText(authorization);
- burp.BurpExtender.tlsBox.setSelected(tls);
+ burp.BurpExtender.tab.setServerText(server);
+ burp.BurpExtender.tab.setPortText(port);
+ burp.BurpExtender.tab.setAuthText(authorization);
+ burp.BurpExtender.tab.setTlsBox(Boolean.parseBoolean(tls));
}
- public static void updateConfig(){
- IBurpExtenderCallbacks callbacks = burp.BurpExtender.getCallbacks();
+ 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.serverText.getText();
- String port = burp.BurpExtender.portText.getText();
- String authorization = burp.BurpExtender.authText.getText();
- boolean tls = burp.BurpExtender.tlsBox.isSelected();
-
- callbacks.saveExtensionSetting("interactsh-server", server);
- callbacks.saveExtensionSetting("interactsh-port", port);
- callbacks.saveExtensionSetting("interactsh-uses-tls", Boolean.toString(tls));
- callbacks.saveExtensionSetting("interactsh-authorization", authorization);
- }
-
- public static String getHost(){
- return burp.BurpExtender.getCallbacks().loadExtensionSetting("interactsh-server");
+ String server = burp.BurpExtender.tab.getServerText();
+ String port = burp.BurpExtender.tab.getPortText();
+ String authorization = burp.BurpExtender.tab.getAuthText();
+ 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-authorization", authorization);
}
- public static String getPort(){
- return burp.BurpExtender.getCallbacks().loadExtensionSetting("interactsh-port");
+ public static String getHost() {
+ return burp.BurpExtender.api.persistence().preferences().getString("interactsh-server");
}
- public static boolean getScheme(){
- return Boolean.parseBoolean(burp.BurpExtender.getCallbacks().loadExtensionSetting("interactsh-uses-tls"));
+ public static String getPort() {
+ return burp.BurpExtender.api.persistence().preferences().getString("interactsh-port");
}
- public static String getAuth(){
- return burp.BurpExtender.getCallbacks().loadExtensionSetting("interactsh-authorization");
+ public static boolean getScheme() {
+ return Boolean.parseBoolean(burp.BurpExtender.api.persistence().preferences().getString("interactsh-uses-tls"));
}
- public static String getUrl(){
- String scheme = "https://";
- if(Boolean.parseBoolean(burp.BurpExtender.getCallbacks().loadExtensionSetting("interactsh-server")) == false){
- scheme = "http://";
- }
-
- String url = scheme + getHost();
- String port = getPort();
- if(!(port == "80" || port == "443")){
- url += ":" + port;
- }
-
- return url;
+ public static String getAuth() {
+ return burp.BurpExtender.api.persistence().preferences().getString("interactsh-authorization");
}
}
diff --git a/src/burp/listeners/InteractshListener.java b/src/burp/listeners/InteractshListener.java
index c35a5b9..ec710b1 100644
--- a/src/burp/listeners/InteractshListener.java
+++ b/src/burp/listeners/InteractshListener.java
@@ -13,44 +13,48 @@
public class InteractshListener implements ActionListener {
public ArrayList pollers = new ArrayList();
public boolean running = true;
- public InteractshListener() {}
+
+ public InteractshListener() {
+ }
+
@Override
public void actionPerformed(ActionEvent e) {
- BurpExtender.getCallbacks().printOutput("Generating new Interactsh client");
- Client c = new Client();
- try {
- c.generateKeys();
+ 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.pollTime);
- }
- } else {
- BurpExtender.getCallbacks().printOutput("Error registering client");
- }
- } catch (Exception ex) {
- // Nothing to do here.
- }
- }
- });
- pollers.add(polling);
- polling.start();
+ 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");
+ }
+ } catch (InterruptedException ie) {
+ } 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();
- BurpExtender.getCallbacks().printOutput("New domain is: " + domain);
- StringSelection stringSelection = new StringSelection(domain);
- Toolkit.getDefaultToolkit().getSystemClipboard().setContents(stringSelection, null);
- } catch (Exception ex){
- BurpExtender.getCallbacks().printOutput(ex.getMessage());
- }
+ 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());
+ }
}
}
\ No newline at end of file
diff --git a/src/interactsh/Client.java b/src/interactsh/Client.java
index 7cb1d63..82984db 100644
--- a/src/interactsh/Client.java
+++ b/src/interactsh/Client.java
@@ -1,13 +1,16 @@
package interactsh;
-import burp.IBurpExtenderCallbacks;
-import burp.BurpExtender;
-import burp.IResponseInfo;
+import burp.api.montoya.http.message.requests.HttpRequest;
+import burp.api.montoya.http.message.responses.HttpResponse;
+import burp.api.montoya.http.HttpService;
+
import javax.crypto.*;
import javax.crypto.spec.*;
+
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;
@@ -17,26 +20,24 @@
public class Client {
public PrivateKey privateKey;
private PublicKey publicKey;
- private IBurpExtenderCallbacks callbacks = BurpExtender.getCallbacks();
private Xid xid;
private String secretKey;
private String correlationId;
// Defaults
- private String server = "https://interact.sh";
- private String host = "interact.sh";
+ private String host = "oast.pro";
private int port = 443;
private boolean scheme = true;
private String authorization = null;
- public Client(){
- server = burp.gui.Config.getUrl();
+ public Client() {
host = burp.gui.Config.getHost();
scheme = burp.gui.Config.getScheme();
authorization = burp.gui.Config.getAuth();
try {
port = Integer.parseInt(burp.gui.Config.getPort());
- } catch (NumberFormatException ne){
+
+ } catch (NumberFormatException ne) {
port = 443;
}
}
@@ -58,19 +59,20 @@ public boolean registerClient() throws Exception {
+ "User-Agent: Interact.sh Client\r\n"
+ "Content-Type: application/json\r\n"
+ "Content-Length: " + registerData.toString().length() + "\r\n";
- if(!(authorization == null || authorization.isEmpty())){
+ if (!(authorization == null || authorization.isEmpty())) {
request += "Authorization: " + authorization + "\r\n";
}
request += "Connection: close\r\n\r\n"
+ registerData.toString();
- byte[] response = callbacks.makeHttpRequest(host, port, scheme, request.getBytes(StandardCharsets.UTF_8));
- IResponseInfo responseInfo = BurpExtender.getHelpers().analyzeResponse(response);
- if (responseInfo.getStatusCode() == 200) {
+ HttpRequest httpRequest = HttpRequest.httpRequest(HttpService.httpService(host, port, scheme), request);
+ HttpResponse resp = burp.BurpExtender.api.http().sendRequest(httpRequest).response();
+
+ if (resp.statusCode() == 200) {
return true;
}
- }catch (Exception ex){
- callbacks.printOutput(ex.getMessage());
+ } catch (Exception ex) {
+ burp.BurpExtender.api.logging().logToError(ex.getMessage());
}
return false;
}
@@ -79,67 +81,69 @@ public boolean poll() throws IOException, InterruptedException {
String request = "GET /poll?id=" + correlationId + "&secret=" + secretKey + " HTTP/1.1\r\n"
+ "Host: " + host + "\r\n"
+ "User-Agent: Interact.sh Client\r\n";
- if(!(authorization == null || authorization.isEmpty())){
+ if (!(authorization == null || authorization.isEmpty())) {
request += "Authorization: " + authorization + "\r\n";
}
request += "Connection: close\r\n\r\n";
- byte[] response = callbacks.makeHttpRequest(host, port, scheme, request.getBytes(StandardCharsets.UTF_8));
- IResponseInfo responseInfo = BurpExtender.getHelpers().analyzeResponse(response);
- if (responseInfo.getStatusCode() != 200) {
- callbacks.printOutput("Poll for " + correlationId + " was unsuccessful: " + responseInfo.getStatusCode());
+ 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());
return false;
}
- String responseStr = new String(response);
- String responseBody = responseStr.split("\r\n\r\n")[1];
+ String responseBody = resp.bodyToString();
try {
JSONObject jsonObject = new JSONObject(responseBody);
String aesKey = jsonObject.getString("aes_key");
String key = decryptAesKey(aesKey);
- JSONArray data = jsonObject.getJSONArray("data");
- for (int i = 0; i < data.length(); i++){
- String d = data.getString(i);
+ if (!jsonObject.isNull("data")) {
+ JSONArray data = jsonObject.getJSONArray("data");
+ for (int i = 0; i < data.length(); i++) {
+ String d = data.getString(i);
- String decryptedData = decryptData(d, key);
+ String decryptedData = decryptData(d, key);
- InteractEntry entry = new InteractEntry(decryptedData);
- burp.BurpExtender.addToTable(entry);
- callbacks.printOutput(entry.toString());
+ InteractEntry entry = new InteractEntry(decryptedData);
+ burp.BurpExtender.addToTable(entry);
+ burp.BurpExtender.api.logging().logToOutput(entry.toString());
+ }
}
-
- } catch(Exception ex){
- callbacks.printOutput(ex.getMessage());
+ } catch (Exception ex) {
+ burp.BurpExtender.api.logging().logToError(ex.getMessage());
}
return true;
}
- public void deregister(){
- callbacks.printOutput("Deregistering " + correlationId);
+ public void deregister() {
+ burp.BurpExtender.api.logging().logToOutput("Deregistering " + correlationId);
try {
JSONObject deregisterData = new JSONObject();
deregisterData.put("correlation-id", correlationId);
+ deregisterData.put("secret-key", secretKey);
String request = "POST /deregister HTTP/1.1\r\n"
+ "Host: " + host + "\r\n"
+ "User-Agent: Interact.sh Client\r\n"
+ "Content-Type: application/json\r\n"
+ "Content-Length: " + deregisterData.toString().length() + "\r\n";
- if(!(authorization == null || authorization.isEmpty())){
+ if (!(authorization == null || authorization.isEmpty())) {
request += "Authorization: " + authorization + "\r\n";
}
request += "Connection: close\r\n\r\n"
+ deregisterData.toString();
- callbacks.makeHttpRequest(host, port, scheme, request.getBytes(StandardCharsets.UTF_8));
- }catch (Exception ex){
- callbacks.printOutput(ex.getMessage());
+ HttpRequest httpRequest = HttpRequest.httpRequest(HttpService.httpService(host, port, scheme), request);
+ burp.BurpExtender.api.http().sendRequest(httpRequest).response();
+ } catch (Exception ex) {
+ burp.BurpExtender.api.logging().logToError(ex.getMessage());
}
}
- public String getInteractDomain(){
- if (correlationId == null || correlationId.isEmpty()){
+ public String getInteractDomain() {
+ if (correlationId == null || correlationId.isEmpty()) {
return "";
} else {
String fullDomain = correlationId;
@@ -147,7 +151,7 @@ public String getInteractDomain(){
// Fix the string up to 33 characters
Random random = new Random();
while (fullDomain.length() < 33) {
- fullDomain += (char)(random.nextInt(26) + 'a');
+ fullDomain += (char) (random.nextInt(26) + 'a');
}
fullDomain += "." + host;
return fullDomain;
@@ -163,18 +167,17 @@ public void generateKeys() throws NoSuchAlgorithmException {
privateKey = kp.getPrivate();
}
- private String getPublicKey(){
+ private String getPublicKey() {
String pubKey = "-----BEGIN PUBLIC KEY-----\n";
- String [] chunks = splitStringEveryN(Base64.getEncoder().encodeToString(publicKey.getEncoded()), 64);
- for (String chunk: chunks) {
+ String[] chunks = splitStringEveryN(Base64.getEncoder().encodeToString(publicKey.getEncoded()), 64);
+ for (String chunk : chunks) {
pubKey += chunk + "\n";
}
pubKey += "-----END PUBLIC KEY-----\n";
return pubKey;
}
- private String decryptAesKey(String encrypted) throws Exception
- {
+ private String decryptAesKey(String encrypted) throws Exception {
byte[] cipherTextArray = Base64.getDecoder().decode(encrypted);
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
@@ -198,10 +201,10 @@ private static String decryptData(String input, String key) throws Exception {
byte[] decrypted = cipher.doFinal(cipherText);
return new String(decrypted);
- };
+ }
private String[] splitStringEveryN(String s, int interval) {
- int arrayLength = (int) Math.ceil(((s.length() / (double)interval)));
+ int arrayLength = (int) Math.ceil(((s.length() / (double) interval)));
String[] result = new String[arrayLength];
int j = 0;
diff --git a/src/interactsh/InteractEntry.java b/src/interactsh/InteractEntry.java
index 077125a..74aefea 100644
--- a/src/interactsh/InteractEntry.java
+++ b/src/interactsh/InteractEntry.java
@@ -1,4 +1,5 @@
package interactsh;
+
import org.json.*;
// {"protocol":"dns","unique-id":"c4jup534f3acspvifdr0cru63feyyyyyn","full-id":"c4jup534f3acspvifdr0cru63feyyyyyn","q-type":"A","raw-request":";; opcode: QUERY, status: NOERROR, id: 52297\n;; flags: cd; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0\n\n;; QUESTION SECTION:\n;c4jup534f3acspvifdr0cru63feyyyyyn.interact.sh.\tIN\t A\n","raw-response":";; opcode: QUERY, status: NOERROR, id: 52297\n;; flags: qr aa cd; QUERY: 1, ANSWER: 1, AUTHORITY: 2, ADDITIONAL: 2\n\n;; QUESTION SECTION:\n;c4jup534f3acspvifdr0cru63feyyyyyn.interact.sh.\tIN\t A\n\n;; ANSWER SECTION:\nc4jup534f3acspvifdr0cru63feyyyyyn.interact.sh.\t3600\tIN\tA\t46.101.25.250\n\n;; AUTHORITY SECTION:\nc4jup534f3acspvifdr0cru63feyyyyyn.interact.sh.\t3600\tIN\tNS\tns1.interact.sh.\nc4jup534f3acspvifdr0cru63feyyyyyn.interact.sh.\t3600\tIN\tNS\tns2.interact.sh.\n\n;; ADDITIONAL SECTION:\nns1.interact.sh.\t3600\tIN\tA\t46.101.25.250\nns2.interact.sh.\t3600\tIN\tA\t46.101.25.250\n","remote-address":"172.253.196.66","timestamp":"2021-08-26T19:35:24.221293174Z"}
@@ -22,16 +23,28 @@ public InteractEntry(String event) throws JSONException {
private String processDetails(String protocol, JSONObject obj) throws JSONException {
String result;
- switch(protocol){
+ switch (protocol) {
case "dns":
result = "Query Type: " + obj.getString("q-type") + "\n\n";
result += "Request: \n" + obj.getString("raw-request") + "\n";
result += "Response: \n" + obj.getString("raw-response") + "\n";
break;
+ case "ftp":
+ result = "FTP From: " + obj.getString("remote-address") + "\n\n";
+ result += "Request: \n" + obj.getString("raw-request") + "\n";
+ break;
case "http":
result = "Request: \n" + obj.getString("raw-request") + "\n";
result += "Response: \n" + obj.getString("raw-response") + "\n";
break;
+ case "ldap":
+ result = "LDAP From: " + obj.getString("remote-address") + "\n\n";
+ result += "Request: \n" + obj.getString("raw-request") + "\n";
+ break;
+ case "responder":
+ case "smb":
+ result = "Request: \n" + obj.getString("raw-request") + "\n";
+ break;
case "smtp":
result = "SMTP From: " + obj.getString("smtp-from") + "\n\n";
result += "Request: \n" + obj.getString("raw-request") + "\n";
@@ -42,7 +55,7 @@ private String processDetails(String protocol, JSONObject obj) throws JSONExcept
return result;
}
- public String toString(){
+ public String toString() {
return "Protocol: " + protocol + "\n"
+ "UID: " + uid + "\n"
+ "Address: " + address + "\n"