def addCenterPane(self, atfAreaView, consoleView): splitPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) splitPane.setTopComponent(atfAreaView) splitPane.setBottomComponent(consoleView) splitPane.setDividerSize(5) self.getContentPane().add(splitPane, BorderLayout.CENTER) # Make console's high remain smaller compared to edit area splitPane.setResizeWeight(0.9)
def addCenterPane(self, atfAreaView, consoleView): splitPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) splitPane.setTopComponent(atfAreaView) splitPane.setBottomComponent(consoleView) splitPane.setDividerSize(5) self.getContentPane().add(splitPane, BorderLayout.CENTER) # Make console's high remain smaller compared to edit area splitPane.setResizeWeight(0.9)
def registerExtenderCallbacks(self, callbacks): # set our extension name callbacks.setExtensionName("Hello world extension") # obtain our output and error streams stdout = PrintWriter(callbacks.getStdout(), True) stderr = PrintWriter(callbacks.getStderr(), True) # write a message to our output stream stdout.println("Hello output") # write a message to our error stream stderr.println("Hello errors") # write a message to the Burp alerts tab callbacks.issueAlert("Hello alerts") #create and populate a jtable: initial_row = [ 'http', 'www.meetup.com', 'PyMNtos-Twin-Cities-Python-User-Group/events/267977020/', '', '', '' ] self.fileTable = JTable(ResourceTableModel(initial_row)) # set up the Tab: self.infoPanel = JPanel() footerPanel = JPanel() footerPanel.add(JLabel("by mcgyver5 ")) self._chooseFileButton = JButton("OPEN Local FILE", actionPerformed=self.fileButtonClick) self.infoPanel.add(JLabel("INFORMATION PANE")) self.infoPanel.add(self._chooseFileButton) scrollpane = JScrollPane(self.fileTable) ## this is a split inside the top component topPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) topPane.setTopComponent(self.infoPanel) topPane.setBottomComponent(scrollpane) self._chooseFileButton.setEnabled(True) self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setTopComponent(topPane) self._splitpane.setBottomComponent(footerPanel) callbacks.addSuiteTab(self)
def registerExtenderCallbacks(self, callbacks): # set our extension name callbacks.setExtensionName("War Story") # obtain our output stream self._stdout = PrintWriter(callbacks.getStdout(), True) # write a message to our output stream self._stdout.println("Loading WarStory") # write a message to the Burp alerts tab callbacks.issueAlert("Hello alerts") label = JLabel("INFO PANEL") self.infoPanel = JPanel() footerPanel = JPanel() footerPanel.add(JLabel("by Tim mcgyver5 McGuire")) self._chooseFileButton = JButton("OPEN WAR FILE", actionPerformed=self.fileButtonClick) self.infoPanel.add(JLabel("THIS IS INFORMATION PANE")) self.infoPanel.add(self._chooseFileButton) # iaap.war|web.xml|axServlet|/skuppy/axservlet.do| self._chooseFileButton.setEnabled(True) initial_row = ['a', 'bb', 'ccc', 'ddd', 'eeee'] self.fileTable = JTable(ResourceTableModel(initial_row)) scrollpane = JScrollPane(self.fileTable) ## this is a split inside the top component topPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) topPane.setTopComponent(self.infoPanel) topPane.setBottomComponent(scrollpane) # split the top panel into a Panel and a JScrollPane self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setTopComponent(topPane) self._splitpane.setBottomComponent(footerPanel) callbacks.addSuiteTab(self)
def registerExtenderCallbacks(self, callbacks): # set our extension name callbacks.setExtensionName("CT Search") callbacks.registerContextMenuFactory(self) # obtain output stream self._stdout = PrintWriter(callbacks.getStdout(), True) stdout = PrintWriter(callbacks.getStdout(), True) # write a message to our output stream self._callbacks = callbacks # write a message to the Burp alerts tab callbacks.issueAlert("Hello alerts") #create and populate a jtable: initial_row = ['a', 'DOMAINS', True] self.fileTable = JTable(ResourceTableModel()) # set up the Tab: self.infoPanel = JPanel() footerPanel = JPanel() footerPanel.add(JLabel("by mcgyver5 ")) # self._chooseFileButton = JButton("OPEN Local FILE", actionPerformed=self.fileButtonClick) self.infoPanel.add(JLabel("INFORMATION PANE")) # self.infoPanel.add(self._chooseFileButton) scrollpane = JScrollPane(self.fileTable) ## this is a split inside the top component topPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) topPane.setTopComponent(self.infoPanel) topPane.setBottomComponent(scrollpane) #self._chooseFileButton.setEnabled(True) self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setTopComponent(topPane) self._splitpane.setBottomComponent(footerPanel)
def getUiComponent(self): self.domainTable = JTable(ResourceTableModel()) self.domainTable.setRowHeight(30) #Delete: #jcolumnModel = self.domainTable.getColumnModel() splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) topPane = JPanel() image_label = HelpLabel(self.callbacks) image_label.setHelpIcon("nothing") image_label.addMouseListener(ScreenMouseListener(self.callbacks)) scope_button = JButton("Add Selected Domains To Scope", actionPerformed=self.addToScope) dns_button = JButton("Resolve DNS", actionPerformed=self.resolveDns) # search_text = JTextField("") saveButton = JButton("Save results", actionPerformed=self.saveResults) topPane.add(image_label) topPane.add(scope_button) topPane.add(dns_button) topPane.add(saveButton) scrollpane = JScrollPane(self.domainTable) splitpane.setTopComponent(topPane) splitpane.setBottomComponent(scrollpane) return splitpane
class BurpExtender(IBurpExtender, ITab, IContextMenuFactory): def registerExtenderCallbacks(self, callbacks): # set our extension name callbacks.setExtensionName("CT Search") callbacks.registerContextMenuFactory(self) # obtain output stream self._stdout = PrintWriter(callbacks.getStdout(), True) stdout = PrintWriter(callbacks.getStdout(), True) # write a message to our output stream self._callbacks = callbacks # write a message to the Burp alerts tab callbacks.issueAlert("Hello alerts") #create and populate a jtable: initial_row = ['a', 'DOMAINS', True] self.fileTable = JTable(ResourceTableModel()) # set up the Tab: self.infoPanel = JPanel() footerPanel = JPanel() footerPanel.add(JLabel("by mcgyver5 ")) # self._chooseFileButton = JButton("OPEN Local FILE", actionPerformed=self.fileButtonClick) self.infoPanel.add(JLabel("INFORMATION PANE")) # self.infoPanel.add(self._chooseFileButton) scrollpane = JScrollPane(self.fileTable) ## this is a split inside the top component topPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) topPane.setTopComponent(self.infoPanel) topPane.setBottomComponent(scrollpane) #self._chooseFileButton.setEnabled(True) self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setTopComponent(topPane) self._splitpane.setBottomComponent(footerPanel) #callbacks.addSuiteTab(self) def get_domains_from_json_list(self, json_list): my_domain_list = [] for cert in json_list: try: domainList = str(cert.get('name_value')).strip() for domain in domainList.split("\n"): if not domain in my_domain_list: my_domain_list.append(domain) except Exception as e: print(e) my_domain_list.sort() return list(set(my_domain_list)) def get_domains_from_api(self, domain): my_domain_list = [] try: api_url = "https://crt.sh/?q=%.{}&output=json".format(domain) request = urllib2.urlopen(api_url) data = request.read() json_list = json.loads(data) my_domain_list = self.get_domains_from_json_list(json_list) except Exception as e: print("error") print(e) return my_domain_list def lookup_ct(self, whatever): domain = "" http_traffic = self.context.getSelectedMessages() for traffic in http_traffic: http_service = traffic.getHttpService() host = http_service.getHost() domain = host.replace('www.', '') self._stdout.println(domain) domain_list = self.get_domains_from_api(domain) ct_tab = CTSearchTab(self._callbacks) self._callbacks.addSuiteTab(ct_tab) ct_tab.setDomainList(domain_list) def fake_lookup_ct(self, whatever): domain_list = self.get_domains_from_file() ct_tab = CTSearchTab(self._callbacks) self._callbacks.addSuiteTab(ct_tab) ct_tab.setDomainList(domain_list) def createMenuItems(self, context_menu): self.context = context_menu menu_list = ArrayList() menu_list.add( JMenuItem("Lookup Domain in CT Logs", actionPerformed=self.lookup_ct)) menu_list.add( JMenuItem("CT LOgs Test get Domains from test file", actionPerformed=self.fake_lookup_ct)) return menu_list def get_domains_from_file(self): my_domain_list = [] fileChooser = JFileChooser() result = fileChooser.showOpenDialog(self._splitpane) if result == JFileChooser.APPROVE_OPTION: f = fileChooser.getSelectedFile() fileName = f.getPath() self._stdout.println(fileName) file_data = open(fileName).read() json_list = json.loads(file_data) for cert in json_list: try: domainList = str(cert.get('name_value')).strip() for domain in domainList.split("\n"): if not domain in my_domain_list: domain = domain.replace("*.", "") my_domain_list.append(domain) except Exception as e: self._stdout.println(e) my_domain_list.sort() return list(set(my_domain_list)) # def populateTableModel(self,f): # domain_list = [] # num = 0 # try: # path = os.getcwd() # self._stdout.println("path is : " + path) # fhandle = open(f) # file_data = fhandle.read() # domain_list = self.get_domains_from_file(file_data) # tableModel = self.fileTable.getModel() # except Exception as e: # self._stdout.println("exception! ") # self._stdout.println(e) # for dom in domain_list: # num = num + 1 # row = [str(num),dom,False] # tableModel.addRow(row) # def getTabCaption(self): return "Import URLs" def getUiComponent(self): return self._splitpane
class BurpExtender(IBurpExtender, IExtensionStateListener, ITab): ext_name = "CompuRacerExtension" ext_version = '1.2' loaded = True t = None def registerExtenderCallbacks(self, callbacks): Cb(callbacks) Cb.callbacks.setExtensionName(self.ext_name) try: global compuracer_communication_lock # option picker item objects (for Java compatibility) item1 = {'key': 'item1', 'name': '2'} item2 = {'key': 'item2', 'name': '3'} item3 = {'key': 'item3', 'name': '4'} item4 = {'key': 'item4', 'name': '5'} item5 = {'key': 'item5', 'name': '10'} item6 = {'key': 'item6', 'name': '15'} item7 = {'key': 'item7', 'name': '20'} item8 = {'key': 'item8', 'name': '25'} item9 = {'key': 'item9', 'name': '50'} item10 = {'key': 'item10', 'name': '100'} # main splitted pane + top pane self._main_splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._outer_settings_pane = JPanel(BorderLayout()) self._settings_pane = JPanel(GridBagLayout()) c = GridBagConstraints() self.label_1 = JLabel("Number of parallel requests:") c.fill = GridBagConstraints.NONE c.gridx = 0 c.gridy = 0 c.insets = Insets(0, 5, 0, 10) c.anchor = GridBagConstraints.LINE_START self._settings_pane.add(self.label_1, c) self.input_parallel_requests = JComboBox([ Item(item1), Item(item2), Item(item3), Item(item4), Item(item5), Item(item6), Item(item7), Item(item8), Item(item9), Item(item10) ]) self.input_parallel_requests.setSelectedIndex(4) self.input_parallel_requests.setToolTipText( "Select the number of parallel requests that will be sent") self.input_parallel_requests.addActionListener( self.change_parallel_requests) c.gridx = 1 c.gridy = 0 c.insets = Insets(0, 5, 0, 10) self._settings_pane.add(self.input_parallel_requests, c) self.option_allow_redirects = JCheckBox( "Allow redirects", actionPerformed=self.check_allow_redirects) self.option_allow_redirects.setToolTipText( "Select whether redirect responses are followed") c.gridx = 2 c.gridy = 0 c.insets = Insets(0, 20, 0, 10) self._settings_pane.add(self.option_allow_redirects, c) self.option_sync_last_byte = JCheckBox( "Sync last byte", actionPerformed=self.check_sync_last_byte) self.option_sync_last_byte.setToolTipText( "Select whether last byte synchronisation is enabled") c.gridx = 2 c.gridy = 1 c.insets = Insets(0, 20, 0, 0) self._settings_pane.add(self.option_sync_last_byte, c) self.label_2 = JLabel("Send timeout in seconds:") c.gridx = 0 c.gridy = 1 c.insets = Insets(0, 5, 0, 0) self._settings_pane.add(self.label_2, c) self.input_send_timeout = JComboBox([ Item(item2), Item(item4), Item(item5), Item(item7), Item(item9), Item(item10) ]) self.input_send_timeout.setSelectedIndex(3) self.input_send_timeout.setToolTipText( "Select the wait-for-response timeout after sending the request(s)" ) self.input_send_timeout.addActionListener(self.change_send_timeout) c.gridx = 1 c.gridy = 1 c.insets = Insets(0, 5, 0, 0) self._settings_pane.add(self.input_send_timeout, c) self.button_resend_batch = JButton("Resend requests") self.button_resend_batch.setToolTipText( "Resend all requests with the current configuration") self.button_resend_batch.setEnabled(False) self.button_resend_batch.addActionListener( MenuFactory.start_request_transmitter_button) c.gridx = 3 c.gridy = 0 c.insets = Insets(0, 20, 0, 10) self._settings_pane.add(self.button_resend_batch, c) immediate_data_ui_elements[ "parallel_requests"] = self.input_parallel_requests immediate_data_ui_elements[ "allow_redirects"] = self.option_allow_redirects immediate_data_ui_elements[ "sync_last_byte"] = self.option_sync_last_byte immediate_data_ui_elements[ "send_timeout"] = self.input_send_timeout immediate_data_ui_elements[ "resend_batch"] = self.button_resend_batch c = GridBagConstraints() c.anchor = GridBagConstraints.WEST self._outer_settings_pane.add(self._settings_pane, BorderLayout.WEST) self._main_splitpane.setTopComponent(self._outer_settings_pane) self._results_splitpane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) self._main_splitpane.setBottomComponent(self._results_splitpane) # table of log entries self.tabs_right = JTabbedPane() global _textEditors, DEFAULT_RESULTS for i in range(3): _textEditors.append(Cb.callbacks.createTextEditor()) _textEditors[-1].setText(str.encode("\n" + DEFAULT_RESULTS)) self.tabs_right.add("Summary", _textEditors[0].getComponent()) self.tabs_right.add("Full result", _textEditors[1].getComponent()) self.tabs_right.add("Config", _textEditors[2].getComponent()) self._results_splitpane.setRightComponent(self.tabs_right) # tabs with request/response viewers global _requestViewers, _requestPane _requestPane = JTabbedPane() _requestViewers.append( Cb.callbacks.createMessageEditor(None, False)) _requestPane.addTab("Request", _requestViewers[-1].getComponent()) self._results_splitpane.setLeftComponent(_requestPane) # customize our UI components Cb.callbacks.customizeUiComponent(self._settings_pane) Cb.callbacks.customizeUiComponent(self.tabs_right) Cb.callbacks.customizeUiComponent(_requestPane) # add the custom tab to Burp's UI Cb.callbacks.addSuiteTab(self) except RuntimeException as e: callbacks.printError(traceback.format_exc()) e = PyException(e) print("10") print(str(self)) print("{}\t{}\n{}\n".format(e.type, e.value, e.traceback)) Cb.callbacks.registerContextMenuFactory(MenuFactory()) callbacks.registerExtensionStateListener(self) self.start_alive_checker() Cb.callbacks.printOutput('%s v%s extension loaded\n' % (self.ext_name, self.ext_version)) def change_parallel_requests(self, event): global immediate_data try: num_parallel = MenuFactory.item_selected(event) if num_parallel != immediate_data['settings'][0]: self.update_setting(0, num_parallel, "number of parallel requests") except Exception as e: print(e) def change_send_timeout(self, event): global immediate_data try: send_timeout = MenuFactory.item_selected(event) if send_timeout != immediate_data['settings'][4]: self.update_setting(4, send_timeout, "send timeout") except Exception as e: print(e) def check_allow_redirects(self, event): global immediate_data is_selected = MenuFactory.button_selected(event) if is_selected != immediate_data['settings'][2]: self.update_setting(2, is_selected, "allow redirects") def check_sync_last_byte(self, event): global immediate_data is_selected = MenuFactory.button_selected(event) if is_selected != immediate_data['settings'][3]: self.update_setting(3, is_selected, "allow redirects") def resend_batches(self, event): global _storedRequests if _storedRequests is not None: self.sen # helper method for two methods above def update_setting(self, index, new_value, text): global immediate_data success = True print("> Updating {}..".format(text)) old_value = immediate_data['settings'][index] immediate_data['settings'][index] = new_value if MenuFactory.set_immediate_mode_settings( {'settings': immediate_data['settings']}): print("> Success!") else: print("> Failed!") immediate_data['settings'][index] = old_value success = False return success # for ITab def getTabCaption(self): return "CompuRacer" # for ITab def getUiComponent(self): return self._main_splitpane # def getHttpService(self): # global _storedRequest # return _storedRequest.getHttpService() # # def getRequest(self): # global _storedRequest # return _storedRequest.getRequest() # # def getResponse(self): # global _storedRequest # return _storedRequest.getResponse() def start_alive_checker(self): self.t = threading.Thread(name='Alive checker', target=self.alive_checker) self.t.start() def closest_match(self, number, list_of_numbers): return min(list(zip(list_of_numbers, range(len(list_of_numbers)))), key=lambda item: (abs(item[0] - number), item[1])) def alive_checker(self): global compuRacer_ip, compuRacer_port, alive_check_path, racer_alive, immediate_mode, compuracer_communication_lock unloaded = False old_alive = racer_alive parallel_req_options = [2, 3, 4, 5, 10, 15, 20, 25, 50, 100] send_time_options = [3, 5, 10, 20, 50, 100] while not unloaded: try: with compuracer_communication_lock: response = requests.get("http://{}:{}/{}".format( compuRacer_ip, compuRacer_port, alive_check_path), timeout=2) racer_alive = response and response.status_code and response.status_code == 200 success, mode, settings = MenuFactory.get_immediate_mode_settings( ) if success: immediate_data['mode'] = mode immediate_data['settings'] = settings # update UI button states immediate_data_ui_elements[ "parallel_requests"].setSelectedIndex( self.closest_match( immediate_data['settings'][0], parallel_req_options)[1]) immediate_data_ui_elements[ "allow_redirects"].setSelected( bool(immediate_data['settings'][2])) immediate_data_ui_elements[ "sync_last_byte"].setSelected( bool(immediate_data['settings'][3])) immediate_data_ui_elements[ "send_timeout"].setSelectedIndex( self.closest_match( immediate_data['settings'][4], send_time_options)[1]) except Exception as e: # it surely did not work racer_alive = False print(e) if racer_alive and not old_alive: print("> Racer is now alive!") MenuFactory.set_state_of_all_buttons(True) old_alive = True elif not racer_alive and old_alive: print("> Racer became dead!") MenuFactory.set_state_of_all_buttons(False) old_alive = False time.sleep(5) if not self.loaded: unloaded = True def extensionUnloaded(self): print("\n> Unloading..") self.loaded = False self.t.join() print("> Done.")
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
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, IMessageEditorController, AbstractTableModel): """ Implements IBurpExtender """ def registerExtenderCallbacks(self, callbacks): # Save callbacks and helpers for later use self._callbacks = callbacks self._helpers = callbacks.getHelpers() # Set extension name self._callbacks.setExtensionName("Burp XML Export Viewer") # Create the log and a lock on which to synchronize when adding log entries self._log = ArrayList() self._lock = Lock() # Main panel self._mainPanel = JPanel(BorderLayout()) # Button to load Burp XML Export file self._loadButton = JButton('Select Burp XML Export File') self._loadButton.addActionListener(self.loadButtonTapped) self._mainPanel.add(self._loadButton, BorderLayout.PAGE_START) # File chooser for Burp XML Export file self._fc = JFileChooser() self._fc.setDialogTitle("Select Burp XML Export File") # Splitpane for table and request/response view self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._mainPanel.add(self._splitpane, BorderLayout.CENTER) # Table of log entries self._logTable = Table(self) self._scrollPane = JScrollPane(self._logTable) self._splitpane.setTopComponent(self._scrollPane) # Set column width of table self._logTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF) self._logTable.getColumnModel().getColumn(0).setPreferredWidth(40) self._logTable.getColumnModel().getColumn(1).setPreferredWidth(60) self._logTable.getColumnModel().getColumn(2).setPreferredWidth(70) self._logTable.getColumnModel().getColumn(3).setPreferredWidth(300) self._logTable.getColumnModel().getColumn(4).setPreferredWidth(500) self._logTable.getColumnModel().getColumn(5).setPreferredWidth(300) self._logTable.getColumnModel().getColumn(6).setPreferredWidth(100) self._logTable.getColumnModel().getColumn(7).setPreferredWidth(100) self._logTable.getColumnModel().getColumn(8).setPreferredWidth(100) self._logTable.getColumnModel().getColumn(9).setPreferredWidth(100) self._logTable.getColumnModel().getColumn(10).setPreferredWidth(230) self._logTable.getColumnModel().getColumn(11).setMaxWidth(100000) # Tabs with request and response viewers self._tabs = JTabbedPane() self._requestViewer = callbacks.createMessageEditor(self, False) self._responseViewer = callbacks.createMessageEditor(self, False) self._tabs.addTab("Request", self._requestViewer.getComponent()) self._tabs.addTab("Response", self._responseViewer.getComponent()) self._splitpane.setBottomComponent(self._tabs) # Customize UI components self._callbacks.customizeUiComponent(self._mainPanel) self._callbacks.customizeUiComponent(self._splitpane) self._callbacks.customizeUiComponent(self._logTable) self._callbacks.customizeUiComponent(self._scrollPane) self._callbacks.customizeUiComponent(self._tabs) # Add the custom tab to Burp's UI self._callbacks.addSuiteTab(self) return """ Helper Functions """ def loadButtonTapped(self, actionEvent): # Display the file chooser dialog retVal = self._fc.showOpenDialog(None) if retVal == JFileChooser.APPROVE_OPTION: self._file = self._fc.getSelectedFile() self.resetList() # clear the table from all previous entries self.parseXML( self._file) # parse the file and load all entries to the table else: print("Open command cancelled by user.") def parseXML(self, file): # Initialize XML stuff dbFactory = DocumentBuilderFactory.newInstance() dBuilder = dbFactory.newDocumentBuilder() doc = dBuilder.parse(file) doc.getDocumentElement().normalize() # All entries in Burp's XML Export File have tag <item>...</item> nodeList = doc.getElementsByTagName("item") # for i in reversed(range(0, nodeList.getLength())): for i in range(0, nodeList.getLength()): node = nodeList.item(i) if node.getNodeType() == Node.ELEMENT_NODE: request = node.getElementsByTagName("request").item( 0).getTextContent() response = node.getElementsByTagName("response").item( 0).getTextContent() request_isBase64 = node.getElementsByTagName("request").item( 0).getAttribute("base64") response_isBase64 = node.getElementsByTagName("response").item( 0).getAttribute("base64") if request_isBase64 == "true": request = Base64.getDecoder().decode(request) if response_isBase64 == "true": response = Base64.getDecoder().decode(response) info = { "time": node.getElementsByTagName("time").item(0).getTextContent(), "url": node.getElementsByTagName("url").item(0).getTextContent(), "host": node.getElementsByTagName("host").item(0).getTextContent(), "port": node.getElementsByTagName("port").item(0).getTextContent(), "protocol": node.getElementsByTagName("protocol").item( 0).getTextContent(), "method": node.getElementsByTagName("method").item( 0).getTextContent(), "path": node.getElementsByTagName("path").item(0).getTextContent(), "extension": node.getElementsByTagName("extension").item( 0).getTextContent(), "request": request, "status": node.getElementsByTagName("status").item( 0).getTextContent(), "responselength": node.getElementsByTagName("responselength").item( 0).getTextContent(), "mimetype": node.getElementsByTagName("mimetype").item( 0).getTextContent(), "response": response, "comment": node.getElementsByTagName("comment").item( 0).getTextContent(), "highlight": "" } logEntry = LogEntry(info) # Remove GET parameters from path component # Path component usually looks like this: /some/path/index.html?q=foo&z=faa info["path"] = info["path"].split("?")[0] # Extract GET parameters params = [] for param in self._helpers.analyzeRequest( logEntry).getParameters(): if param.getType() == IParameter.PARAM_URL: params.append("{}={}".format(param.getName(), param.getValue())) info["params"] = "&".join(params) self.addLogEntryToList(logEntry) def addLogEntryToList(self, logEntry): self._lock.acquire() row = self._log.size() self._log.add(logEntry) self.fireTableRowsInserted(row, row) self._lock.release() def resetList(self): self._lock.acquire() self._log.clear() self.fireTableRowsInserted(0, 0) self._lock.release() """ Implements ITab """ def getTabCaption(self): return "Burp XML Export Viewer" def getUiComponent(self): return self._mainPanel """ Extends AbstractTableModel """ def getRowCount(self): try: return self._log.size() except: return 0 def getColumnCount(self): return 12 def getColumnName(self, columnIndex): if columnIndex == 0: return "#" if columnIndex == 1: return "Method" if columnIndex == 2: return "Protocol" if columnIndex == 3: return "Host" if columnIndex == 4: return "Path" if columnIndex == 5: return "Parameters" if columnIndex == 6: return "Status" if columnIndex == 7: return "Length" if columnIndex == 8: return "MIME type" if columnIndex == 9: return "Extension" if columnIndex == 10: return "Time" if columnIndex == 11: return "Comment" return "" def getValueAt(self, rowIndex, columnIndex): logEntry = self._log.get(rowIndex) if columnIndex == 0: return "{}".format(rowIndex) if columnIndex == 1: return logEntry._info["method"] if columnIndex == 2: return logEntry._info["protocol"] if columnIndex == 3: return logEntry.getHttpService().getHost() if columnIndex == 4: return logEntry._info["path"] if columnIndex == 5: return logEntry._info["params"] if columnIndex == 6: return logEntry._info["status"] if columnIndex == 7: return logEntry._info["responselength"] if columnIndex == 8: return logEntry._info["mimetype"] if columnIndex == 9: return logEntry._info["extension"] if columnIndex == 10: return logEntry._info["time"] if columnIndex == 11: return logEntry._info["comment"] return "" """ Implements IMessageEditorController Allows request and response viewers to obtain details about the messages being displayed """ def getHttpService(self): return self._currentlyDisplayedItem.getHttpService() def getRequest(self): return self._currentlyDisplayedItem.getRequest() def getResponse(self): return self._currentlyDisplayedItem.getResponse()
class BurpExtender(IBurpExtender, ITab): # # implement IBurpExtender # def hello(self): return "hello" def process_file(self, file): freshrows = [] # return list of list of file parts for url in file: result = urlparse(url) scheme = result[0] domain = result[0] path = result[0] params = '' query = '' fragment = '' next = [scheme, domain, path, params, query, fragment] freshrows.append(next) return freshrows def registerExtenderCallbacks(self, callbacks): # set our extension name callbacks.setExtensionName("Hello world extension") # obtain our output and error streams stdout = PrintWriter(callbacks.getStdout(), True) stderr = PrintWriter(callbacks.getStderr(), True) # write a message to our output stream stdout.println("Hello output") # write a message to our error stream stderr.println("Hello errors") # write a message to the Burp alerts tab callbacks.issueAlert("Hello alerts") #create and populate a jtable: initial_row = [ 'http', 'www.meetup.com', 'PyMNtos-Twin-Cities-Python-User-Group/events/267977020/', '', '', '' ] self.fileTable = JTable(ResourceTableModel(initial_row)) # set up the Tab: self.infoPanel = JPanel() footerPanel = JPanel() footerPanel.add(JLabel("by mcgyver5 ")) self._chooseFileButton = JButton("OPEN Local FILE", actionPerformed=self.fileButtonClick) self.infoPanel.add(JLabel("INFORMATION PANE")) self.infoPanel.add(self._chooseFileButton) scrollpane = JScrollPane(self.fileTable) ## this is a split inside the top component topPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) topPane.setTopComponent(self.infoPanel) topPane.setBottomComponent(scrollpane) self._chooseFileButton.setEnabled(True) self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setTopComponent(topPane) self._splitpane.setBottomComponent(footerPanel) callbacks.addSuiteTab(self) def populateTableModel(self, results): tableModel = self.fileTable.getModel() for row in results: tableModel.addRow(row) def fileButtonClick(self, callbacks): fileTypeList = ["csv", "txt", "json"] txtFilter = FileNameExtensionFilter("txt", fileTypeList) fileChooser = JFileChooser() fileChooser.addChoosableFileFilter(txtFilter) result = fileChooser.showOpenDialog(self._splitpane) if result == JFileChooser.APPROVE_OPTION: f = fileChooser.getSelectedFile() fileName = f.getPath() self.populateTableModel(f) ## Implement ITab: def getTabCaption(self): return "Import URLs" def getUiComponent(self): return self._splitpane
def create(self): # Estilo general para todas las sub-tab. gBC = GridBagConstraints() gBC.fill = GridBagConstraints.BOTH gBC.ipadx = 5 gBC.ipady = 5 gBC.insets = Insets(0, 5, 5, 5) gBC.weightx = 0.5 #gBC.weighty = 0.7 ####################################### ### Creamos la primera sub-tab. (MASHUP) ####################################### tab_1 = JPanel(GridBagLayout()) tab_1_jlabelAyuda = JLabel( '<html><i>•Tip: This Mashup receive one or more keywords in order to generate a list of possible passwords</i></html>' ) tab_1_jlabelAyuda.setFont(Font("Serif", 0, 12)) gBC.gridx = 0 gBC.gridy = 0 tab_1.add( JLabel('<html><font color=green><i>Income:</i></font></html>'), gBC) gBC.gridy = 1 tab_1.add(JLabel('<html><b>• Name:</b></html>'), gBC) gBC.gridy = 2 tab_1.add(self._tab1_nombre, gBC) gBC.gridy = 3 tab_1.add(JLabel('<html><b>• Surname:</b></html>'), gBC) gBC.gridy = 4 tab_1.add(self._tab1_apellido, gBC) gBC.gridy = 5 tab_1.add(JLabel('<html><b>• Birthdate: (DDMMYYYY)</b></html>'), gBC) gBC.gridy = 6 tab_1.add(self._tab1_FNacimiento, gBC) gBC.gridy = 7 tab_1.add(JLabel('<html><b>• Pet:</b></html>'), gBC) gBC.gridy = 8 tab_1.add(self._tab1_mascota, gBC) gBC.gridy = 9 tab_1.add(JLabel('<html><b>• Anyother:</b></html>'), gBC) gBC.gridy = 10 tab_1.add(self._tab1_otro, gBC) gBC.gridy = 11 tab_1.add(JLabel('<html><b>• Passwd Min Size:</b></html>'), gBC) gBC.gridy = 12 tab_1.add(self._tab1_minsize, gBC) gBC.gridy = 13 tab_1.add(JLabel('<html><b>• Passwd Max Size:</b></html>'), gBC) gBC.gridy = 14 tab_1.add(self._tab1_maxsize, gBC) gBC.gridy = 15 tab_1.add( JLabel( '<html><b>• Especial Chars: (comma separated)</b></html>' ), gBC) gBC.gridy = 16 tab_1.add(self._tab1_specialchars, gBC) gBC.gridy = 17 tab_1.add(self._tab1_transformations, gBC) gBC.gridy = 18 tab_1.add(self._tab1_firstcapital, gBC) gBC.gridy = 19 tab_1.add(JButton('Mashup!', actionPerformed=self.mashup), gBC) gBC.gridy = 20 gBC.gridwidth = 3 tab_1.add(JSeparator(), gBC) gBC.gridwidth = 1 gBC.gridy = 21 gBC.gridwidth = 3 tab_1.add(tab_1_jlabelAyuda, gBC) gBC.gridwidth = 1 gBC.gridx = 1 gBC.gridy = 0 gBC.gridheight = 20 gBC.weightx = 0 tab_1.add(JSeparator(SwingConstants.VERTICAL), gBC) gBC.gridheight = 1 gBC.weightx = 0.5 gBC.gridx = 2 gBC.gridy = 0 tab_1.add( JLabel('<html><font color=green><i>Outcome:</i></font></html>'), gBC) gBC.gridy = 1 gBC.gridwidth = 2 gBC.gridheight = 18 tab_1.add(self._tab1_feedback_sp, gBC) gBC.gridwidth = 1 gBC.gridheight = 1 gBC.gridy = 19 tab_1.add( JButton('Copy to clipboard!', actionPerformed=self.cpy_clipboard), gBC) ####################################### ### Creamos la segunda sub-tab. (REDIRECT) ####################################### tab_2 = JPanel(GridBagLayout()) tab_2_jlabelAyuda = JLabel( '<html><i>•Tip: This Redirect receive a pair of hosts x,y in order to redirect from x to y.</i></html>' ) tab_2_jlabelAyuda.setFont(Font("Serif", 0, 12)) gBC.gridx = 0 gBC.gridy = 0 tab_2.add( JLabel('<html><b>• From: (i.e. www.facebook.com)</b></html>'), gBC) gBC.gridx = 1 gBC.gridy = 0 tab_2.add(self._tab2_JTFa, gBC) gBC.gridx = 2 gBC.gridy = 0 tab_2.add( JLabel('<html><b>• To: (i.e. www.myhomepage.es)</b></html>'), gBC) gBC.gridx = 3 gBC.gridy = 0 tab_2.add(self._tab2_JTFaa, gBC) gBC.gridx = 0 gBC.gridy = 1 gBC.gridwidth = 4 tab_2.add(JSeparator(), gBC) gBC.gridwidth = 1 gBC.gridx = 0 gBC.gridy = 2 tab_2.add(JLabel('<html><b>• From:</b></html>'), gBC) gBC.gridx = 1 gBC.gridy = 2 tab_2.add(self._tab2_JTFb, gBC) gBC.gridx = 2 gBC.gridy = 2 tab_2.add(JLabel('<html><b>• To:</b></html>'), gBC) gBC.gridx = 3 gBC.gridy = 2 tab_2.add(self._tab2_JTFbb, gBC) gBC.gridx = 0 gBC.gridy = 3 gBC.gridwidth = 4 tab_2.add(self._tab2_boton, gBC) gBC.gridwidth = 1 gBC.gridx = 0 gBC.gridy = 4 gBC.gridwidth = 4 gBC.insets = Insets(100, 10, 5, 10) tab_2.add(JSeparator(), gBC) gBC.gridwidth = 1 gBC.insets = Insets(5, 10, 5, 10) gBC.gridx = 0 gBC.gridy = 5 gBC.gridwidth = 4 tab_2.add(tab_2_jlabelAyuda, gBC) gBC.gridwidth = 1 ####################################### ### Creamos la tercera sub-tab. (LOADER) ####################################### tab_3 = JPanel(GridBagLayout()) tab_3_jlabelAyuda = JLabel( '<html><i>•Tip: This Loader receive a list of Hosts or IPs that will be added to the Burp Scope.</i></html>' ) tab_3_jlabelAyuda.setFont(Font("Serif", 0, 12)) gBC.gridx = 0 gBC.gridy = 0 tab_3.add( JLabel( '<html><font color=green><i>List of targets: (i.e. http://www.mytargetweb.com)</i></font></html>' ), gBC) gBC.gridy = 1 gBC.gridheight = 10 gBC.weighty = 0.5 tab_3.add(self._tab3_urls_sp, gBC) gBC.gridheight = 1 gBC.weighty = 0 gBC.gridy = 11 tab_3.add( JButton('Load Into Target => Scope!', actionPerformed=self.loader), gBC) gBC.gridy = 12 gBC.gridwidth = 5 gBC.insets = Insets(100, 10, 5, 10) tab_3.add(JSeparator(), gBC) gBC.gridwidth = 1 gBC.insets = Insets(5, 10, 5, 10) gBC.gridy = 13 tab_3.add(tab_3_jlabelAyuda, gBC) ####################################### ### Creamos la cuarta sub-tab. (HEADERS) ####################################### tab_4_jlabelAyuda = JLabel( "<html><i>•Tip: This Headers records all unique headers that appear in every host, check out the security headers.</i></html>" ) tab_4_jlabelAyuda.setFont(Font("Serif", 0, 12)) tab_4_jLabelRecomendacion = JLabel( "<html>•<b>Server</b>: Don't give away much information.<br> •<b>Content-Security-Policy</b>: Protect your site from XSS attacks by whitelisting sources of approved content.<br> •<b>Strict-Transport-Security</b>: Enforce the browser to use HTTPS.<br> •<b>Public-Key-Pins</b>: Protect your site from MITM attacks.<br> •<b>X-Content-Type-Options</b>: the valid value is -> nosniff .<br> •<b>X-Frame-Options</b>: tells the browser whether you want to allow your site to be framed or not.<br> •<b>X-XSS-Protection</b>: the best value is -> 1; mode=block .</html>" ) tab_4_jLabelRecomendacion.setFont(Font("Dialog", 0, 13)) tab_4 = JPanel(GridBagLayout()) splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) tab_4_top = JPanel(GridBagLayout()) tab_4_bottom = JPanel(GridBagLayout()) gBC_table = GridBagConstraints() gBC_table.fill = GridBagConstraints.BOTH gBC_table.ipadx = 5 gBC_table.ipady = 5 gBC_table.insets = Insets(5, 10, 5, 10) gBC_table.weightx = 1 gBC_table.weighty = 1 tabla_datos = [] tabla_headers = ('Severity', 'Header', 'Value', 'Host') self._tab4_tabla_model = DefaultTableModel(tabla_datos, tabla_headers) tabla_ej = JTable(self._tab4_tabla_model) tabla_example = JScrollPane(tabla_ej, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED) gBC_table.gridx = 0 gBC_table.gridy = 0 gBC_table.gridheight = 5 tab_4_top.add(tabla_example, gBC_table) gBC_table.gridheight = 1 gBC_table.weightx = 0.5 gBC_table.weighty = 0 gBC_table.gridwidth = 2 gBC_table.gridx = 0 gBC_table.gridy = 0 tab_4_bottom.add(JSeparator(), gBC_table) gBC_table.gridy = 1 tab_4_bottom.add(tab_4_jlabelAyuda, gBC_table) gBC_table.gridy = 2 tab_4_bottom.add(tab_4_jLabelRecomendacion, gBC_table) splitpane.setTopComponent(tab_4_top) splitpane.setBottomComponent(tab_4_bottom) gBC_table.weightx = 1 gBC_table.weighty = 1 gBC_table.gridx = 0 gBC_table.gridy = 0 tab_4.add(splitpane, gBC_table) ####################################### ### Creamos la quinta sub-tab. (ACTIVE SCAN) ####################################### tab_5 = JPanel(GridBagLayout()) tab_5_jlabelAyuda = JLabel( '<html><i>•Tip: This Quick Scan receive a list of targets and launch an active scan.</i></html>' ) tab_5_jlabelAyuda.setFont(Font("Serif", 0, 12)) tab_5_jlabelWarning = JLabel( '<html><font color=red><i>•Warning: Active scanning generates large numbers of requests which are malicious in form and which may result in compromise of the application. You should use this scanning mode with caution, only with the explicit permission of the application owner. For more information, read the documentation of active scan, Burp Suite.</font></i></html>' ) tab_5_jlabelWarning.setFont(Font("Dialog", 0, 13)) gBC.gridx = 0 gBC.gridy = 0 tab_5.add( JLabel( '<html><font color=green><i>List of targets: (i.e. http://192.168.1.1/index.html)</i></font></html>' ), gBC) gBC.gridy = 1 gBC.gridheight = 8 gBC.weighty = 0.5 tab_5.add(self._tab5_target_sp, gBC) gBC.gridheight = 1 gBC.weighty = 0 gBC.gridy = 9 tab_5.add(JButton('Launch Scan!', actionPerformed=self.do_active_scan), gBC) gBC.gridy = 10 gBC.gridwidth = 5 gBC.insets = Insets(100, 10, 5, 10) tab_5.add(JSeparator(), gBC) gBC.gridwidth = 1 gBC.insets = Insets(5, 10, 5, 10) gBC.gridy = 11 tab_5.add(tab_5_jlabelAyuda, gBC) gBC.gridy = 12 tab_5.add(tab_5_jlabelWarning, gBC) ####################################### ### Creamos la ultima sub-tab. ####################################### tab_about = JPanel(GridBagLayout()) gBC_about = GridBagConstraints() gBC_about.fill = GridBagConstraints.HORIZONTAL gBC_about.ipadx = 5 gBC_about.ipady = 5 gBC_about.insets = Insets(5, 10, 5, 10) gBC_about.weightx = 1 gBC_about.weighty = 1 Jlabel1 = JLabel('<html><b>Plug-in L-Tools</b></html>') Jlabel1.setFont(Font("Dialog", 1, 18)) jlabel2 = JLabel( '<html>This Plug-in provides utilities for pentesters, researchers and developers, in order to support their work.</html>' ) jlabel3 = JLabel('<html><b>CC-BY 4.0, 2017. Gino Angles</b></html>') jlabel3.setFont(Font("Dialog", 1, 14)) jlabel4 = JLabel('<html><b>License</b></html>') jlabel4.setFont(Font("Dialog", 1, 14)) jlabel5 = JLabel( '<html><img alt="Licensed under a Creative Commons BY" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png"></html>' ) jlabel6 = JLabel( '<html>This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.</html>' ) jlabel7 = JLabel('<html><b>Dependencies</b></html>') jlabel7.setFont(Font("Dialog", 1, 14)) jlabel8 = JLabel('Jython +2.7') jlabel9 = JLabel('http://www.jython.org') gBC_about.gridx = 0 gBC_about.gridy = 0 tab_about.add(Jlabel1, gBC_about) gBC_about.gridy = 1 tab_about.add(jlabel2, gBC_about) gBC_about.gridy = 2 tab_about.add(jlabel3, gBC_about) gBC_about.gridy = 3 gBC_about.gridwidth = 5 tab_about.add(JSeparator(), gBC_about) gBC_about.gridwidth = 1 gBC_about.gridy = 4 tab_about.add(jlabel4, gBC_about) gBC_about.gridy = 5 tab_about.add(jlabel5, gBC_about) gBC_about.gridy = 6 tab_about.add(jlabel6, gBC_about) gBC_about.gridy = 7 gBC_about.gridwidth = 5 tab_about.add(JSeparator(), gBC_about) gBC_about.gridwidth = 1 gBC_about.gridy = 8 tab_about.add(jlabel7, gBC_about) gBC_about.gridy = 9 tab_about.add(jlabel8, gBC_about) gBC_about.gridy = 10 tab_about.add(jlabel9, gBC_about) # Añadimos los sub-tab al contenedor y lo devolvemos. self.contenedor.addTab('Mashup', tab_1) self.contenedor.addTab('Redirect', tab_2) self.contenedor.addTab('Loader', tab_3) self.contenedor.addTab('Headers', tab_4) self.contenedor.addTab('Quick Scan', tab_5) self.contenedor.addTab('About', tab_about) return self.contenedor
class BurpExtender(IBurpExtender, ITab): # # implement IBurpExtender # def registerExtenderCallbacks(self, callbacks): # set our extension name callbacks.setExtensionName("War Story") # obtain our output stream self._stdout = PrintWriter(callbacks.getStdout(), True) # write a message to our output stream self._stdout.println("Loading WarStory") # write a message to the Burp alerts tab callbacks.issueAlert("Hello alerts") label = JLabel("INFO PANEL") self.infoPanel = JPanel() footerPanel = JPanel() footerPanel.add(JLabel("by Tim mcgyver5 McGuire")) self._chooseFileButton = JButton("OPEN WAR FILE", actionPerformed=self.fileButtonClick) self.infoPanel.add(JLabel("THIS IS INFORMATION PANE")) self.infoPanel.add(self._chooseFileButton) # iaap.war|web.xml|axServlet|/skuppy/axservlet.do| self._chooseFileButton.setEnabled(True) initial_row = ['a', 'bb', 'ccc', 'ddd', 'eeee'] self.fileTable = JTable(ResourceTableModel(initial_row)) scrollpane = JScrollPane(self.fileTable) ## this is a split inside the top component topPane = JSplitPane(JSplitPane.VERTICAL_SPLIT) topPane.setTopComponent(self.infoPanel) topPane.setBottomComponent(scrollpane) # split the top panel into a Panel and a JScrollPane self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setTopComponent(topPane) self._splitpane.setBottomComponent(footerPanel) callbacks.addSuiteTab(self) def populateJTable(self, f): filename = f.getPath() tableModel = self.fileTable.getModel() test_row = ["a", "b", "doo", "dah", "dob"] re = Resource("Servlet", "bingServlet", "bingservlet.do", [], [], "GET") self._stdout.println("populatin table model") tableModel.addRow(test_row) def fileButtonClick(self, e): fileTypeList = ["war", "ear", "zip"] warFilter = FileNameExtensionFilter("war", fileTypeList) fileChooser = JFileChooser() fileChooser.addChoosableFileFilter(warFilter) result = fileChooser.showOpenDialog(self._splitpane) if result == JFileChooser.APPROVE_OPTION: f = fileChooser.getSelectedFile() fileName = f.getPath() self.populateJTable(f) # Implement ITab def getTabCaption(self): return "War Story" def getUiComponent(self): return self._splitpane
class BurpExtender(IBurpExtender, IContextMenuFactory, ITab, ComponentListener, ActionListener, MouseAdapter): # contains the messages to show in the messages table _table_data = [] # contains the messages to translate _messages = [] # used to keep track when to refresh the table _reload_table = False _sql_file = None def registerExtenderCallbacks(self, callbacks): self._panel = JPanel() self._panel.setLayout(BorderLayout()) #self._panel.setSize(400,400) # sourrounding try\except because Burp is not giving enough info try: # creating all the UI elements # create the split pane self._split_pane_horizontal = JSplitPane( JSplitPane.HORIZONTAL_SPLIT) self._split_panel_vertical = JSplitPane(JSplitPane.VERTICAL_SPLIT) # create panels self._panel_top = JPanel() self._panel_top.setLayout(BorderLayout()) self._panel_bottom = JPanel() self._panel_bottom.setLayout(BorderLayout()) self._panel_right = JPanel() self._panel_right.setLayout(BorderLayout()) self._panel_request = JPanel() self._panel_request.setLayout(BorderLayout()) self._panel_response = JPanel() self._panel_response.setLayout(BorderLayout()) # create the tabbed pane used to show request\response self._tabbed_pane = JTabbedPane(JTabbedPane.TOP) # create the tabbed pane used to show aslan++\concretization file self._tabbed_pane_editor = JTabbedPane(JTabbedPane.TOP) # create the bottom command for selecting the SQL file and # generating the model self._button_generate = JButton( 'Generate!', actionPerformed=self._generate_model) self._button_save = JButton('Save', actionPerformed=self._save_model) self._button_select_sql = JButton( 'Select SQL', actionPerformed=self._select_sql_file) self._text_field_sql_file = JTextField(20) self._panel_bottom_commands = JPanel() layout = GroupLayout(self._panel_bottom_commands) layout.setAutoCreateGaps(True) layout.setAutoCreateContainerGaps(True) seq_layout = layout.createSequentialGroup() seq_layout.addComponent(self._text_field_sql_file) seq_layout.addComponent(self._button_select_sql) seq_layout.addComponent(self._button_generate) seq_layout.addComponent(self._button_save) layout.setHorizontalGroup(seq_layout) # create the message editors that will be used to show request and response self._message_editor_request = callbacks.createMessageEditor( None, True) self._message_editor_response = callbacks.createMessageEditor( None, True) # create the table that will be used to show the messages selected for # the translation self._columns_names = ('Host', 'Method', 'URL') dataModel = NonEditableModel(self._table_data, self._columns_names) self._table = JTable(dataModel) self._scrollPane = JScrollPane() self._scrollPane.getViewport().setView((self._table)) popmenu = JPopupMenu() delete_item = JMenuItem("Delete") delete_item.addActionListener(self) popmenu.add(delete_item) self._table.setComponentPopupMenu(popmenu) self._table.addMouseListener(self) # add all the elements self._panel_request.add( self._message_editor_request.getComponent()) self._panel_response.add( self._message_editor_response.getComponent()) self._tabbed_pane.addTab("Request", self._panel_request) self._tabbed_pane.addTab("Response", self._panel_response) self._panel_top.add(self._scrollPane, BorderLayout.CENTER) self._panel_bottom.add(self._tabbed_pane, BorderLayout.CENTER) scroll = JScrollPane(self._panel_bottom) self._panel_right.add(self._tabbed_pane_editor, BorderLayout.CENTER) self._panel_right.add(self._panel_bottom_commands, BorderLayout.PAGE_END) self._split_panel_vertical.setTopComponent(self._panel_top) self._split_panel_vertical.setBottomComponent(scroll) self._split_pane_horizontal.setLeftComponent( self._split_panel_vertical) self._split_pane_horizontal.setRightComponent(self._panel_right) self._panel.addComponentListener(self) self._panel.add(self._split_pane_horizontal) self._callbacks = callbacks callbacks.setExtensionName("WAFEx") callbacks.addSuiteTab(self) callbacks.registerContextMenuFactory(self) except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] print(exc_type, fname, exc_tb.tb_lineno) def getTabCaption(self): return "WAFEx" def getUiComponent(self): try: Platform.runLater(EditorTabUI(self)) return self._panel except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1] print(exc_type, fname, exc_tb.tb_lineno) def componentShown(self, e): self._split_pane_horizontal.setDividerLocation(0.25) # populate the table with the selected requests\response try: if self._reload_table: print("reload") self._table_data = [ ] # empty _table_data (not too cool but quick) for c in self._messages: msg = c[0] http_request = converter._byte_array_to_string( msg.getRequest()) request_parser = HttpParser() request_parser.execute(http_request, len(http_request)) host = msg.getHttpService().getHost() page = request_parser.get_url() method = request_parser.get_method() tmp = [host, method, page] self._table_data += [tmp] self._table.getModel().setDataVector(self._table_data, self._columns_names) self._reload_table = False except Exception as e: print(e) def componentHidden(self, e): return def componentMoved(self, e): return def componentResized(self, e): self._split_pane_horizontal.setDividerLocation(0.25) def createMenuItems(self, invocation): ret = [] try: if (invocation.getInvocationContext() == invocation.CONTEXT_TARGET_SITE_MAP_TABLE): menu = JMenuItem("Send to WAFEx") messages = invocation.getSelectedMessages() def listener(e): """ Generates a new WAFEx model. """ #self._generateWAFExModel(messages) self._addToGeneration(messages) menu.addActionListener(listener) ret.append(menu) except Exception as e: print(e) return ret def mouseClicked(self, e): """ Positions the Aslan++ editor to the selected request position. """ try: index = self._table.getSelectedRow() c = self._messages[index] print(len(c)) message = c[0] tag = c[1] self._message_editor_request.setMessage(message.getRequest(), True) self._message_editor_response.setMessage(message.getResponse(), False) if tag != None: document = self._jfxp_aslanpp._editor.getText() start, end = self._search_tag_position(tag, document) self._jfxp_aslanpp._editor.moveTo(start) self._jfxp_aslanpp._editor.selectRange(start, end) self._jfxp_aslanpp._editor.requestFollowCaret() self._jfxp_aslanpp._editor.requestFocus() except Exception as e: print(e) def actionPerformed(self, e): """ Performs the delete action. """ try: index = self._table.getSelectedRow() del self._table_data[index] del self._messages[index] self._table.getModel().setDataVector(self._table_data, self._columns_names) except Exception as e: print(e) def _search_tag_position(self, tag, text): """ Searches for a particular tag in a given text and return its position. """ pattern = self._search_pattern.format(tag) for m in re.finditer(pattern, text): return m.start(), m.end() def _save_model(self, e): """ Saves the current Aslan++ model and concretization file. """ try: chooseFile = JFileChooser() filter_ = FileNameExtensionFilter("txt files", ["txt"]) chooseFile.addChoosableFileFilter(filter_) ret = chooseFile.showDialog(self._panel, "Choose file") if ret == JFileChooser.APPROVE_OPTION: self._model_name = chooseFile.getSelectedFile().getPath() with open("{}.aslan++".format(self._model_name), "w") as f: skeleton = self._jfxp_aslanpp._editor.getText() skeleton = skeleton.replace("@filename", basename(self._model_name)) f.write(skeleton) print("model created") with open("{}.txt".format(self._model_name), "w") as f: f.write(self._jfxp_concretization._editor.getText()) except Exception as e: print(e) def _select_sql_file(self, e): """ Shows a JFileChooser dialog to select the SQL file to use for creating the model. """ try: chooseFile = JFileChooser() filter_ = FileNameExtensionFilter("txt files", ["txt"]) chooseFile.addChoosableFileFilter(filter_) ret = chooseFile.showDialog(self._panel, "Choose file") if ret == JFileChooser.APPROVE_OPTION: self._sql_file = chooseFile.getSelectedFile().getPath() else: self._sql_file = None self._text_field_sql_file.setText("" + self._sql_file) except Exception as e: print(e) def _addToGeneration(self, messages): for msg in messages: self._messages += [[msg, None]] self._reload_table = True def _generate_model(self, e): if len(self._messages) <= 0: frame = JFrame("Error") JOptionPane.showMessageDialog(frame, "No messages!", "Error", JOptionPane.ERROR_MESSAGE) return if self._sql_file == None: frame = JFrame("Error") replay = JOptionPane.showConfirmDialog( frame, "No SQL file selected!\nDo you want to continue?", "Info", JOptionPane.YES_NO_OPTION) if replay == JOptionPane.NO_OPTION: return # create a new AslanppModel model = AslanppModel() # save _sql_file model._sql_file = self._sql_file for c in self._messages: # from byte to char Request and Response # for some reason b can be a negative value causing a crash # so I put a check to ensure b is in the right range msg = c[0] if msg.getRequest() == None or msg.getResponse() == None: # do not convert empty messages continue http_request = "".join( chr(b) for b in msg.getRequest() if b >= 0 and b <= 256) http_response = "".join( chr(b) for b in msg.getResponse() if b >= 0 and b <= 256) protocol = msg.getHttpService().getProtocol() # save the tag number generate by _parseHttpRequestResponse in the _messages array c[1] = converter._parseHttpRequestResponse(model, http_request, http_response, protocol) # generate the ASLan++ code self._model, self._concrete = converter._generateWAFExModel(model) Platform.runLater( UpdateEditor(self._jfxp_aslanpp._editor, self._jfxp_concretization._editor, self._model, self._concrete))
class BurpExtender(IBurpExtender, ISessionHandlingAction, ITab, IContextMenuFactory, IContextMenuInvocation, ActionListener, ITextEditor): # # implement IBurpExtender # def registerExtenderCallbacks(self, callbacks): # save the helpers for later self.helpers = callbacks.getHelpers() # set our extension name callbacks.setExtensionName("Custom Request Handler") callbacks.registerSessionHandlingAction(self) callbacks.registerContextMenuFactory(self) self._text_editor = callbacks.createTextEditor() self._text_editor.setEditable(False) #How much loaded the table row self.current_column_id = 0 #GUI self._split_main = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._split_top = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) self._split_top.setPreferredSize(Dimension(100, 50)) self._split_top.setDividerLocation(700) self._split_center = JSplitPane(JSplitPane.VERTICAL_SPLIT) boxVertical = swing.Box.createVerticalBox() box_top = swing.Box.createHorizontalBox() boxHorizontal = swing.Box.createHorizontalBox() buttonHorizontal = swing.Box.createHorizontalBox() boxVertical.add(boxHorizontal) box_regex = swing.Box.createVerticalBox() border = BorderFactory.createTitledBorder(LineBorder(Color.BLACK), "Extract target strings", TitledBorder.LEFT, TitledBorder.TOP) box_regex.setBorder(border) self._add_btn = JButton("Add") self._add_btn.addActionListener(self) self._remove_btn = JButton("Remove") self._remove_btn.addActionListener(self) items = [ 'JSON', 'Header', ] self._dropdown = JComboBox(items) type_panel = JPanel(FlowLayout(FlowLayout.LEADING)) type_panel.add(JLabel('Type:')) type_panel.add(self._dropdown) self._jLabel_param = JLabel("Name:") self._param_error = JLabel("Name is required") self._param_error.setVisible(False) self._param_error.setFont(Font(Font.MONOSPACED, Font.ITALIC, 12)) self._param_error.setForeground(Color.red) regex_checkbox = JPanel(FlowLayout(FlowLayout.LEADING)) self._is_use_regex = JCheckBox("Extract from regex group") regex_checkbox.add(self._is_use_regex) self._jTextIn_param = JTextField(20) self._jLabel_regex = JLabel("Regex:") self._jTextIn_regex = JTextField(20) self._regex_error = JLabel("No group defined") self._regex_error.setVisible(False) self._regex_error.setFont(Font(Font.MONOSPACED, Font.ITALIC, 12)) self._regex_error.setForeground(Color.red) self._param_panel = JPanel(FlowLayout(FlowLayout.LEADING)) self._param_panel.add(self._jLabel_param) self._param_panel.add(self._jTextIn_param) self._param_panel.add(self._param_error) self._regex_panel = JPanel(FlowLayout(FlowLayout.LEADING)) self._regex_panel.add(self._jLabel_regex) self._regex_panel.add(self._jTextIn_regex) self._regex_panel.add(self._regex_error) button_panel = JPanel(FlowLayout(FlowLayout.LEADING)) #padding button_panel.add(JPanel()) button_panel.add(JPanel()) button_panel.add(JPanel()) button_panel.add(self._add_btn) button_panel.add(self._remove_btn) box_regex.add(type_panel) box_regex.add(self._param_panel) box_regex.add(regex_checkbox) box_regex.add(self._regex_panel) buttonHorizontal.add(button_panel) box_regex.add(buttonHorizontal) boxVertical.add(box_regex) box_top.add(boxVertical) box_file = swing.Box.createHorizontalBox() checkbox_panel = JPanel(FlowLayout(FlowLayout.LEADING)) border = BorderFactory.createTitledBorder( LineBorder(Color.BLACK), 'Payload Sets [Simple list]', TitledBorder.LEFT, TitledBorder.TOP) box_file.setBorder(border) box_param = swing.Box.createVerticalBox() box_param.add(checkbox_panel) file_column_names = [ "Type", "Name", "Payload", ] data = [] self.file_table_model = DefaultTableModel(data, file_column_names) self.file_table = JTable(self.file_table_model) self.file_table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF) column_model = self.file_table.getColumnModel() for count in xrange(column_model.getColumnCount()): column = column_model.getColumn(count) column.setPreferredWidth(160) self.file_table.preferredScrollableViewportSize = Dimension(500, 70) self.file_table.setFillsViewportHeight(True) panel_dropdown = JPanel(FlowLayout(FlowLayout.LEADING)) self._file_dropdown = JComboBox(items) panel_dropdown.add(JLabel('Type:')) panel_dropdown.add(self._file_dropdown) box_param.add(panel_dropdown) box_param.add(JScrollPane(self.file_table)) callbacks.customizeUiComponent(self.file_table) file_param_panel = JPanel(FlowLayout(FlowLayout.LEADING)) self._file_param = JLabel("Name:") self._file_param_text = JTextField(20) file_param_panel.add(self._file_param) file_param_panel.add(self._file_param_text) self._error_message = JLabel("Name is required") self._error_message.setVisible(False) self._error_message.setFont(Font(Font.MONOSPACED, Font.ITALIC, 12)) self._error_message.setForeground(Color.red) file_param_panel.add(self._error_message) box_param.add(file_param_panel) box_button_file = swing.Box.createVerticalBox() self._file_load_btn = JButton("Load") self._file_clear_btn = JButton("Clear") self._file_clear_btn.addActionListener(self) self._file_load_btn.addActionListener(self) box_button_file.add(self._file_load_btn) box_button_file.add(self._file_clear_btn) box_file.add(box_button_file) box_file.add(box_param) boxVertical.add(box_file) regex_column_names = [ "Type", "Name", "Regex", "Start at offset", "End at offset", ] #clear target.json with open("target.json", "w") as f: pass data = [] self.target_table_model = DefaultTableModel(data, regex_column_names) self.target_table = JTable(self.target_table_model) self.target_table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF) column_model = self.target_table.getColumnModel() for count in xrange(column_model.getColumnCount()): column = column_model.getColumn(count) column.setPreferredWidth(100) self.target_table.preferredScrollableViewportSize = Dimension(500, 70) self.target_table.setFillsViewportHeight(True) callbacks.customizeUiComponent(self.target_table) callbacks.customizeUiComponent(boxVertical) table_panel = swing.Box.createVerticalBox() table_panel.add(JScrollPane(self.target_table)) box_top.add(table_panel) self._jScrollPaneOut = JScrollPane() #self._split_main.setBottomComponent(self._jScrollPaneOut) self._split_main.setBottomComponent(self._text_editor.getComponent()) self._split_main.setTopComponent(box_top) self._split_main.setDividerLocation(450) callbacks.customizeUiComponent(self._split_main) callbacks.addSuiteTab(self) return def getTabCaption(self): return "CRH" def getUiComponent(self): return self._split_main def createMenuItems(self, invocation): menu = [] ctx = invocation.getInvocationContext() menu.append( swing.JMenuItem("Send to CRH", None, actionPerformed=lambda x, inv=invocation: self. menu_action(inv))) return menu if menu else None # # Implementation of Menu Action # def menu_action(self, invocation): try: invMessage = invocation.getSelectedMessages() message = invMessage[0].getResponse() res_info = self.helpers.analyzeResponse(message) send_res = message.tostring() self._text_editor.setText(send_res) except: print('Failed to add data to CRH tab.') # # Implementation of event action # def actionPerformed(self, actionEvent): # onclick add button of extract from regex group if actionEvent.getSource() is self._add_btn: start, end = self._text_editor.getSelectionBounds() value = None regex = None item = self._dropdown.getSelectedItem() param = self._jTextIn_param.getText() if len(param) is 0: self._param_error.setVisible(True) return self._param_error.setVisible(False) is_selected = self._is_use_regex.isSelected() if is_selected: start = None end = None regex = self._jTextIn_regex.getText() if len(regex) is 0: self._regex_error.setVisible(True) return req = self._text_editor.getText() try: pattern = re.compile(regex) match = pattern.search(req) value = match.group(1) if match else None if value is None: raise IndexError except IndexError: self._regex_error.setVisible(True) return self._regex_error.setVisible(False) data = [ item, param, regex, start, end, ] self.target_table_model.addRow(data) with open("target.json", "r+") as f: try: json_data = json.load(f) except ValueError: json_data = dict() if is_selected: data = { param: [ item, regex, ] } else: data = { param: [ item, start, end, ] } json_data.update(data) self.write_file(f, json.dumps(json_data)) # onclick remove button of extract from regex group if actionEvent.getSource() is self._remove_btn: rowno = self.target_table.getSelectedRow() if rowno != -1: column_model = self.target_table.getColumnModel() param_name = self.target_table_model.getValueAt(rowno, 1) start = self.target_table_model.getValueAt(rowno, 3) self.target_table_model.removeRow(rowno) with open("target.json", 'r+') as f: try: json_data = json.load(f) except ValueError: json_data = dict() for key, value in json_data.items(): if value[1] == start and key == param_name: try: del json_data[key] except IndexError: print('Error: {0}: No such json key.'.format( key)) self.write_file(f, json.dumps(json_data)) # onclick load button of payload sets if actionEvent.getSource() is self._file_load_btn: #clear table self.remove_all(self.file_table_model) self.current_column_id = 0 target_param = self._file_param_text.getText() item = self._file_dropdown.getSelectedItem() if len(target_param) == 0: self._error_message.setVisible(True) return self._error_message.setVisible(False) chooser = JFileChooser() chooser.showOpenDialog(actionEvent.getSource()) file_path = chooser.getSelectedFile().getAbsolutePath() with open(file_path, 'r') as f: while True: line = f.readline().strip() if not line: break data = [ item, target_param, line, ] self.file_table_model.addRow(data) with open('target.json', 'r+') as f: try: json_data = json.load(f) except ValueError: json_data = dict() json_data.update({target_param: [ item, 'Set payload', ]}) self.write_file(f, json.dumps(json_data)) # onclick clear button of payload sets if actionEvent.getSource() is self._file_clear_btn: self.remove_all(self.file_table_model) self.current_column_id = 0 with open("target.json", 'r+') as f: try: json_data = json.load(f) except: json_data = dict() for key, value in json_data.items(): if isinstance(value[1], unicode): if value[1].encode('utf-8') == 'Set payload': try: del json_data[key] except IndexError: print('Error: {0}: No such json key.'.format( key)) self.write_file(f, json.dumps(json_data)) # # Implementaion of ISessionHandlingAction # def getActionName(self): return "custom request handler" def performAction(self, current_request, macro_items): if len(macro_items) == 0: return # extract the response headers final_response = macro_items[len(macro_items) - 1].getResponse() if final_response is None: return req = self.helpers.analyzeRequest(current_request) try: with open('target.json', 'r') as f: read_data = f.read() self.read_data = json.loads(read_data) except ValueError: sys.stderr.write('Error: json.loads()') return for key, value in self.read_data.items(): if value[0] == 'JSON': self.set_json_parameter(current_request, final_response, key, value) elif value[0] == 'Header': self.set_header(current_request, final_response, key, value) def set_json_parameter(self, current_request, final_response, key, value): req = self.helpers.analyzeRequest(current_request) if IRequestInfo.CONTENT_TYPE_JSON != req.getContentType(): return False body = current_request.getRequest()[req.getBodyOffset():].tostring() json_data = json.loads(body, object_pairs_hook=collections.OrderedDict) target_keys = filter(lambda x: x == key, json_data.keys()) if not target_keys: return req_data = json_data column_model = self.file_table.getColumnModel() row_count = self.file_table_model.getRowCount() for key in target_keys: if value[-1] == 'Set payload': if row_count > self.current_column_id: req_value = self.file_table_model.getValueAt( self.current_column_id, 2) self.current_column_id += 1 else: # No selected regex if len(value) > 2: start, end = value[1:] req_value = final_response[start:end].tostring() else: regex = value[1] match = re.search(regex, final_response.tostring()) req_value = match.group(1) if match else None req_data[key] = req_value req = current_request.getRequest() json_data_start = self.helpers.indexOf(req, bytearray(body), False, 0, len(req)) # glue together header + customized json of request current_request.setRequest( req[0:json_data_start] + self.helpers.stringToBytes(json.dumps(req_data))) def set_header(self, current_request, final_response, key, value): req = self.helpers.analyzeRequest(current_request) headers = req.getHeaders() target_keys = [] for header in headers: if header.startswith(key): target_keys += [key] if not target_keys: return column_model = self.file_table.getColumnModel() row_count = self.file_table_model.getRowCount() req = current_request.getRequest() for key in target_keys: if value[-1] == 'Set payload': if row_count > self.current_column_id: req_value = self.file_table_model.getValueAt( self.current_column_id, 2) self.current_column_id += 1 else: # No selected regex if len(value) > 2: start, end = value[1:] req_value = final_response[start:end].tostring() else: regex = value[1] match = re.search(regex, final_response.string()) req_value = match.group(1) if match else None key_start = self.helpers.indexOf(req, bytearray(key.encode('utf-8')), False, 0, len(req)) key_end = self.helpers.indexOf(req, bytearray('\r\n'), False, key_start, len(req)) keylen = len(key) # glue together first line + customized hedaer + rest of request current_request.setRequest( req[0:key_start] + self.helpers.stringToBytes("%s: %s" % (key.encode('utf-8'), req_value)) + req[key_end:]) # # Implementation of function for Remove all for specific table data # def remove_all(self, model): count = model.getRowCount() for i in xrange(count): model.removeRow(0) # # Implementaion of function for write data for specific file # def write_file(self, f, data): f.seek(0) f.write(data) f.truncate() return