├── HandyCollaborator1.png ├── HandyCollaborator2.png ├── HandyCollaborator3.png ├── HandyCollaborator4.png ├── LICENSE ├── src └── main │ └── java │ └── burp │ ├── CustomScanIssue.java │ ├── InteractionServer.java │ └── BurpExtender.java ├── pom.xml └── README.md /HandyCollaborator1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/federicodotta/HandyCollaborator/HEAD/HandyCollaborator1.png -------------------------------------------------------------------------------- /HandyCollaborator2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/federicodotta/HandyCollaborator/HEAD/HandyCollaborator2.png -------------------------------------------------------------------------------- /HandyCollaborator3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/federicodotta/HandyCollaborator/HEAD/HandyCollaborator3.png -------------------------------------------------------------------------------- /HandyCollaborator4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/federicodotta/HandyCollaborator/HEAD/HandyCollaborator4.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 federicodotta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/main/java/burp/CustomScanIssue.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.net.URL; 4 | 5 | public class CustomScanIssue implements IScanIssue { 6 | 7 | private IHttpService httpService; 8 | private URL url; 9 | private IHttpRequestResponse[] httpMessages; 10 | private String name; 11 | private String severity; 12 | private String confidence; 13 | private String issueDetail; 14 | private String remediationDetail; 15 | 16 | public CustomScanIssue( 17 | IHttpService httpService, 18 | URL url, 19 | IHttpRequestResponse[] httpMessages, 20 | String name, 21 | String severity, 22 | String confidence, 23 | String issueDetail, 24 | String remediationDetail 25 | ) 26 | { 27 | this.httpService = httpService; 28 | this.url = url; 29 | this.httpMessages = httpMessages; 30 | this.name = name; 31 | this.severity = severity; 32 | this.confidence = confidence; 33 | this.issueDetail = issueDetail; 34 | this.remediationDetail = remediationDetail; 35 | } 36 | 37 | @Override 38 | public URL getUrl() 39 | { 40 | return url; 41 | } 42 | 43 | @Override 44 | public String getIssueName() 45 | { 46 | return name; 47 | } 48 | 49 | @Override 50 | public int getIssueType() 51 | { 52 | return 0; 53 | } 54 | 55 | @Override 56 | public String getSeverity() 57 | { 58 | return severity; 59 | } 60 | 61 | @Override 62 | public String getConfidence() 63 | { 64 | return confidence; 65 | } 66 | 67 | @Override 68 | public String getIssueBackground() 69 | { 70 | return null; 71 | } 72 | 73 | @Override 74 | public String getRemediationBackground() 75 | { 76 | return null; 77 | } 78 | 79 | @Override 80 | public String getIssueDetail() 81 | { 82 | return issueDetail; 83 | } 84 | 85 | @Override 86 | public String getRemediationDetail() 87 | { 88 | return remediationDetail; 89 | } 90 | 91 | @Override 92 | public IHttpRequestResponse[] getHttpMessages() 93 | { 94 | return httpMessages; 95 | } 96 | 97 | @Override 98 | public IHttpService getHttpService() 99 | { 100 | return httpService; 101 | } 102 | 103 | } 104 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | org.fd 4 | HandyCollaborator 5 | 0.2 6 | Handy Collaborator 7 | Burp Suite Plugin to use Collaborator during manual testing 8 | jar 9 | 10 | 11 | UTF-8 12 | 13 | 14 | 15 | 16 | 17 | org.apache.maven.plugins 18 | maven-compiler-plugin 19 | 3.1 20 | 21 | 1.7 22 | 1.7 23 | 24 | 25 | 26 | maven-assembly-plugin 27 | 28 | 29 | true 30 | 31 | 32 | jar-with-dependencies 33 | 34 | 35 | 36 | 37 | true 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | make-assembly 46 | package 47 | 48 | single 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | net.portswigger.burp.extender 60 | burp-extender-api 61 | 1.7.22 62 | 63 | 64 | 65 | 66 | org.apache.commons 67 | commons-lang3 68 | 3.6 69 | 70 | 71 | 72 | 73 | org.json 74 | json 75 | 20180130 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Handy Collaborator 2 | Handy Collaborator is a Burp Suite Extension that lets you use the Collaborator tool during manual testing in a comfortable way. It is possible to generate a Collaborator payload from the contextual menu of editable tabs (Repeater, Intercept, etc.) and a separate thread will check periodically all interactions (DNS, HTTP and SMTP) received by the Collaborator for the generated payloads. If an interaction is found, an issue with all the details is added to the target host. 3 | 4 | # Authors 5 | - Federico Dotta, Security Advisor at @ Mediaservice.net 6 | - Gianluca Baldi, Security Expert at @ Mediaservice.net 7 | 8 | # Installation 9 | 1. Download Burp Suite: http://portswigger.net/burp/download.html 10 | 2. Install Handy Collaborator from the BApp Store or follow these steps: 11 | 3. Download the last release of Handy Collaborator 12 | 4. Open Burp -> Extender -> Extensions -> Add -> Choose HandyCollaboratorXX.jar file 13 | 14 | # Usage and examples 15 | 1. In the Repeater or the Intercept tab, right click on the point where you want to insert the Collaborator payload (or select a portion of text that will be replaced with the Collaborator payload) and click on "Insert Collaborator payload" or on "Insert Collaborator insertion point". 16 | 2. Execute the request with the payload or with the insertion point 17 | 3. If the payload causes an external interaction (DNS, HTTP or SMTP), soon an issue will appear in the Target tab with all the details of the interaction (request/reponse, type, timestamp and specific details that depend on the type of interaction) 18 | 4. That's all! 19 | 20 | If you choose the "Insert Collaborator insertion point" option, the insertion point will be transparently replaced with a new Collaborator payload every time that the request will be executed. In this way, if you execute multiple tests on the same request, a different Collaborator URL will be transparently inserted in each request and, in the case of an interaction, the exact request responsible for the interaction will be reported. 21 | 22 | # Limitations 23 | Currently, due to limitations in Burp Suite API, it is not possible to retrieve details on Collaborator interactions related to the payloads generated with this extension after unloading the extension or closing Burp Suite. The reason is that it is not possible to save the Collaborator context. An issue has been opened in Burp Suite Support Center on February 2017 and maybe this feature will be added in future (fingers crossed). 24 | 25 | # Screenshot 26 | ![Handy Collaborator Screenshot](https://raw.githubusercontent.com/federicodotta/HandyCollaborator/master/HandyCollaborator1.png) 27 | ![Handy Collaborator Screenshot](https://raw.githubusercontent.com/federicodotta/HandyCollaborator/master/HandyCollaborator2.png) 28 | ![Handy Collaborator Screenshot](https://raw.githubusercontent.com/federicodotta/HandyCollaborator/master/HandyCollaborator4.png) 29 | ![Handy Collaborator Screenshot](https://raw.githubusercontent.com/federicodotta/HandyCollaborator/master/HandyCollaborator3.png) 30 | 31 | # MIT License 32 | 33 | Copyright (c) 2017 Handy Collaborator 34 | 35 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 36 | 37 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 38 | 39 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/main/java/burp/InteractionServer.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.io.PrintWriter; 4 | import java.text.DateFormat; 5 | import java.text.SimpleDateFormat; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.TimeZone; 9 | import java.util.regex.Matcher; 10 | import java.util.regex.Pattern; 11 | import java.util.ArrayList; 12 | import java.util.Base64; 13 | import java.util.Date; 14 | import static java.util.concurrent.TimeUnit.*; 15 | 16 | public class InteractionServer extends Thread { 17 | 18 | private IBurpExtenderCallbacks callbacks; 19 | private HashMap processedRequestResponse; 20 | 21 | private PrintWriter stdout; 22 | private PrintWriter stderr; 23 | 24 | private List collaboratorContextList; 25 | 26 | private volatile boolean goOn; 27 | 28 | private static final String issueName = " Collaborator interaction - Handy Collaborator"; 29 | String remediation = "The remediations depends on the specific issue manually tested."; 30 | private static final String severity = "High"; 31 | private static final String confidence = "Certain"; 32 | 33 | private static final int pollingMilliseconds = 3000; 34 | 35 | private final Object pauseLock = new Object(); 36 | private volatile boolean paused = false; 37 | 38 | public InteractionServer(IBurpExtenderCallbacks callbacks, HashMap processedRequestResponse, IBurpCollaboratorClientContext initialCollaboratorContext) { 39 | 40 | this.callbacks = callbacks; 41 | this.processedRequestResponse = processedRequestResponse; 42 | 43 | // Initialize stdout and stderr 44 | this.stdout = new PrintWriter(callbacks.getStdout(), true); 45 | this.stderr = new PrintWriter(callbacks.getStderr(), true); 46 | 47 | this.collaboratorContextList = new ArrayList(); 48 | 49 | if(initialCollaboratorContext != null) { 50 | this.collaboratorContextList.add(initialCollaboratorContext); 51 | } else { 52 | stdout.println("Collaborator disabled"); 53 | } 54 | 55 | this.goOn = true; 56 | 57 | } 58 | 59 | public void setGoOn(boolean goOn) { 60 | this.goOn = goOn; 61 | } 62 | 63 | public void pause() { 64 | paused = true; 65 | stdout.println("Stopping Collaborator interactions polling"); 66 | } 67 | 68 | public void resumeThread() { 69 | synchronized (pauseLock) { 70 | paused = false; 71 | pauseLock.notifyAll(); // Unblocks thread 72 | } 73 | stdout.println("Restarting Collaborator interactions polling"); 74 | } 75 | 76 | public void addNewCollaboratorContext(IBurpCollaboratorClientContext collaboratorContext) { 77 | this.collaboratorContextList.add(collaboratorContext); 78 | } 79 | 80 | public void addIssue(IBurpCollaboratorInteraction interaction, IBurpCollaboratorClientContext collaboratorContext) { 81 | 82 | String interactionId = interaction.getProperty("interaction_id"); 83 | IHttpRequestResponse requestResponse = processedRequestResponse.get(interactionId + "." + collaboratorContext.getCollaboratorServerLocation()); 84 | 85 | String issueDetails = ""; 86 | 87 | // Convert timestamp to local time 88 | String dateStr = interaction.getProperty("time_stamp"); 89 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss z"); 90 | TimeZone tz = TimeZone.getDefault(); 91 | sdf.setTimeZone(tz); 92 | String localTimestamp = ""; 93 | try{ 94 | Date date = sdf.parse(dateStr); 95 | localTimestamp = sdf.format(date); 96 | } catch(Exception e) { 97 | localTimestamp = dateStr; 98 | } 99 | 100 | switch (interaction.getProperty("type")) { 101 | 102 | case "DNS": 103 | 104 | issueDetails = "The Collaborator server received a DNS lookup of type " + interaction.getProperty("query_type") + 105 | " for the domain name " + interaction.getProperty("interaction_id") + "." + 106 | collaboratorContext.getCollaboratorServerLocation() + "

" + 107 | "The lookup was received from IP address " + interaction.getProperty("client_ip") + " at " + 108 | localTimestamp + "

" + "DNS query (encoded in Base64)
" + 109 | interaction.getProperty("raw_query"); 110 | break; 111 | 112 | case "HTTP": 113 | 114 | issueDetails = "The Collaborator server received an HTTP request for the domain name " + interaction.getProperty("interaction_id") + 115 | "." + collaboratorContext.getCollaboratorServerLocation() + ".

The request was received from IP address " + 116 | interaction.getProperty("client_ip") + " at " + localTimestamp + "

" + 117 | "Request to collaborator (encoded in Base64)
" + interaction.getProperty("request") + "

" + 118 | "Response from collaborator (encoded in Base64)
" + interaction.getProperty("response"); 119 | 120 | break; 121 | 122 | case "SMTP": 123 | 124 | String decodedConversation = new String(Base64.getDecoder().decode(interaction.getProperty("conversation"))); 125 | 126 | Pattern p = Pattern.compile(".*mail from:.*?<(.*?)>.*rcpt to:.*?<(.*?)>.*\\r\\n\\r\\n(.*?)\\r\\n\\.\\r\\n.*",Pattern.CASE_INSENSITIVE + Pattern.DOTALL); 127 | Matcher m = p.matcher(decodedConversation); 128 | 129 | if(m.find()) { 130 | String from = m.group(1); 131 | String to = m.group(2); 132 | String message = m.group(3); 133 | 134 | issueDetails = "The Collaborator server received an SMTP connection from IP address " + 135 | interaction.getProperty("client_ip") + " at " + localTimestamp + "

" + 136 | "The email details were:

From:
" + from + "

To:
" + to + 137 | "

Message:
" + message + "

" + 138 | "SMTP Conversation:

" + decodedConversation.replace("\r\n", "
"); 139 | } else { 140 | issueDetails = "The Collaborator server received an SMTP connection from IP address " + 141 | interaction.getProperty("client_ip") + " at " + localTimestamp + "

" + 142 | "SMTP Conversation:

" + decodedConversation.replace("\r\n", "
"); 143 | } 144 | 145 | break; 146 | 147 | default: 148 | 149 | issueDetails = "The Collaborator server received a " + interaction.getProperty("type") + " interaction from IP address " + 150 | interaction.getProperty("client_ip") + " at " + localTimestamp + " (domain name: " + 151 | interaction.getProperty("interaction_id") + "." + collaboratorContext.getCollaboratorServerLocation() + ")"; 152 | 153 | break; 154 | 155 | } 156 | 157 | CustomScanIssue newIssue = new CustomScanIssue( 158 | requestResponse.getHttpService(), 159 | callbacks.getHelpers().analyzeRequest(requestResponse).getUrl(), 160 | new IHttpRequestResponse[] { requestResponse }, 161 | interaction.getProperty("type") + issueName, 162 | severity, 163 | confidence, 164 | issueDetails, 165 | remediation); 166 | 167 | callbacks.addScanIssue(newIssue); 168 | 169 | } 170 | 171 | public void run() { 172 | 173 | stdout.println("Thread started"); 174 | 175 | DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss"); 176 | long INTERVAL = MILLISECONDS.convert(3, MINUTES); 177 | Date lastPollingDate = null; 178 | 179 | while(goOn) { 180 | 181 | synchronized (pauseLock) { 182 | 183 | // Maybe is changed while waiting for pauseLock 184 | if(!goOn) { 185 | break; 186 | } 187 | 188 | if (paused) { 189 | try { 190 | pauseLock.wait(); 191 | } catch (InterruptedException e) { 192 | stderr.println("Exception with wait/notify"); 193 | stderr.println(e.toString()); 194 | } 195 | // Maybe is changed while waiting for pauseLock 196 | if(!goOn) { 197 | break; 198 | } 199 | } 200 | 201 | } 202 | 203 | Date date = new Date(); 204 | if(lastPollingDate == null || (date.getTime() - lastPollingDate.getTime()) > INTERVAL) { 205 | stdout.println("**** " + dateFormat.format(date) + " ****"); 206 | for(int i=0;i allCollaboratorInteractions = collaboratorContextList.get(i).fetchAllCollaboratorInteractions(); 225 | 226 | for(int j=0; j < allCollaboratorInteractions.size(); j++) { 227 | 228 | addIssue(allCollaboratorInteractions.get(j),collaboratorContextList.get(i)); 229 | 230 | /* 231 | // DEBUG - Print all interaction properties 232 | Map currentProperties = allCollaboratorInteractions.get(i).getProperties(); 233 | Set a = currentProperties.keySet(); 234 | Iterator b = a.iterator(); 235 | while(b.hasNext()) { 236 | String d = b.next(); 237 | stdout.println(d); 238 | stdout.println(currentProperties.get(d)); 239 | } 240 | */ 241 | 242 | } 243 | 244 | } catch(IllegalStateException e) { 245 | //stdout.println("Can't fetch interactions while Collaborator is disabled (Burp Suite limitation)"); 246 | } catch(Exception f) { 247 | stdout.println("Exception"); 248 | stdout.println(f.toString()); 249 | } 250 | 251 | } 252 | 253 | try { 254 | Thread.sleep(pollingMilliseconds); 255 | } catch (InterruptedException e) { 256 | stderr.println(e.toString()); 257 | } 258 | 259 | } 260 | 261 | } 262 | 263 | } 264 | -------------------------------------------------------------------------------- /src/main/java/burp/BurpExtender.java: -------------------------------------------------------------------------------- 1 | package burp; 2 | 3 | import java.awt.Color; 4 | import java.awt.Component; 5 | import java.awt.Font; 6 | import java.awt.event.ActionEvent; 7 | import java.awt.event.ActionListener; 8 | import java.io.PrintWriter; 9 | import java.util.ArrayList; 10 | import java.util.Arrays; 11 | import java.util.HashMap; 12 | import java.util.List; 13 | 14 | import org.json.*; 15 | 16 | import javax.swing.BorderFactory; 17 | import javax.swing.BoxLayout; 18 | import javax.swing.JCheckBox; 19 | import javax.swing.JLabel; 20 | import javax.swing.JMenuItem; 21 | import javax.swing.JPanel; 22 | import javax.swing.SwingUtilities; 23 | 24 | import org.apache.commons.lang3.ArrayUtils; 25 | 26 | public class BurpExtender implements IBurpExtender, IContextMenuFactory, ActionListener, IExtensionStateListener, IHttpListener, ITab { 27 | 28 | private IBurpExtenderCallbacks callbacks; 29 | private IExtensionHelpers helpers; 30 | 31 | private PrintWriter stdout; 32 | private PrintWriter stderr; 33 | 34 | private IContextMenuInvocation currentInvocation; 35 | 36 | private HashMap processedRequestResponse; 37 | 38 | private IBurpCollaboratorClientContext collaboratorContext; 39 | 40 | private InteractionServer interactionServer; 41 | 42 | private final String collaboratorInsertionPointString = (char)167 + "COLLABORATOR_PAYLOAD" + (char)167; 43 | 44 | private String currentCollaboratorLocation; 45 | private boolean currentCollaboratorPollOverUnenecryptedHttp; 46 | private String currentCollaboratorPollingLocation; 47 | private String currentCollaboratorType; 48 | 49 | private JPanel mainPanel; 50 | private JCheckBox enablePolling; 51 | 52 | public void registerExtenderCallbacks(final IBurpExtenderCallbacks callbacks) { 53 | 54 | this.callbacks = callbacks; 55 | 56 | // Obtain an extension helpers object 57 | helpers = callbacks.getHelpers(); 58 | 59 | // Set our extension name 60 | callbacks.setExtensionName("Handy Collaborator"); 61 | 62 | //register to produce options for the context menu 63 | callbacks.registerContextMenuFactory(this); 64 | 65 | //register to get extension state changes 66 | callbacks.registerExtensionStateListener(this); 67 | 68 | // register ourselves as an HttpListener 69 | callbacks.registerHttpListener(this); 70 | 71 | // Initialize stdout and stderr 72 | stdout = new PrintWriter(callbacks.getStdout(), true); 73 | stderr = new PrintWriter(callbacks.getStderr(), true); 74 | 75 | stdout.println("Welcome to Handy Collaborator, the plugin that make it comfortable to use the Collaborator during manual testing!"); 76 | stdout.println("Created by Federico Dotta and Gianluca Baldi"); 77 | stdout.println(""); 78 | stdout.println("Github: https://github.com/federicodotta/HandyCollaborator"); 79 | stdout.println(""); 80 | 81 | initializeCurrentCollaboratorVariables(); 82 | 83 | if(!(currentCollaboratorType.equals("none"))) { 84 | collaboratorContext = callbacks.createBurpCollaboratorClientContext(); 85 | } else { 86 | collaboratorContext = null; 87 | } 88 | 89 | processedRequestResponse = new HashMap(); 90 | 91 | interactionServer = new InteractionServer(callbacks,processedRequestResponse,collaboratorContext); 92 | 93 | interactionServer.start(); 94 | 95 | SwingUtilities.invokeLater(new Runnable() { 96 | 97 | @Override 98 | public void run() { 99 | 100 | mainPanel = new JPanel(); 101 | mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); 102 | 103 | JPanel innerPanel = new JPanel(); 104 | innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.Y_AXIS)); 105 | innerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); 106 | 107 | JLabel pollingTitleLabel = new JLabel("Polling options"); 108 | pollingTitleLabel.setForeground(new Color(249,130,11)); 109 | pollingTitleLabel.setFont(new Font("Nimbus", Font.BOLD, 16)); 110 | pollingTitleLabel.setAlignmentX(Component.LEFT_ALIGNMENT); 111 | 112 | JLabel enablePollingLabel = new JLabel(); 113 | String enablePollingLabelContent = "Unchecking this checkbox will temporary disable polling interactions from Collaborator " 114 | + "Server. This option WILL NOT delete Collaborator Contexts. If you re-enable the flag you will get all the interactions" 115 | + " of the current contexts, included the ones generated when polling was disabled. This option is usefull during internal" 116 | + " penetration tests in order to avoid lot of polling alerts in \"Alert\" in Burp Suite Alertts tab. After the internal" 117 | + " penetration test you can connect to Internet and obtain all the interactions of the internal penetration test. " 118 | + "Remeber that if you close Burp Suite you will loose all Collaborato Interactions (by Burp Suite design)"; 119 | enablePollingLabel.setText("" + enablePollingLabelContent + ""); 120 | enablePollingLabel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); 121 | 122 | enablePolling = new JCheckBox("Enable polling"); 123 | enablePolling.setSelected(true); 124 | enablePolling.setActionCommand("enableDisablePolling"); 125 | enablePolling.addActionListener(BurpExtender.this); 126 | enablePolling.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); 127 | 128 | innerPanel.add(pollingTitleLabel); 129 | innerPanel.add(enablePollingLabel); 130 | innerPanel.add(enablePolling); 131 | 132 | mainPanel.add(innerPanel); 133 | 134 | callbacks.customizeUiComponent(mainPanel); 135 | 136 | callbacks.addSuiteTab(BurpExtender.this); 137 | 138 | } 139 | 140 | }); 141 | 142 | } 143 | 144 | public List createMenuItems(IContextMenuInvocation invocation) { 145 | 146 | if(invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST || 147 | invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_RESPONSE) { 148 | 149 | currentInvocation = invocation; 150 | 151 | List menu = new ArrayList(); 152 | 153 | JMenuItem itemInsertCollaboratorPayload = new JMenuItem("Insert collaborator payload"); 154 | itemInsertCollaboratorPayload.setActionCommand("contextInsertCollaboratorPayload"); 155 | itemInsertCollaboratorPayload.addActionListener(this); 156 | 157 | JMenuItem itemInsertCollaboratorInsertionPoint = new JMenuItem("Insert collaborator insertion point"); 158 | itemInsertCollaboratorInsertionPoint.setActionCommand("contextInsertCollaboratorInsertionPoint"); 159 | itemInsertCollaboratorInsertionPoint.addActionListener(this); 160 | 161 | menu.add(itemInsertCollaboratorPayload); 162 | menu.add(itemInsertCollaboratorInsertionPoint); 163 | 164 | return menu; 165 | 166 | } else { 167 | 168 | return null; 169 | 170 | } 171 | } 172 | 173 | public void initializeCurrentCollaboratorVariables() { 174 | 175 | String collaboratorOption = callbacks.saveConfigAsJson("project_options.misc.collaborator_server"); 176 | JSONObject rootJsonObject = new JSONObject(collaboratorOption); 177 | currentCollaboratorLocation = rootJsonObject.getJSONObject("project_options").getJSONObject("misc").getJSONObject("collaborator_server").getString("location"); 178 | currentCollaboratorPollOverUnenecryptedHttp = rootJsonObject.getJSONObject("project_options").getJSONObject("misc").getJSONObject("collaborator_server").getBoolean("poll_over_unencrypted_http"); 179 | currentCollaboratorPollingLocation = rootJsonObject.getJSONObject("project_options").getJSONObject("misc").getJSONObject("collaborator_server").getString("polling_location"); 180 | currentCollaboratorType = rootJsonObject.getJSONObject("project_options").getJSONObject("misc").getJSONObject("collaborator_server").getString("type"); 181 | 182 | } 183 | 184 | public boolean isCollaboratorChanged() { 185 | 186 | String collaboratorOption = callbacks.saveConfigAsJson("project_options.misc.collaborator_server"); 187 | JSONObject rootJsonObject = new JSONObject(collaboratorOption); 188 | 189 | if(!(currentCollaboratorLocation.equals(rootJsonObject.getJSONObject("project_options").getJSONObject("misc").getJSONObject("collaborator_server").getString("location"))) || 190 | !(currentCollaboratorPollOverUnenecryptedHttp == rootJsonObject.getJSONObject("project_options").getJSONObject("misc").getJSONObject("collaborator_server").getBoolean("poll_over_unencrypted_http")) || 191 | !(currentCollaboratorPollingLocation.equals(rootJsonObject.getJSONObject("project_options").getJSONObject("misc").getJSONObject("collaborator_server").getString("polling_location"))) || 192 | !(currentCollaboratorType.equals(rootJsonObject.getJSONObject("project_options").getJSONObject("misc").getJSONObject("collaborator_server").getString("type"))) ) { 193 | return true; 194 | } else { 195 | return false; 196 | } 197 | 198 | } 199 | 200 | public void checkCollaboratorChanges() { 201 | 202 | if(isCollaboratorChanged()) { 203 | 204 | initializeCurrentCollaboratorVariables(); 205 | 206 | if(!(currentCollaboratorType.equals("none"))) { 207 | 208 | stdout.println("Collaborator location changed! Adding a new collaborator context to the polling thread!"); 209 | collaboratorContext = callbacks.createBurpCollaboratorClientContext(); 210 | interactionServer.addNewCollaboratorContext(collaboratorContext); 211 | 212 | } else { 213 | collaboratorContext = null; 214 | stdout.println("Collaborator disabled!"); 215 | 216 | } 217 | 218 | } 219 | 220 | } 221 | 222 | public void actionPerformed(ActionEvent event) { 223 | 224 | String command = event.getActionCommand(); 225 | 226 | if(command.equals("enableDisablePolling")) { 227 | 228 | if(enablePolling.isSelected()) { 229 | 230 | interactionServer.resumeThread(); 231 | 232 | } else { 233 | 234 | interactionServer.pause(); 235 | 236 | } 237 | 238 | } else if(command.equals("contextInsertCollaboratorPayload") || command.equals("contextInsertCollaboratorInsertionPoint")) { 239 | 240 | // DEBUG 241 | //String collaboratorOption = callbacks.saveConfigAsJson("project_options.misc.collaborator_server"); 242 | //stdout.println(collaboratorOption); 243 | 244 | checkCollaboratorChanges(); 245 | 246 | IHttpRequestResponse[] selectedItems = currentInvocation.getSelectedMessages(); 247 | int[] selectedBounds = currentInvocation.getSelectionBounds(); 248 | byte selectedInvocationContext = currentInvocation.getInvocationContext(); 249 | 250 | byte[] selectedRequestOrResponse = null; 251 | if(selectedInvocationContext == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST) { 252 | selectedRequestOrResponse = selectedItems[0].getRequest(); 253 | } else { 254 | selectedRequestOrResponse = selectedItems[0].getResponse(); 255 | } 256 | 257 | // It works if something is selected and if is not 258 | byte[] preSelectedPortion = Arrays.copyOfRange(selectedRequestOrResponse, 0, selectedBounds[0]); 259 | byte[] postSelectedPortion = Arrays.copyOfRange(selectedRequestOrResponse, selectedBounds[1], selectedRequestOrResponse.length); 260 | 261 | String currentCollaboratorPayload = ""; 262 | 263 | if(collaboratorContext == null) { 264 | currentCollaboratorPayload = "THE_COLLABORATOR_IS_DISABLED"; 265 | } else if(command.equals("contextInsertCollaboratorPayload")) { 266 | currentCollaboratorPayload = collaboratorContext.generatePayload(true); 267 | } else { 268 | currentCollaboratorPayload = collaboratorInsertionPointString; 269 | } 270 | //stdout.println(currentCollaboratorPayload); 271 | 272 | byte[] newRequestResponseBytes = ArrayUtils.addAll(preSelectedPortion, helpers.stringToBytes(currentCollaboratorPayload)); 273 | newRequestResponseBytes = ArrayUtils.addAll(newRequestResponseBytes, postSelectedPortion); 274 | 275 | if(selectedInvocationContext == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST) { 276 | selectedItems[0].setRequest(newRequestResponseBytes); 277 | } else { 278 | selectedItems[0].setResponse(newRequestResponseBytes); 279 | } 280 | 281 | // Add request/response to processed requests/responses 282 | if(command.equals("contextInsertCollaboratorPayload")) { 283 | processedRequestResponse.put(currentCollaboratorPayload, callbacks.saveBuffersToTempFiles(selectedItems[0])); 284 | } 285 | 286 | } 287 | 288 | } 289 | 290 | public void extensionUnloaded() { 291 | 292 | stdout.println("Stopping thread of Collaborator interaction server"); 293 | interactionServer.setGoOn(false); 294 | 295 | } 296 | 297 | private void replaceInsertionPointWithPayload(IHttpRequestResponse messageInfo, boolean request) { 298 | 299 | checkCollaboratorChanges(); 300 | 301 | if(collaboratorContext != null) { 302 | 303 | String requestResponse = ""; 304 | 305 | if(request){ 306 | byte[] requestByte = messageInfo.getRequest(); 307 | requestResponse = new String(requestByte); 308 | } else { 309 | byte[] responseByte = messageInfo.getResponse(); 310 | requestResponse = new String(responseByte); 311 | } 312 | 313 | // Count occurences of insertion point string in request/response 314 | int lastIndex = 0; 315 | int count = 0; 316 | while(lastIndex != -1){ 317 | 318 | lastIndex = requestResponse.indexOf(collaboratorInsertionPointString,lastIndex); 319 | 320 | if(lastIndex != -1){ 321 | count ++; 322 | lastIndex += collaboratorInsertionPointString.length(); 323 | } 324 | } 325 | 326 | // Replace all the occurrences with a Collaborator payload 327 | String[] collaboratorPayloads = new String[count]; 328 | for(int i=0; i