class BurpExtender(IBurpExtender, ITab): def registerExtenderCallbacks(self, callbacks): print "Loading..." self._callbacks = callbacks self._callbacks.setExtensionName('Burp SSL Scanner') # self._callbacks.registerScannerCheck(self) # self._callbacks.registerExtensionStateListener(self) self._helpers = callbacks.getHelpers() # initialize the main scanning event and thread self.scanningEvent = Event() self.scannerThread = None self.targetURL = None # main split pane self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setBorder(EmptyBorder(20, 20, 20, 20)) # sub split pane (top) self._topPanel = JPanel(BorderLayout(10, 10)) self._topPanel.setBorder(EmptyBorder(0, 0, 10, 0)) # Setup Panel : [Target: ] [______________________] [START BUTTON] self.setupPanel = JPanel(FlowLayout(FlowLayout.LEADING, 10, 10)) self.setupPanel.add( JLabel("Target:", SwingConstants.LEFT), BorderLayout.LINE_START) self.hostField = JTextField('', 50) self.setupPanel.add(self.hostField) self.toggleButton = JButton( 'Start scanning', actionPerformed=self.startScan) self.setupPanel.add(self.toggleButton) if 'Professional' in callbacks.getBurpVersion()[0] : self.addToSitemapCheckbox = JCheckBox('Add to sitemap', True) else : self.addToSitemapCheckbox = JCheckBox('Add to sitemap (requires Professional version)', False) self.addToSitemapCheckbox.setEnabled(False) self.setupPanel.add(self.addToSitemapCheckbox) self.scanSiteMapHostCheckbox = JCheckBox('Scan sitemap hosts', True) self.setupPanel.add(self.scanSiteMapHostCheckbox) self._topPanel.add(self.setupPanel, BorderLayout.PAGE_START) # Status bar self.scanStatusPanel = JPanel(FlowLayout(FlowLayout.LEADING, 10, 10)) self.scanStatusPanel.add(JLabel("Status: ", SwingConstants.LEFT)) self.scanStatusLabel = JLabel("Ready to scan", SwingConstants.LEFT) self.scanStatusPanel.add(self.scanStatusLabel) self._topPanel.add(self.scanStatusPanel, BorderLayout.LINE_START) self._splitpane.setTopComponent(self._topPanel) # bottom panel self._bottomPanel = JPanel(BorderLayout(10, 10)) self._bottomPanel.setBorder(EmptyBorder(10, 0, 0, 0)) self.initialText = ('<h1 style="color: red;">Burp SSL Scanner<br />' 'Please note that TLS1.3 is still not supported by this extension.</h1>') self.currentText = self.initialText self.textPane = JTextPane() self.textScrollPane = JScrollPane(self.textPane) self.textPane.setContentType("text/html") self.textPane.setText(self.currentText) self.textPane.setEditable(False) self._bottomPanel.add(self.textScrollPane, BorderLayout.CENTER) self.savePanel = JPanel(FlowLayout(FlowLayout.LEADING, 10, 10)) self.saveButton = JButton('Save to file', actionPerformed=self.saveToFile) self.saveButton.setEnabled(False) self.savePanel.add(self.saveButton) self.clearScannedHostButton = JButton('Clear scanned host', actionPerformed=self.clearScannedHost) self.savePanel.add(self.clearScannedHostButton) self.savePanel.add(JLabel("Clear hosts that were scanned by active scan to enable rescanning", SwingConstants.LEFT)) self._bottomPanel.add(self.savePanel, BorderLayout.PAGE_END) self._splitpane.setBottomComponent(self._bottomPanel) callbacks.customizeUiComponent(self._splitpane) callbacks.addSuiteTab(self) print "SSL Scanner tab loaded" self.scannerMenu = ScannerMenu(self) callbacks.registerContextMenuFactory(self.scannerMenu) print "SSL Scanner custom menu loaded" self.scannerCheck = ScannerCheck(self, self.scanSiteMapHostCheckbox.isSelected) callbacks.registerScannerCheck(self.scannerCheck) print "SSL Scanner check registered" projectConfig = json.loads(self._callbacks.saveConfigAsJson()) scanAccuracy = projectConfig['scanner']['active_scanning_optimization']['scan_accuracy'] scanSpeed = projectConfig['scanner']['active_scanning_optimization']['scan_speed'] print(scanAccuracy, scanSpeed) self.scannedHost = [] print 'SSL Scanner loaded' def startScan(self, ev) : host = self.hostField.text self.scanningEvent.set() if(len(host) == 0): return if host.find("://") == -1: host = "https://" + host try: self.targetURL = URL(host) if(self.targetURL.getPort() == -1): self.targetURL = URL("https", self.targetURL.getHost(), 443, "/") self.hostField.setEnabled(False) self.toggleButton.setEnabled(False) self.saveButton.setEnabled(False) self.addToSitemapCheckbox.setEnabled(False) self.currentText = self.initialText self.textPane.setText(self.currentText) self.updateText("<h2>Scanning %s:%d</h2>" % (self.targetURL.getHost(), self.targetURL.getPort())) print("Scanning %s:%d" % (self.targetURL.getHost(), self.targetURL.getPort())) self.scannerThread = Thread(target=self.scan, args=(self.targetURL, )) self.scannerThread.start() except BaseException as e: self.saveButton.setEnabled(False) print(e) return def scan(self, url, usingBurpScanner=False): def setScanStatusLabel(text) : if not usingBurpScanner : SwingUtilities.invokeLater( ScannerRunnable(self.scanStatusLabel.setText, (text,))) def updateResultText(text) : if not usingBurpScanner : SwingUtilities.invokeLater( ScannerRunnable(self.updateText, (text, ))) if usingBurpScanner : res = result.Result(url, self._callbacks, self._helpers, False) else : res = result.Result(url, self._callbacks, self._helpers, self.addToSitemapCheckbox.isSelected()) host, port = url.getHost(), url.getPort() ### Get project configuration projectConfig = json.loads(self._callbacks.saveConfigAsJson()) if 'scanner' in projectConfig: # scanAccuracy: minimise_false_negatives, normal, minimise_false_positives scanAccuracy = projectConfig['scanner']['active_scanning_optimization']['scan_accuracy'] # scanSpeed: fast, normal, thorough scanSpeed = projectConfig['scanner']['active_scanning_optimization']['scan_speed'] else: scanAccuracy = 'normal' scanSpeed = 'normal' updateResultText('<h2>Scanning speed: %s</h2> %s' % (scanSpeed, test_details.SCANNING_SPEED_INFO[scanSpeed])) updateResultText('<h2>Scanning accuracy: %s</h2> %s' % (scanAccuracy, test_details.SCANNING_ACCURACY_INFO[scanAccuracy])) try : setScanStatusLabel("Checking for supported SSL/TLS versions") con = connection_test.ConnectionTest(res, host, port, scanSpeed, scanAccuracy) con.start() conResultText = '<hr /><br /><h3>' + res.printResult('connectable') + '</h3>' + \ '<ul><li>' + res.printResult('offer_ssl2') + '</li>' + \ '<li>' + res.printResult('offer_ssl3') + '</li>' + \ '<li>' + res.printResult('offer_tls10') + '</li>' + \ '<li>' + res.printResult('offer_tls11') + '</li>' + \ '<li>' + res.printResult('offer_tls12') + '</li></ul>' updateResultText(conResultText) if not res.getResult('connectable') : updateResultText("<h2>Scan terminated (Connection failed)</h2>") raise BaseException('Connection failed') setScanStatusLabel("Checking for supported cipher suites (This can take a long time)") supportedCipher = supportedCipher_test.SupportedCipherTest(res, host, port, scanSpeed, scanAccuracy) supportedCipher.start() setScanStatusLabel("Checking for Cipherlist") cipher = cipher_test.CipherTest(res, host, port, scanSpeed, scanAccuracy) cipher.start() cipherResultText = '<h3>Available ciphers:</h3>' + \ '<ul><li>' + res.printResult('cipher_NULL') + '</li>' + \ '<li>' + res.printResult('cipher_ANON') + '</li>' + \ '<li>' + res.printResult('cipher_EXP') + '</li>' + \ '<li>' + res.printResult('cipher_LOW') + '</li>' + \ '<li>' + res.printResult('cipher_WEAK') + '</li>' + \ '<li>' + res.printResult('cipher_3DES') + '</li>' + \ '<li>' + res.printResult('cipher_HIGH') + '</li>' + \ '<li>' + res.printResult('cipher_STRONG') + '</li></ul>' updateResultText(cipherResultText) setScanStatusLabel("Checking for Heartbleed") heartbleed = heartbleed_test.HeartbleedTest(res, host, port, scanSpeed, scanAccuracy) heartbleed.start() heartbleedResultText = res.printResult('heartbleed') updateResultText(heartbleedResultText) setScanStatusLabel("Checking for CCS Injection") ccs = ccs_test.CCSTest(res, host, port, scanSpeed, scanAccuracy) ccs.start() ccsResultText = res.printResult('ccs_injection') updateResultText(ccsResultText) setScanStatusLabel("Checking for TLS_FALLBACK_SCSV") fallback = fallback_test.FallbackTest(res, host, port, scanSpeed, scanAccuracy) fallback.start() fallbackResultText = res.printResult('fallback_support') updateResultText(fallbackResultText) setScanStatusLabel("Checking for POODLE (SSLv3)") poodle = poodle_test.PoodleTest(res, host, port, scanSpeed, scanAccuracy) poodle.start() poodleResultText = res.printResult('poodle_ssl3') updateResultText(poodleResultText) setScanStatusLabel("Checking for SWEET32") sweet32 = sweet32_test.Sweet32Test(res, host, port, scanSpeed, scanAccuracy) sweet32.start() sweet32ResultText = res.printResult('sweet32') updateResultText(sweet32ResultText) setScanStatusLabel("Checking for DROWN") drown = drown_test.DrownTest(res, host, port, scanSpeed, scanAccuracy) drown.start() drownResultText = res.printResult('drown') updateResultText(drownResultText) setScanStatusLabel("Checking for FREAK") freak = freak_test.FreakTest(res, host, port, scanSpeed, scanAccuracy) freak.start() freakResultText = res.printResult('freak') updateResultText(freakResultText) setScanStatusLabel("Checking for LUCKY13") lucky13 = lucky13_test.Lucky13Test(res, host, port, scanSpeed, scanAccuracy) lucky13.start() lucky13ResultText = res.printResult('lucky13') updateResultText(lucky13ResultText) setScanStatusLabel("Checking for CRIME") crime = crime_test.CrimeTest(res, host, port, scanSpeed, scanAccuracy) crime.start() crimeResultText = res.printResult('crime_tls') updateResultText(crimeResultText) setScanStatusLabel("Checking for BREACH") breach = breach_test.BreachTest(res, host, port, scanSpeed, scanAccuracy) breach.start(self._callbacks, self._helpers) breachResultText = res.printResult('breach') updateResultText(breachResultText) setScanStatusLabel("Checking for BEAST") beast = beast_test.BeastTest(res, host, port, scanSpeed, scanAccuracy) beast.start() beastResultText = res.printResult('beast') updateResultText(beastResultText) setScanStatusLabel("Checking for LOGJAM") logjam = logjam_test.LogjamTest(res, host, port, scanSpeed, scanAccuracy) logjam.start() logjamResultText = res.printResult('logjam_export') + '<br />' + res.printResult('logjam_common') updateResultText(logjamResultText) updateResultText('<h2>Finished scanning</h2><br /><hr /><br /><h2>Summary</h2>') updateResultText('<h2>Supported ciphers (by Protocol)</h2>') updateResultText(res.printCipherList()) updateResultText('<h2>Supported ciphers (by Vulnerability)</h2>') updateResultText(res.printCipherListByVulns()) updateResultText('<h2>Issues found</h2>') updateResultText(res.printAllIssue()) except BaseException as e : print(e) setScanStatusLabel("An error occurred. Please refer to the output/errors tab for more information.") time.sleep(2) if usingBurpScanner : return res.getAllIssue() else : self.scanningEvent.clear() SwingUtilities.invokeLater( ScannerRunnable(self.toggleButton.setEnabled, (True, )) ) SwingUtilities.invokeLater( ScannerRunnable(self.hostField.setEnabled, (True, )) ) SwingUtilities.invokeLater( ScannerRunnable(self.saveButton.setEnabled, (True, )) ) if 'Professional' in self._callbacks.getBurpVersion()[0] : SwingUtilities.invokeLater( ScannerRunnable(self.addToSitemapCheckbox.setEnabled, (True, )) ) setScanStatusLabel("Ready to scan") print("Finished scanning") def updateText(self, stringToAppend): self.currentText += ('<br />' + stringToAppend) self.textPane.setText(self.currentText) def saveToFile(self, event): fileChooser = JFileChooser() if not (self.targetURL is None): fileChooser.setSelectedFile(File("Burp_SSL_Scanner_Result_%s.html" \ % (self.targetURL.getHost()))) else: fileChooser.setSelectedFile(File("Burp_SSL_Scanner_Result.html")) if (fileChooser.showSaveDialog(self.getUiComponent()) == JFileChooser.APPROVE_OPTION): fw = FileWriter(fileChooser.getSelectedFile()) fw.write(self.textPane.getText()) fw.flush() fw.close() print "Saved results to disk" def clearScannedHost(self, event) : self.scannedHost = [] def addHostToScannedList(self, host, port) : self.scannedHost.append([host, port]) def getTabCaption(self): return "SSL Scanner" def getUiComponent(self): return self._splitpane
class BurpExtender(IBurpExtender, ITab): def registerExtenderCallbacks(self, callbacks): print "Loading..." self._callbacks = callbacks self._callbacks.setExtensionName('Burp SPA Explorer') # self._callbacks.registerScannerCheck(self) # self._callbacks.registerExtensionStateListener(self) self._helpers = callbacks.getHelpers() self.crawlingEvent = Event() self.crawlerThread = None # main split pane self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setBorder(EmptyBorder(20, 20, 20, 20)) # sub split pane (top) self._topPanel = JPanel(BorderLayout(10, 10)) self._topPanel.setBorder(EmptyBorder(0, 0, 10, 0)) # Setup Panel : [Target: ] [______________________] [START BUTTON] self.setupPanel = JPanel(FlowLayout(FlowLayout.LEADING, 10, 10)) self.setupPanel.add(JLabel("Target:", SwingConstants.LEFT), BorderLayout.LINE_START) self.hostField = JTextField('', 50) self.setupPanel.add(self.hostField) self.toggleButton = JButton('Start crawling', actionPerformed=self.toggleCrawl) self.setupPanel.add(self.toggleButton) self._topPanel.add(self.setupPanel, BorderLayout.PAGE_START) # Options Panel : [Buttons] [ RegEx ] self.optionsPanel = JPanel() self.optionsPanel.setLayout( BoxLayout(self.optionsPanel, BoxLayout.LINE_AXIS)) # Button options panel : [Add][Edit][Up][Down][Remove] self.buttonOptionsPanel = JPanel() self.buttonOptionsPanel.setLayout( BoxLayout(self.buttonOptionsPanel, BoxLayout.PAGE_AXIS)) self.addRegexButton = JButton('Add', actionPerformed=self.addRegex) self.buttonOptionsPanel.add(self.addRegexButton) self.editRegexButton = JButton('Edit', actionPerformed=self.editRegex) self.buttonOptionsPanel.add(self.editRegexButton) self.moveRegexUpButton = JButton('Move up', actionPerformed=self.moveRegexUp) self.buttonOptionsPanel.add(self.moveRegexUpButton) self.moveRegexDownButton = JButton('Move down', actionPerformed=self.moveRegexDown) self.buttonOptionsPanel.add(self.moveRegexDownButton) self.removeRegexButton = JButton('Remove', actionPerformed=self.removeRegex) self.buttonOptionsPanel.add(self.removeRegexButton) self.buttonOptionsPanel.add(Box.createVerticalGlue()) self.optionsPanel.add(self.buttonOptionsPanel) self.optionsPanel.add(Box.createHorizontalStrut(20)) self.regexTableModel = RegexTableModel([x for x in regex]) self.regexTable = Table(self.regexTableModel) self.regexScrollPane = JScrollPane(self.regexTable) self.optionsPanel.add(self.regexScrollPane) self._topPanel.add(self.optionsPanel, BorderLayout.CENTER) self._splitpane.setTopComponent(self._topPanel) # Bottom Panel self._bottomPanel = JPanel(BorderLayout(10, 10)) #self._bottomPanel.setLayout(BoxLayout(self._bottomPanel,BoxLayout.PAGE_AXIS)) # Status bar self.crawlStatusPanel = JPanel(FlowLayout(FlowLayout.LEADING, 10, 10)) self.crawlStatusPanel.add(JLabel("Status: ", SwingConstants.LEFT)) self.crawlStatusLabel = JLabel("Ready to crawl", SwingConstants.LEFT) self.crawlStatusPanel.add(self.crawlStatusLabel) # Result Table self.resultTableModel = Result([]) self.resultTable = Table(self.resultTableModel) self.resultTable.setAutoCreateRowSorter(True) self.resultScrollPane = JScrollPane(self.resultTable) # Result Table popup menu def selectWhenRightClickEvent(event): def select(e): rowAtPoint = self.resultTable.rowAtPoint( SwingUtilities.convertPoint(self.resultTablePopupMenu, Point(0, 0), self.resultTable)) if rowAtPoint > -1: self.resultTable.setRowSelectionInterval( rowAtPoint, rowAtPoint) SwingUtilities.invokeLater(CrawlerRunnable(select, (event, ))) self.resultTablePopupMenu = JPopupMenu( popupMenuWillBecomeVisible=selectWhenRightClickEvent) self.resultTablePopupMenu.add( JMenuItem("Send to scanner", actionPerformed=self.sendToScanner)) self.resultTablePopupMenu.add( JMenuItem("Send to repeater", actionPerformed=self.sendToRepeater)) self.resultTablePopupMenu.add( JMenuItem("Send to intruder", actionPerformed=self.sendToIntruder)) self.resultTablePopupMenu.add( JMenuItem("Send to spider", actionPerformed=self.sendToSpider)) self.resultTable.setComponentPopupMenu(self.resultTablePopupMenu) self._bottomPanel.add(self.resultScrollPane, BorderLayout.CENTER) self._bottomPanel.add(self.crawlStatusPanel, BorderLayout.SOUTH) self._splitpane.setBottomComponent(self._bottomPanel) self._splitpane.setDividerLocation(300 + self._splitpane.getInsets().left) callbacks.customizeUiComponent(self._splitpane) callbacks.addSuiteTab(self) explorerMenu = ExplorerMenu(self) callbacks.registerContextMenuFactory(explorerMenu) print "SPA Explorer custom menu loaded" #print "Loading chrome driver" #a = Test(os.path.dirname(os.path.realpath('selenium-client.jar')) + '/chromedriver.exe') #print "Chrome driver started" print "Burp SPA Explorer loaded" # Button Actions def getURLComponents(self, url): return (url.getHost(), (443 if url.getProtocol() == 'https' else 80) if url.getPort() == -1 else url.getPort(), url.getProtocol() == 'https') def sendToScanner(self, event): url = URL( self.resultTable.getValueAt(self.resultTable.getSelectedRow(), 1)) urlComp = self.getURLComponents(url) self._callbacks.doActiveScan(urlComp[0], urlComp[1], urlComp[2], self._helpers.buildHttpRequest(url)) def sendToRepeater(self, event): url = URL( self.resultTable.getValueAt(self.resultTable.getSelectedRow(), 1)) urlComp = self.getURLComponents(url) self._callbacks.sendToRepeater(urlComp[0], urlComp[1], urlComp[2], self._helpers.buildHttpRequest(url), None) def sendToIntruder(self, event): url = URL( self.resultTable.getValueAt(self.resultTable.getSelectedRow(), 1)) urlComp = self.getURLComponents(url) self._callbacks.sendToIntruder(urlComp[0], urlComp[1], urlComp[2], self._helpers.buildHttpRequest(url)) def sendToSpider(self, event): url = URL( self.resultTable.getValueAt(self.resultTable.getSelectedRow(), 1)) self._callbacks.sendToSpider(url) def addRegex(self, event): optionPane = JOptionPane() dialog = optionPane.createDialog(self._splitpane, "Add RegEx") panel = JPanel(GridLayout(0, 2)) panel.setBorder(EmptyBorder(10, 10, 10, 10)) nameField = JTextField('', 15) panel.add(JLabel("Name:", SwingConstants.LEFT)) panel.add(nameField) regexField = JTextField('', 15) panel.add(JLabel("RegEx:", SwingConstants.LEFT)) panel.add(regexField) crawlField = JCheckBox() panel.add(JLabel("Crawl:", SwingConstants.LEFT)) panel.add(crawlField) def closeDialog(event): if len(nameField.text) == 0 or len(regexField.text) == 0: JOptionPane.showMessageDialog(self._splitpane, "Name or RegEx can't be empty", "Error", JOptionPane.ERROR_MESSAGE) return self.regexTableModel.addRow( [nameField.text, regexField.text, crawlField.isSelected()]) dialog.hide() addButton = JButton('OK', actionPerformed=closeDialog) panel.add(addButton) dialog.setSize(600, 200) dialog.setContentPane(panel) self._callbacks.customizeUiComponent(dialog) dialog.show() return True def editRegex(self, event): selectedRowIdx = self.regexTable.getSelectedRow() if selectedRowIdx == -1: return False selectedRow = self.regexTableModel.data[selectedRowIdx] optionPane = JOptionPane() dialog = optionPane.createDialog(self._splitpane, "Edit RegEx") panel = JPanel(GridLayout(0, 2)) panel.setBorder(EmptyBorder(10, 10, 10, 10)) nameField = JTextField('', 15) nameField.text = selectedRow[0] panel.add(JLabel("Name:", SwingConstants.LEFT)) panel.add(nameField) regexField = JTextField('', 15) regexField.text = selectedRow[1] panel.add(JLabel("RegEx:", SwingConstants.LEFT)) panel.add(regexField) crawlField = JCheckBox() crawlField.setSelected(selectedRow[2]) panel.add(JLabel("Crawl:", SwingConstants.LEFT)) panel.add(crawlField) def closeDialog(event): if len(nameField.text) == 0 or len(regexField.text) == 0: JOptionPane.showMessageDialog(self._splitpane, "Name or RegEx can't be empty", "Error", JOptionPane.ERROR_MESSAGE) return self.regexTableModel.editRow( selectedRowIdx, [nameField.text, regexField.text, crawlField.isSelected()]) dialog.hide() editButton = JButton('OK', actionPerformed=closeDialog) panel.add(editButton) dialog.setSize(600, 200) dialog.setContentPane(panel) self._callbacks.customizeUiComponent(dialog) dialog.show() return True def moveRegexDown(self, event): idxs = self.regexTable.getSelectedRows() if self.regexTableModel.getRowCount() - 1 in idxs: return False self.regexTable.clearSelection() for i in sorted(idxs)[::-1]: self.regexTableModel.moveDown(i) self.regexTable.addRowSelectionInterval(i + 1, i + 1) return True def moveRegexUp(self, event): idxs = self.regexTable.getSelectedRows() if 0 in idxs: return False self.regexTable.clearSelection() for i in sorted(idxs): self.regexTableModel.moveUp(i) self.regexTable.addRowSelectionInterval(i - 1, i - 1) return True def removeRegex(self, event): idx = self.regexTable.getSelectedRows() for i in sorted(idx)[::-1]: self.regexTableModel.removeRow(i) return True # Implement ITab def getTabCaption(self): return "SPA Explorer" def getUiComponent(self): return self._splitpane def crawl(self, event): print("Starting") host = self.hostField.text if host.find("://") == -1: host = "http://" + host try: self._callbacks.includeInScope(URL(host)) except: JOptionPane.showMessageDialog(self._splitpane, "Can't add host to scope", "Error", JOptionPane.ERROR_MESSAGE) return self.resultTableModel.clearAllRow() self.crawlingEvent.set() self.crawlerThread = Thread(target=self.crawl_thread, args=(host, )) self.crawlerThread.start() print("Started") def stopCrawling(self, event): print("Clear event") self.crawlingEvent.clear() # Disable button if self.toggleButton.text == "Stop crawling": # If button is still "Stop crawling" (Thread still running), disable button self.toggleButton.setEnabled(False) def toggleCrawl(self, event): if (self.crawlerThread == None or not self.crawlerThread.is_alive()): self.crawl(event) #self.toggleButton.setText("Start crawling") else: self.stopCrawling(event) #self.toggleButton.setText("Stop crawling") def crawl_thread(self, host): # print(self, host) print("Crawl thread started") SwingUtilities.invokeLater( CrawlerRunnable(self.toggleButton.setText, ("Stop crawling", ))) SwingUtilities.invokeLater( CrawlerRunnable(self.addRegexButton.setEnabled, (False, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.editRegexButton.setEnabled, (False, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.moveRegexUpButton.setEnabled, (False, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.moveRegexDownButton.setEnabled, (False, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.removeRegexButton.setEnabled, (False, ))) pageType = {} # url -> type pageContentHash = {} # hash -> url list def concatURL(baseURL, link): return URL(URL(baseURL), link).toString() def makeRequest(url): url = URL(url) if not self._callbacks.isInScope(url): #self.logger.addRow(url.toString()+" is out of scope") raise ValueError("URL is out of scope") prot = url.getProtocol() host = url.getHost() port = url.getPort() if port == -1: port = 80 if prot == "http" else 443 httpService = self._helpers.buildHttpService(host, port, prot) reqRes = self._callbacks.makeHttpRequest( httpService, self._helpers.buildHttpRequest(url)) self._callbacks.addToSiteMap(reqRes) resp = reqRes.getResponse() respInfo = self._helpers.analyzeResponse(resp) respBody = self._helpers.bytesToString( resp[respInfo.getBodyOffset():]) return respBody def matchRegex(baseURL, res): toRet = [] for (name, regStr, ret) in self.regexTableModel.data: matchObj = re.findall(regStr, res, re.M | re.I) for i in matchObj: try: if i.find('http://') == 0 or i.find('https://') == 0: url = i elif i[0] == '/': url = host + i else: url = host + '/' + i if url not in pageType: pageType[url] = name SwingUtilities.invokeLater( CrawlerRunnable(self.resultTableModel.addRow, ([name, url], ))) if ret: toRet.append(url) except: print("Error when trying to save result ", i, sys.exc_info()[0], sys.exc_info()[1]) return toRet def getAllLink(url): toRet = [] try: print("Making request", url) r = makeRequest(url) print("Done request", len(r)) hash = hashlib.sha256(r.encode('utf-8')).hexdigest() #print(r.text) if hash in pageContentHash: print("Content hash is the same as ", pageContentHash[hash][0]) pageContentHash[hash].append(url) return toRet else: pageContentHash[hash] = [url] toRet += matchRegex(url, r) except BaseException as e: print("Error while making request to ", url, e) except: print("Error while making request to ", url, sys.exc_info()[0], sys.exc_info()[1]) return toRet crawledPage = [host] crawledNow = 0 SwingUtilities.invokeLater( CrawlerRunnable(self.resultTableModel.addRow, (["TARGET", host], ))) while crawledNow < len(crawledPage): if self.crawlingEvent.is_set(): print("Crawling", crawledPage[crawledNow]) SwingUtilities.invokeLater( CrawlerRunnable(self.crawlStatusLabel.setText, ("Crawling " + crawledPage[crawledNow], ))) for i in getAllLink(crawledPage[crawledNow]): if i not in crawledPage: print("ADD:", i) crawledPage.append(i) crawledNow += 1 else: print("Stop Requested") break print(crawledNow, crawledPage) output = [] SwingUtilities.invokeLater( CrawlerRunnable(self.toggleButton.setText, ("Start crawling", ))) SwingUtilities.invokeLater( CrawlerRunnable(self.toggleButton.setEnabled, (True, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.addRegexButton.setEnabled, (True, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.editRegexButton.setEnabled, (True, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.moveRegexUpButton.setEnabled, (True, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.moveRegexDownButton.setEnabled, (True, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.removeRegexButton.setEnabled, (True, ))) SwingUtilities.invokeLater( CrawlerRunnable(self.crawlStatusLabel.setText, ("Ready to crawl", ))) self.crawlingEvent.clear() print("Completed")
class BurpExtender(IBurpExtender, ITab, IExtensionStateListener): # Define the global variables for the burp plugin EXTENSION_NAME = "UPnP BHunter" ipv4_selected = True services_dict = {} ip_service_dict = {} STOP_THREAD = False #Some SSDP m-search parameters are based upon "UPnP Device Architecture v2.0" SSDP_MULTICAST_IPv4 = ["239.255.255.250"] SSDP_MULTICAST_IPv6 = ["FF02::C", "FF05::C"] SSDP_MULTICAST_PORT = 1900 ST_ALL = "ssdp:all" ST_ROOTDEV = "upnp:rootdevice" PLACEHOLDER = "FUZZ_HERE" SSDP_TIMEOUT = 2 def registerExtenderCallbacks(self, callbacks): # Get a reference to callbacks object self.callbacks = callbacks # Get the useful extension helpers object self.helpers = callbacks.getHelpers() # Set the extension name self.callbacks.setExtensionName(self.EXTENSION_NAME) self.callbacks.registerExtensionStateListener(self) # Draw plugin user interface self.drawPluginUI() self.callbacks.addSuiteTab(self) # Plugin loading message print("[+] Burp plugin UPnP BHunter loaded successfully") return def drawPluginUI(self): # Create the plugin user interface self.pluginTab = JPanel() self.uiTitle = JLabel('UPnP BHunter Load, Aim and Fire Console') self.uiTitle.setFont(Font('Tahoma', Font.BOLD, 14)) self.uiTitle.setForeground(Color(250, 100, 0)) self.uiPanelA = JSplitPane(JSplitPane.VERTICAL_SPLIT) self.uiPanelA.setMaximumSize(Dimension(2500, 1000)) self.uiPanelA.setDividerSize(2) self.uiPanelB = JSplitPane(JSplitPane.VERTICAL_SPLIT) self.uiPanelB.setDividerSize(2) self.uiPanelA.setBottomComponent(self.uiPanelB) self.uiPanelA.setBorder(BorderFactory.createLineBorder(Color.gray)) # Create and configure labels and text fields self.labeltitle_step1 = JLabel("[1st STEP] Discover UPnP Locations") self.labeltitle_step1.setFont(Font('Tahoma', Font.BOLD, 14)) self.labeltitle_step2 = JLabel( "[2nd STEP] Select a UPnP Service and Action") self.labeltitle_step2.setFont(Font('Tahoma', Font.BOLD, 14)) self.labeltitle_step3 = JLabel("[3rd STEP] Time to Attack it") self.labeltitle_step3.setFont(Font('Tahoma', Font.BOLD, 14)) self.labelsubtitle_step1 = JLabel( "Specify the IP version address in scope and start UPnP discovery") self.labelsubtitle_step2 = JLabel( "Select which of the found UPnP services will be probed") self.labelsubtitle_step3 = JLabel( "Review and modify the request, then send it to one of the attack tools" ) self.label_step1 = JLabel("Target IP") self.label_step2 = JLabel("Found UPnp Services") self.labelstatus = JLabel(" Status") self.labelempty_step1 = JLabel(" ") self.labelempty_step2 = JLabel(" ") self.labelupnp = JLabel("UPnP list") self.labelip = JLabel("IP list") self.labelactions = JLabel("Actions") self.labelNoneServiceFound = JLabel(" ") self.labelNoneServiceFound.setFont(Font('Tahoma', Font.BOLD, 12)) self.labelNoneServiceFound.setForeground(Color.red) # Create combobox for IP version selection self.ip_versions = ["IPv4", "IPv6"] self.combo_ipversion = JComboBox(self.ip_versions) self.combo_ipversion.setSelectedIndex(0) self.combo_ipversion.setEnabled(True) # Create and configure progress bar self.progressbar = JProgressBar(0, 100) self.progressbar.setString("Ready") self.progressbar.setStringPainted(True) # Create and configure buttons self.startbutton = JButton("Start Discovery", actionPerformed=self.startHunting) self.clearbutton = JButton("Clear All", actionPerformed=self.clearAll) self.intruderbutton = JButton("Send to Intruder", actionPerformed=self.sendToIntruder) self.repeaterbutton = JButton("Send to Repeater", actionPerformed=self.sendToRepeater) #self.WANrepeaterbutton = JButton("to Repeater", actionPerformed=self.sendWANUPnPToRepeater) self.textarea_request = JTextArea(18, 90) self.intruderbutton.setEnabled(False) self.repeaterbutton.setEnabled(False) # Class neeeded to handle the target combobox in second step panel class TargetComboboxListener(ActionListener): def __init__(self, upnpcombo_targets, upnpcombo_services, ip_service_dict): self.upnpcombo_targets = upnpcombo_targets self.upnpcombo_services = upnpcombo_services self.ip_service_dict = ip_service_dict def actionPerformed(self, event): try: # Update the location url combobox depending on the IP combobox selected_target = self.upnpcombo_targets.getSelectedItem() if self.ip_service_dict and selected_target: self.upnpcombo_services.removeAllItems() for service_url in self.ip_service_dict[ selected_target]: self.upnpcombo_services.addItem(service_url) self.upnpcombo_services.setSelectedIndex(0) except BaseException as e: print("[!] Exception selecting service: \"%s\" ") % e # Class neeeded to handle the service combobox in second step panel class ServiceComboboxListener(ActionListener): def __init__(self, upnpcombo_services, upnpcombo_actions, services_dict): self.upnpcombo_services = upnpcombo_services self.upnpcombo_actions = upnpcombo_actions self.services = services_dict def actionPerformed(self, event): try: # Update the location url combobox depending on the IP combobox selected_service = self.upnpcombo_services.getSelectedItem( ) if self.services and selected_service: self.upnpcombo_actions.removeAllItems() actions = self.services[selected_service] for action in actions: self.upnpcombo_actions.addItem(action) self.upnpcombo_actions.setSelectedIndex(0) except BaseException as e: print("[!] Exception selecting service: \"%s\" ") % e # Class neeeded to handle the action combobox in second step panel class ActionComboboxListener(ActionListener): def __init__(self, upnpcombo_services, upnpcombo_actions, textarea_request, services_dict): self.upnpcombo_services = upnpcombo_services self.upnpcombo_actions = upnpcombo_actions self.textarea_request = textarea_request self.services = services_dict def actionPerformed(self, event): try: # Update the location url combobox depending on the IP combobox selected_action = self.upnpcombo_actions.getSelectedItem() selected_service = self.upnpcombo_services.getSelectedItem( ) if self.services and selected_action: self.textarea_request.setText( self.services[selected_service][selected_action]) except BaseException as e: print("[!] Exception selecting action: \"%s\" ") % e self.upnpactions = [" "] self.upnpcombo_actions = JComboBox(self.upnpactions) self.upnpcombo_actions.setSelectedIndex(0) self.upnpcombo_actions.setEnabled(False) # Create the combo box, select item at index 0 (first item in list) self.upnpservices = [" "] self.upnpcombo_services = JComboBox(self.upnpservices) self.upnpcombo_services.setSelectedIndex(0) self.upnpcombo_services.setEnabled(False) # Create the combo box, select item at index 0 (first item in list) self.upnptargets = [" "] self.upnpcombo_targets = JComboBox(self.upnptargets) self.upnpcombo_targets.setSelectedIndex(0) self.upnpcombo_targets.setEnabled(False) # Set the action listeners for all the comboboxes self.upnpcombo_targets.addActionListener( TargetComboboxListener(self.upnpcombo_targets, self.upnpcombo_services, self.ip_service_dict)) self.upnpcombo_services.addActionListener( ServiceComboboxListener(self.upnpcombo_services, self.upnpcombo_actions, self.services_dict)) self.upnpcombo_actions.addActionListener( ActionComboboxListener(self.upnpcombo_services, self.upnpcombo_actions, self.textarea_request, self.services_dict)) # Configuring first step panel self.panel_step1 = JPanel() self.panel_step1.setPreferredSize(Dimension(2250, 100)) self.panel_step1.setBorder(EmptyBorder(10, 10, 10, 10)) self.panel_step1.setLayout(BorderLayout(15, 15)) self.titlepanel_step1 = JPanel() self.titlepanel_step1.setLayout(BorderLayout()) self.titlepanel_step1.add(self.labeltitle_step1, BorderLayout.NORTH) self.titlepanel_step1.add(self.labelsubtitle_step1) self.targetpanel_step1 = JPanel() self.targetpanel_step1.add(self.label_step1) self.targetpanel_step1.add(self.combo_ipversion) self.targetpanel_step1.add(self.startbutton) self.targetpanel_step1.add(self.clearbutton) self.targetpanel_step1.add(self.labelstatus) self.targetpanel_step1.add(self.progressbar) self.emptypanel_step1 = JPanel() self.emptypanel_step1.setLayout(BorderLayout()) self.emptypanel_step1.add(self.labelempty_step1, BorderLayout.WEST) # Assembling first step panel components self.panel_step1.add(self.titlepanel_step1, BorderLayout.NORTH) self.panel_step1.add(self.targetpanel_step1, BorderLayout.WEST) self.panel_step1.add(self.emptypanel_step1, BorderLayout.SOUTH) self.uiPanelA.setTopComponent(self.panel_step1) # Configure second step panel self.panel_step2 = JPanel() self.panel_step2.setPreferredSize(Dimension(2250, 100)) self.panel_step2.setBorder(EmptyBorder(10, 10, 10, 10)) self.panel_step2.setLayout(BorderLayout(15, 15)) self.titlepanel_step2 = JPanel() self.titlepanel_step2.setLayout(BorderLayout()) self.titlepanel_step2.add(self.labeltitle_step2, BorderLayout.NORTH) self.titlepanel_step2.add(self.labelsubtitle_step2) self.selectpanel_step2 = JPanel() self.selectpanel_step2.add(self.labelip) self.selectpanel_step2.add(self.upnpcombo_targets) self.selectpanel_step2.add(self.labelupnp) self.selectpanel_step2.add(self.upnpcombo_services) self.selectpanel_step2.add(self.labelactions) self.selectpanel_step2.add(self.upnpcombo_actions) self.emptypanel_step2 = JPanel() self.emptypanel_step2.setLayout(BorderLayout()) self.emptypanel_step2.add(self.labelempty_step2, BorderLayout.WEST) self.emptypanel_step2.add(self.labelNoneServiceFound) # Assembling second step panel components self.panel_step2.add(self.titlepanel_step2, BorderLayout.NORTH) self.panel_step2.add(self.selectpanel_step2, BorderLayout.WEST) self.panel_step2.add(self.emptypanel_step2, BorderLayout.SOUTH) self.uiPanelB.setTopComponent(self.panel_step2) # Configuring third step panel self.panel_step3 = JPanel() self.panel_step3.setPreferredSize(Dimension(2250, 100)) self.panel_step3.setBorder(EmptyBorder(10, 10, 10, 10)) self.panel_step3.setLayout(BorderLayout(15, 15)) self.titlepanel_step3 = JPanel() self.titlepanel_step3.setLayout(BorderLayout()) self.titlepanel_step3.add(self.labeltitle_step3, BorderLayout.NORTH) self.titlepanel_step3.add(self.labelsubtitle_step3) self.underpanel_step3 = JPanel() self.underpanel_step3.setLayout(BorderLayout()) self.underpanel_step3.add((JScrollPane(self.textarea_request)), BorderLayout.NORTH) self.actionpanel_step3 = JPanel() self.actionpanel_step3.add(self.intruderbutton) self.actionpanel_step3.add(self.repeaterbutton) self.extrapanel_step3 = JPanel() self.extrapanel_step3.setLayout(BorderLayout()) self.extrapanel_step3.add(self.actionpanel_step3, BorderLayout.WEST) # Assembling thirdd step panel components self.panel_step3.add(self.titlepanel_step3, BorderLayout.NORTH) self.panel_step3.add(self.underpanel_step3, BorderLayout.WEST) self.panel_step3.add(self.extrapanel_step3, BorderLayout.SOUTH) self.uiPanelB.setBottomComponent(self.panel_step3) # Assembling the group of all panels layout = GroupLayout(self.pluginTab) self.pluginTab.setLayout(layout) layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING).addGroup( layout.createSequentialGroup().addGap(10, 10, 10).addGroup( layout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( self.uiTitle).addGap(15, 15, 15).addComponent( self.uiPanelA)).addContainerGap( 26, Short.MAX_VALUE))) layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING).addGroup( layout.createSequentialGroup().addGap(15, 15, 15).addComponent( self.uiTitle).addGap(15, 15, 15).addComponent( self.uiPanelA).addGap(20, 20, 20).addGap(20, 20, 20))) def extensionUnloaded(self): # Unload the plugin, and if running stop the background thread if self.upnpcombo_services.isEnabled(): if self.th.isAlive(): print("[+] Stopping thread %s") % self.th.getName() self.STOP_THREAD = True self.th.join() else: print("Thread %s already dead") % self.th.getName() print("[+] Burp plugin UPnP BHunter successfully unloaded") return def getTabCaption(self): return self.EXTENSION_NAME def getUiComponent(self): return self.pluginTab def clearAll(self, e=None): # Reset all data of the plugin self.services_dict.clear() self.progressbar.setString("Ready") self.progressbar.setValue(0) self.upnpcombo_targets.removeAllItems() self.upnpcombo_targets.setEnabled(False) self.upnpcombo_services.removeAllItems() self.upnpcombo_services.setEnabled(False) self.upnpcombo_actions.removeAllItems() self.upnpcombo_actions.setEnabled(False) self.intruderbutton.setEnabled(False) self.repeaterbutton.setEnabled(False) self.labelNoneServiceFound.setText(" ") self.textarea_request.setText(" ") print("[+] Clearing all data") return def startHunting(self, e=None): # Starting the UPnP hunt def startHunting_run(): # Initialize the internal parameters every time the start-discovery button is clicked self.services_dict.clear() found_loc = [] discovery_files = [] self.labelNoneServiceFound.setText(" ") self.intruderbutton.setEnabled(False) self.repeaterbutton.setEnabled(False) # Then determine if targerting IPv4 or IPv6 adresses if self.combo_ipversion.getSelectedItem() == "IPv4": self.ipv4_selected = True print("[+] Selected IPv4 address scope") else: self.ipv4_selected = False print("[+] Selected IPv6 address scope") # And here finally the hunt could start self.progressbar.setString("Running...") self.progressbar.setValue(20) found_loc = self.discoverUpnpLocations() self.progressbar.setValue(40) discovery_files = self.downloadXMLfiles(found_loc) self.progressbar.setValue(60) self.buildSOAPs(discovery_files) self.progressbar.setValue(80) self.progressbar.setString("Done") self.progressbar.setValue(100) self.updateComboboxList(self.services_dict) # Update the comboboxes list with the discovered UPnPs if (self.services_dict): self.upnpcombo_targets.setEnabled(True) self.upnpcombo_services.setEnabled(True) self.upnpcombo_actions.setEnabled(True) self.intruderbutton.setEnabled(True) self.repeaterbutton.setEnabled(True) if self.STOP_THREAD: return # Start a background thread to run the above nested function in order to prevent the blocking of plugin UI self.th = threading.Thread(target=startHunting_run) #self.th.daemon = True # This does not seem to be useful self.th.setName("th-BHunter") self.th.start() def ssdpReqBuilder(self, ssdp_timeout, st_type, ssdp_ip, ssdp_port): # Builder of the two ssdp msearch request types msearch_req = "M-SEARCH * HTTP/1.1\r\n" \ "HOST: {0}:{1}\r\n" \ "MAN: \"ssdp:discover\"\r\n" \ "MX: {2}\r\n" \ "ST: {3}\r\n" \ "\r\n" \ .format(ssdp_ip, ssdp_port, ssdp_timeout, st_type) return msearch_req def sendMsearch(self, ssdp_req, ssdp_ip, ssdp_port): # Send the ssdp request and retrieve response buf_resp = set() if self.ipv4_selected: print("[+] Creating IPv4 SSDP multicast request") sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) else: print("[+] Creating IPv6 SSDP multicast request") sock = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) sock.setblocking(0) # Sending ssdp requests while len(ssdp_req): # Blocking socket client until the request is completely sent try: sent = sock.sendto(ssdp_req.encode("ASCII"), (ssdp_ip, ssdp_port)) ssdp_req = ssdp_req[sent:] except socket.error, exc: if exc.errno != errno.EAGAIN: print("[E] Got error %s with socket when sending") % exc sock.close() raise exc print("[!] Blocking socket until ", len(ssdp_req), " is sent.") select.select([], [sock], []) continue # Retrieving ssdp responses num_resp = 0 while sock: # Blocking socket until there are ssdp responses to be read or timeout is reached readable, __, __ = select.select([sock], [], [], self.SSDP_TIMEOUT) if not readable: # Timeout reached without receiving any ssdp response if num_resp == 0: print( "[!] Got timeout without receiving any ssdp response.") break else: num_resp = num_resp + 1 # Almost an ssdp response was received if readable[0]: try: data = sock.recv(1024) if data: buf_resp.add(data.decode('ASCII')) except socket.error, exc: print("[E] Got error %s with socket when receiving" ) % exc sock.close() raise exc