def buildRequestTable(self, state, callbacks): """ Builds the request list on the results page on the right. """ splitpane = JSplitPane() splitpane.setDividerLocation(1000) endpointTable = Table(state.endpointTableModel) endpointTable.setDefaultRenderer(Class.forName('java.lang.Object'), CellHighlighterRenderer(state)) endpointTable.getColumnModel().getColumn(0).setPreferredWidth(15) endpointTable.getColumnModel().getColumn(1).setPreferredWidth(500) endpointTable.setAutoCreateRowSorter(True) endpointTable.addMouseListener(TableMouseAdapter()) endpointView = JScrollPane(endpointTable) callbacks.customizeUiComponent(endpointTable) callbacks.customizeUiComponent(endpointView) requestTable = Table(state.requestTableModel) requestTable.getColumnModel().getColumn(0).setPreferredWidth(500) requestView = JScrollPane(requestTable) callbacks.customizeUiComponent(requestTable) callbacks.customizeUiComponent(requestView) splitpane.setLeftComponent(endpointView) splitpane.setRightComponent(requestView) return splitpane
def initGui(self): def make_game_selector(): self.gameChanger = False def dbChange(evt): if evt.source.text: self.gamedb = GameDB(evt.source.text) self.gameChanger = True def idChange(evt): if evt.source.text: self.gameid = evt.source.text self.gameChanger = True def turnChange(evt): if evt.source.text: self.turnid = evt.source.text self.gameChanger = True selector = JPanel() selector.add(JLabel("DB:")) selector.add(textfield(self.gamedb.dbfile, dbChange)) selector.add(JLabel("Game ID:")) selector.add(textfield(self.gameid, idChange)) selector.add(JLabel("Turn ID:")) selector.add(textfield(self.turnid, turnChange)) return JScrollPane(selector) def make_content_panel(): self.contentPanel = JPanel(GridLayout(1, 0, 5, 5)) self.render() return JScrollPane(self.contentPanel) def save(self, txt, filename): pass def make_code_editor(): import inspect panel = JPanel(BorderLayout(2, 2)) self.codeArea = JTextArea() self.codeArea.text = self.scoringModule and inspect.getsource( self.scoringModule) or "" panel.add(JScrollPane(self.codeArea), BorderLayout.CENTER) return panel self.frame.contentPane.add(make_game_selector(), BorderLayout.NORTH) # self.frame.contentPane.add(make_content_panel(), BorderLayout.WEST) # self.frame.contentPane.add(make_code_editor(), BorderLayout.CENTER) pane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, make_content_panel(), make_code_editor()) pane.setDividerLocation(self.frame.width / 2) self.frame.contentPane.add(pane) reloadButton = JButton("Reload") def reload(evt): self.reload() reloadButton.addActionListener(reload) self.frame.contentPane.add(reloadButton, BorderLayout.SOUTH)
class FileView: """ SplitPane containing an editoresque (Sublime-alike) filetree+editor widget """ def __init__(self, dir=None, filetree_label=None, texteditor_factory=None): if not dir: dir = os.getcwd() self._filetree = FileTree(dir=dir, label=filetree_label) self._payloadview = PayloadView(texteditor_factory=texteditor_factory) self.this = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, self._filetree.this, self._payloadview.this) self.this.setOneTouchExpandable(True) self._filetree.add_tree_selection_listener(self._tree_listener) self.this.getRightComponent().setVisible(False) def _tree_listener(self, e): """ Listen for tree selection and fill the payloadview :param e: unused :return: None """ try: fpath = os.path.join(*[str(p) for p in e.getPath().getPath()][1:]) if fpath.endswith('.html'): self.this.getRightComponent().setVisible(False) return with open(fpath, 'r') as f: payload = f.read() self._payloadview.set_editable(True) self._payloadview.refresh(payload) self.this.getRightComponent().setVisible(True) self.this.setDividerLocation(0.25) except IOError: pass def addTreeListener(self, action): """ Add a new Tree ActionListener :param action: actionListener lambda :return: """ self._filetree.add_tree_selection_listener(action) def addPayloadListener(self, action): """ Add a new PayloadView Listener :param action: actionListener lambda :return: """ self._payloadview.add_listener(action) def refresh(self): self._filetree.refresh()
def initGui(self): def make_game_selector(): self.gameChanger = False def dbChange(evt): if evt.source.text: self.gamedb = GameDB(evt.source.text) self.gameChanger = True def idChange(evt): if evt.source.text: self.gameid = evt.source.text self.gameChanger = True def turnChange(evt): if evt.source.text: self.turnid = evt.source.text self.gameChanger = True selector = JPanel() selector.add(JLabel("DB:")) selector.add(textfield(self.gamedb.dbfile, dbChange)) selector.add(JLabel("Game ID:")) selector.add(textfield(self.gameid, idChange)) selector.add(JLabel("Turn ID:")) selector.add(textfield(self.turnid, turnChange)) return JScrollPane(selector) def make_content_panel(): self.contentPanel = JPanel(GridLayout(1, 0, 5, 5)) self.render() return JScrollPane(self.contentPanel) def save(self, txt, filename): pass def make_code_editor(): import inspect panel = JPanel(BorderLayout(2,2)) self.codeArea = JTextArea() self.codeArea.text = self.scoringModule and inspect.getsource(self.scoringModule) or "" panel.add(JScrollPane(self.codeArea), BorderLayout.CENTER) return panel self.frame.contentPane.add(make_game_selector(), BorderLayout.NORTH) # self.frame.contentPane.add(make_content_panel(), BorderLayout.WEST) # self.frame.contentPane.add(make_code_editor(), BorderLayout.CENTER) pane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, make_content_panel(), make_code_editor()) pane.setDividerLocation(self.frame.width/2) self.frame.contentPane.add(pane) reloadButton = JButton("Reload") def reload(evt): self.reload() reloadButton.addActionListener(reload) self.frame.contentPane.add(reloadButton, BorderLayout.SOUTH)
def run(self): #----------------------------------------------------------------------- # Size the frame to use 1/2 of the screen #----------------------------------------------------------------------- screenSize = Toolkit.getDefaultToolkit().getScreenSize() frameSize = Dimension(screenSize.width >> 1, screenSize.height >> 1) frame = JFrame('javadocInfo', size=frameSize, defaultCloseOperation=JFrame.EXIT_ON_CLOSE) #----------------------------------------------------------------------- # Reposition the frame to be in the center of the screen #----------------------------------------------------------------------- frame.setLocation((screenSize.width - frameSize.width) >> 1, (screenSize.height - frameSize.height) >> 1) #----------------------------------------------------------------------- # Initialize the list to have exactly 1 element #----------------------------------------------------------------------- self.List = JList(['One moment please...'], valueChanged=self.pick, selectionMode=ListSelectionModel.SINGLE_SELECTION) #----------------------------------------------------------------------- # Put the List in a ScrollPane and place it in the middle of a pane #----------------------------------------------------------------------- pane = JPanel(layout=BorderLayout()) pane.add(JScrollPane(self.List), BorderLayout.CENTER) #----------------------------------------------------------------------- # Add a TextField [for the URL of the selected entry] at the bottom #----------------------------------------------------------------------- self.msg = JTextField() pane.add(self.msg, BorderLayout.SOUTH) #----------------------------------------------------------------------- # Add the pane and a scrollable TextArea to a SplitPane in the frame #----------------------------------------------------------------------- self.area = JTextArea() sPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, pane, JScrollPane(self.area), propertyChange=self.propChange) sPane.setDividerLocation(234) frame.add(sPane) #----------------------------------------------------------------------- # Create a separate thread to locate & proces the remote URL #----------------------------------------------------------------------- self.Links = {} # Initialize the Links dictionary soupTask( self.List, # The visible JList instance self.msg, # The message area (JTextField) JAVADOC_URL, # Remote web page URL to be processed self.Links # Dictionary of links found ).execute() frame.setVisible(1)
def buildMessageViewer(self, state, callbacks): """ Builds the panel that allows users to view requests on the results page. Args: state: the state object. callbacks: the burp callbacks object. """ tabs = JTabbedPane() original = JSplitPane() original.setDividerLocation(1000) modified = JSplitPane() modified.setDividerLocation(1000) originalRequestEditor = MessageEditorController(state, "original") repeatedRequestEditor = MessageEditorController(state, "repeated") state.originalRequestViewer = callbacks.createMessageEditor( originalRequestEditor, False) state.originalResponseViewer = callbacks.createMessageEditor( originalRequestEditor, False) state.repeatedRequestViewer = callbacks.createMessageEditor( repeatedRequestEditor, False) state.repeatedResponseViewer = callbacks.createMessageEditor( repeatedRequestEditor, False) original.setLeftComponent(state.originalRequestViewer.getComponent()) original.setRightComponent(state.originalResponseViewer.getComponent()) modified.setLeftComponent(state.repeatedRequestViewer.getComponent()) modified.setRightComponent(state.repeatedResponseViewer.getComponent()) tabs.addTab("Original", original) tabs.addTab("Modified", modified) return tabs
class MainPanel(): """Represents the converted frame from NetBeans.""" # default issue to populate the panel with defaultIssue = Issue(name="Name", severity="Critical", host="Host", path="Path", description="Description", remediation="", reqResp=RequestResponse(request="default request", response="default response")) def loadPanel(self, issue): # type: (Issue) -> () """Populates the panel with issue.""" if issue is None: return # check if the input is the correct object assert isinstance(issue, Issue) # add selected issue to the panel to enable right-click stuff. self.selectedIssue = issue # set textfields and textareas self.textName.text = issue.name self.textHost.text = issue.host self.textPath.text = issue.path self.textAreaDescription.text = issue.description self.textAreaRemediation.text = issue.remediation self.textSeverity.text = issue.severity # request and response tabs self.panelRequest.setMessage(issue.getRequest(), True) self.panelResponse.setMessage(issue.getResponse(), False) # button actions def newIssueAction(self, event): """Pops up a frame to add a new issue.""" frm = NewIssueDialog(callbacks=self.callbacks, title="New Issue") frm.display(self) def gotNewIssue(self, issue): """got a new issue.""" self.tableIssue.addRow(issue) def editIssue(self, index, issue): """Issue has been edited.""" self.tableIssue.editRow(index, issue) def deleteIssueAction(self, event): """Delete the currently selected issue.""" # this is the button # btn = event.getSource() row = self.tableIssue.getTableSelectedRow() # YOLO self.tableIssue.deleteRow(row) # it works! def exportAction(self, event): """Export everything in the table to a file.""" lastDir = "" try: # load the last used directory # this will probably change as we will use a base64 encoded json as the complete config? lastDir = self.callbacks.loadExtensionSetting("lastDir") except: # if there is not a last used directory in the settings, continue pass from Utils import saveFileDialog, writeFile selectedFile, usedDirectory = saveFileDialog(parent=self.panel, startingDir=lastDir, title="Export Issues", extension="json") if selectedFile is not None: # write to the file writeFile(selectedFile.getAbsolutePath(), self.tableIssue.exportIssues()) if usedDirectory is not None: # overwrite the last used directory self.callbacks.saveExtensionSetting("lastDir", usedDirectory) def importAction(self, event): """Import a file to the table.""" lastDir = "" try: # load the last used directory # this will probably change as we will use a base64 encoded json as the complete config? lastDir = self.callbacks.loadExtensionSetting("lastDir") except: # if there is not a last used directory in the settings, continue pass from Utils import openFileDialog selectedFile, usedDirectory = openFileDialog(parent=self.panel, startingDir=lastDir, title="Import Issues", extension="json") # save the last directory self.callbacks.saveExtensionSetting("lastDir", usedDirectory) fi = open(selectedFile.getAbsolutePath(), "r") # read the file and create a list of Issues import json # newIssues = json.load(fi, object_hook=dictToIssue) # problem here is object_hook runs for every single object so newIssues # will have internal objects, even if we tag them from RequestResponse import RequestResponse, HttpService from base64 import b64decode issuesArray = json.load(fi) # now issuesArray is an array of dicts. # manual JSON deserialization - move this to a method/function? # also think about what happens if dictionaries are missing items newIssues = list() for eachissue in issuesArray: # now we have each issue # what if dictionaries are missing items? ht = HttpService( host=eachissue["reqResp"]["httpService"]["host"], port=eachissue["reqResp"]["httpService"]["port"], protocol=eachissue["reqResp"]["httpService"]["protocol"]) rr = RequestResponse( request=b64decode(eachissue["reqResp"]["request"]), response=b64decode(eachissue["reqResp"]["response"]), comment=eachissue["reqResp"]["comment"], highlight=eachissue["reqResp"]["highlight"], httpService=ht) iss = Issue(name=eachissue["name"], severity=eachissue["severity"], host=eachissue["host"], path=eachissue["path"], description=eachissue["description"], remediation=eachissue["remediation"], reqResp=rr) # iss = Issue() # rr = RequestResponse() # ht = HttpService() newIssues.append(iss) # clear the table self.tableIssue.clear() # add the issues to the table # for iss in newIssues: # self.tableIssue.addRow(iss) self.tableIssue.populate(newIssues) def newIssueFromBurp(self, invocation): """Create a New Issue from the context menu.""" from Utils import getPath, bytesToString, burpToolName reqResp = invocation.getSelectedMessages()[0] host = str(reqResp.getHttpService()) path = getPath(self.callbacks, reqResp) convertedReqResp = RequestResponse() convertedReqResp.fromIHttpRequestResponse(reqResp) tmpIssue = Issue(host=host, path=path, reqResp=convertedReqResp) # change the title to "New Issue from [TOOL]"? frameTitle = "New Issue from %s" % (burpToolName( invocation.getToolFlag())) frm = NewIssueDialog(callbacks=self.callbacks, issue=tmpIssue, title=frameTitle # , modality="application" ) frm.display(self) # FOCUS! frm.requestFocus() # print self.callbacks.getHelpers().bytesToString(reqResp[0].getRequest()) # mostly converted generated code def __init__(self, callbacks, table=None): self.callbacks = callbacks self.jScrollPane1 = JScrollPane() self.jPanel1 = JPanel() self.labelName = JLabel("Name") self.textName = JTextField() self.labelSeverity = JLabel("Severity") self.textSeverity = JTextField() self.labelHost = JLabel("Host") self.labelPath = JLabel("Path") self.textHost = JTextField() self.textPath = JTextField() self.tabIssue = JTabbedPane() self.textAreaDescription = JTextArea() self.textAreaRemediation = JTextArea() # JScrollPanes to hold the two jTextAreas # put the textareas in JScrollPanes self.jsPaneDescription = JScrollPane(self.textAreaDescription) self.jsPaneRemediation = JScrollPane(self.textAreaRemediation) self.panelRequest = self.callbacks.createMessageEditor(None, False) self.panelResponse = self.callbacks.createMessageEditor(None, False) self.loadPanel(self.defaultIssue) # buttons self.buttonNewIssue = JButton("New Issue", actionPerformed=self.newIssueAction) self.buttonDeleteIssue = JButton( "Delete Issue", actionPerformed=self.deleteIssueAction) self.buttonImport = JButton("Import", actionPerformed=self.importAction) self.buttonExport = JButton("Export", actionPerformed=self.exportAction) if table is not None: self.tableIssue = table else: from IssueTable import IssueTable self.tableIssue = IssueTable() # wrap the table in a scrollpane self.jScrollPane1.setViewportView(self.tableIssue) # top panel containing the table from java.awt import Color self.jPanel1.setBorder(BorderFactory.createLineBorder(Color(0, 0, 0))) # create the labels and textfields self.textName.editable = False self.textName.setBackground(Color.LIGHT_GRAY) self.textSeverity.editable = False self.textSeverity.setBackground(Color.LIGHT_GRAY) self.textHost.editable = False self.textHost.setBackground(Color.LIGHT_GRAY) self.textPath.editable = False self.textPath.setBackground(Color.LIGHT_GRAY) # description textarea self.textAreaDescription.editable = False self.textAreaDescription.setLineWrap(True) self.textAreaDescription.setWrapStyleWord(True) self.tabIssue.addTab("Description", self.jsPaneDescription) # remediation textarea self.textAreaRemediation.editable = False self.textAreaRemediation.setLineWrap(True) self.textAreaRemediation.setWrapStyleWord(True) self.tabIssue.addTab("Remediation", self.jsPaneRemediation) # request tab self.panelRequest.setMessage("", True) self.tabIssue.addTab("Request", self.panelRequest.getComponent()) # response tab self.panelResponse.setMessage("", False) self.tabIssue.addTab("Response", self.panelResponse.getComponent()) # from java.lang import Short # jpanel1 is the bottom panel jPanel1Layout = GroupLayout(self.jPanel1) self.jPanel1.setLayout(jPanel1Layout) jPanel1Layout.setHorizontalGroup( # GroupLayout.Alignment.CENTER centers the group, in this case it # centers the buttons jPanel1Layout.createParallelGroup( GroupLayout.Alignment.CENTER ).addGroup(jPanel1Layout.createSequentialGroup().addContainerGap( ).addGroup( jPanel1Layout.createParallelGroup( GroupLayout.Alignment.LEADING). addGroup(jPanel1Layout.createSequentialGroup().addGroup( jPanel1Layout.createParallelGroup( GroupLayout.Alignment.TRAILING).addComponent( self.labelHost).addComponent(self.labelName) ).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED).addGroup( jPanel1Layout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( jPanel1Layout.createSequentialGroup( ).addComponent(self.textName).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED). addComponent( self.labelSeverity).addPreferredGap( LayoutStyle.ComponentPlacement. RELATED).addComponent( self.textSeverity, GroupLayout.PREFERRED_SIZE, 186, GroupLayout.PREFERRED_SIZE)). addGroup( jPanel1Layout.createSequentialGroup().addComponent( self.textHost, GroupLayout.PREFERRED_SIZE, 330, GroupLayout.PREFERRED_SIZE).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED ).addComponent(self.labelPath).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED). addComponent(self.textPath)))).addComponent( self.tabIssue)).addContainerGap() ).addGroup( jPanel1Layout.createSequentialGroup().addComponent( self.buttonNewIssue).addComponent( self.buttonDeleteIssue).addComponent( self.buttonImport).addComponent( self.buttonExport))) # link size of buttons from javax.swing import SwingConstants jPanel1Layout.linkSize(SwingConstants.HORIZONTAL, [ self.buttonDeleteIssue, self.buttonExport, self.buttonImport, self.buttonNewIssue ]) jPanel1Layout.setVerticalGroup(jPanel1Layout.createParallelGroup( ).addGroup( jPanel1Layout.createSequentialGroup().addContainerGap().addGroup( jPanel1Layout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( self.labelName).addComponent( self.textName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addComponent( self.labelSeverity).addComponent( self.textSeverity, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) ).addPreferredGap(LayoutStyle.ComponentPlacement.RELATED).addGroup( jPanel1Layout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( self.textHost, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addComponent( self.labelPath).addComponent( self.textPath, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addComponent( self.labelHost)).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED) .addComponent(self.tabIssue).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED).addGroup( jPanel1Layout.createParallelGroup().addComponent( self.buttonNewIssue).addComponent( self.buttonDeleteIssue).addComponent( self.buttonImport).addComponent( self.buttonExport)).addContainerGap())) # create the main panel self.panel = JSplitPane(JSplitPane.VERTICAL_SPLIT) # set the top component self.panel.leftComponent = self.jScrollPane1 self.panel.rightComponent = self.jPanel1 self.panel.setDividerLocation(150)
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
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, IHttpListener, IMessageEditorController, AbstractTableModel, IContextMenuFactory, IHttpRequestResponseWithMarkers, ITextEditor): def registerExtenderCallbacks(self, callbacks): self._callbacks = callbacks #Initialize callbacks to be used later self._helpers = callbacks.getHelpers() callbacks.setExtensionName("Trishul") self._log = ArrayList() #_log used to store our outputs for a URL, which is retrieved later by the tool self._lock = Lock() #Lock is used for locking threads while updating logs in order such that no multiple updates happen at once self.intercept = 0 self.FOUND = "Found" self.CHECK = "Possible! Check Manually" self.NOT_FOUND = "Not Found" #Static Values for output #Initialize GUI self.issuesTab() self.advisoryReqResp() self.configTab() self.tabsInit() self.definecallbacks() print("Thank You for Installing Trishul") return # #Initialize Issues Tab displaying the JTree # def issuesTab(self): self.root = DefaultMutableTreeNode('Issues') frame = JFrame("Issues Tree") self.tree = JTree(self.root) self.rowSelected = '' self.tree.addMouseListener(mouseclick(self)) self.issuepanel = JScrollPane() self.issuepanel.setPreferredSize(Dimension(300,450)) self.issuepanel.getViewport().setView((self.tree)) frame.add(self.issuepanel,BorderLayout.CENTER) # #Adding Issues to Issues TreePath # def addIssues(self, branch, branchData=None): if branchData == None: branch.add(DefaultMutableTreeNode('No valid data')) else: for item in branchData: branch.add(DefaultMutableTreeNode(item)) # #Initialize the Config Tab to modify tool settings # def configTab(self): Config = JLabel("Config") self.startButton = JToggleButton("Intercept Off", actionPerformed=self.startOrStop) self.startButton.setBounds(40, 30, 200, 30) self.autoScroll = JCheckBox("Auto Scroll") self.autoScroll.setBounds(40, 80, 200, 30) self.xsscheck = JCheckBox("Detect XSS") self.xsscheck.setSelected(True) self.xsscheck.setBounds(40, 110, 200, 30) self.sqlicheck = JCheckBox("Detect SQLi") self.sqlicheck.setSelected(True) self.sqlicheck.setBounds(40, 140, 200, 30) self.ssticheck = JCheckBox("Detect SSTI") self.ssticheck.setSelected(True) self.ssticheck.setBounds(40, 170, 200, 30) self.blindxss = JCheckBox("Blind XSS") self.blindxss.setBounds(40, 200, 200, 30) self.BlindXSSText = JTextArea("", 5, 30) scrollbxssText = JScrollPane(self.BlindXSSText) scrollbxssText.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED) scrollbxssText.setBounds(40, 250, 400, 110) self.configtab = JPanel() self.configtab.setLayout(None) self.configtab.setBounds(0, 0, 300, 300) self.configtab.add(Config) self.configtab.add(self.startButton) self.configtab.add(self.autoScroll) self.configtab.add(self.xsscheck) self.configtab.add(self.sqlicheck) self.configtab.add(self.ssticheck) self.configtab.add(self.blindxss) self.configtab.add(scrollbxssText) # #Turn Intercept from Proxy on or off # def startOrStop(self, event): if self.startButton.getText() == "Intercept Off": self.startButton.setText("Intercept On") self.startButton.setSelected(True) self.intercept = 1 else: self.startButton.setText("Intercept Off") self.startButton.setSelected(False) self.intercept = 0 # #Intialize the Advisory, Request and Response Tabs # def advisoryReqResp(self): self.textfield = JEditorPane("text/html", "") self.kit = HTMLEditorKit() self.textfield.setEditorKit(self.kit) self.doc = self.textfield.getDocument() self.textfield.setEditable(0) self.advisorypanel = JScrollPane() self.advisorypanel.getVerticalScrollBar() self.advisorypanel.setPreferredSize(Dimension(300,450)) self.advisorypanel.getViewport().setView((self.textfield)) self.selectedreq = [] self._requestViewer = self._callbacks.createMessageEditor(self, False) self._responseViewer = self._callbacks.createMessageEditor(self, False) self._texteditor = self._callbacks.createTextEditor() self._texteditor.setEditable(False) # #Initialize Trishul Tabs # def tabsInit(self): self.logTable = Table(self) tableWidth = self.logTable.getPreferredSize().width self.logTable.getColumn("#").setPreferredWidth(Math.round(tableWidth / 50 * 0.1)) self.logTable.getColumn("Method").setPreferredWidth(Math.round(tableWidth / 50 * 3)) self.logTable.getColumn("URL").setPreferredWidth(Math.round(tableWidth / 50 * 40)) self.logTable.getColumn("Parameters").setPreferredWidth(Math.round(tableWidth / 50 * 1)) self.logTable.getColumn("XSS").setPreferredWidth(Math.round(tableWidth / 50 * 4)) self.logTable.getColumn("SQLi").setPreferredWidth(Math.round(tableWidth / 50 * 4)) self.logTable.getColumn("SSTI").setPreferredWidth(Math.round(tableWidth / 50 * 4)) self.logTable.getColumn("Request Time").setPreferredWidth(Math.round(tableWidth / 50 * 4)) self.tableSorter = TableRowSorter(self) self.logTable.setRowSorter(self.tableSorter) self._bottomsplit = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) self._bottomsplit.setDividerLocation(500) self.issuetab = JTabbedPane() self.issuetab.addTab("Config",self.configtab) self.issuetab.addTab("Issues",self.issuepanel) self._bottomsplit.setLeftComponent(self.issuetab) self.tabs = JTabbedPane() self.tabs.addTab("Advisory",self.advisorypanel) self.tabs.addTab("Request", self._requestViewer.getComponent()) self.tabs.addTab("Response", self._responseViewer.getComponent()) self.tabs.addTab("Highlighted Response", self._texteditor.getComponent()) self._bottomsplit.setRightComponent(self.tabs) self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) self._splitpane.setDividerLocation(450) self._splitpane.setResizeWeight(1) self.scrollPane = JScrollPane(self.logTable) self._splitpane.setLeftComponent(self.scrollPane) self.scrollPane.getVerticalScrollBar().addAdjustmentListener(autoScrollListener(self)) self._splitpane.setRightComponent(self._bottomsplit) # #Initialize burp callbacks # def definecallbacks(self): self._callbacks.registerHttpListener(self) self._callbacks.customizeUiComponent(self._splitpane) self._callbacks.customizeUiComponent(self.logTable) self._callbacks.customizeUiComponent(self.scrollPane) self._callbacks.customizeUiComponent(self._bottomsplit) self._callbacks.registerContextMenuFactory(self) self._callbacks.addSuiteTab(self) # #Menu Item to send Request to Trishul # def createMenuItems(self, invocation): responses = invocation.getSelectedMessages() if responses > 0: ret = LinkedList() requestMenuItem = JMenuItem("Send request to Trishul") for response in responses: requestMenuItem.addActionListener(handleMenuItems(self,response, "request")) ret.add(requestMenuItem) return ret return None # #Highlighting Response # def markHttpMessage( self, requestResponse, responseMarkString ): responseMarkers = None if responseMarkString: response = requestResponse.getResponse() responseMarkBytes = self._helpers.stringToBytes( responseMarkString ) start = self._helpers.indexOf( response, responseMarkBytes, False, 0, len( response ) ) if -1 < start: responseMarkers = [ array( 'i',[ start, start + len( responseMarkBytes ) ] ) ] requestHighlights = [array( 'i',[ 0, 5 ] )] return self._callbacks.applyMarkers( requestResponse, requestHighlights, responseMarkers ) def getTabCaption(self): return "Trishul" def getUiComponent(self): return self._splitpane # #Table Model to display URL's and results based on the log size # def getRowCount(self): try: return self._log.size() except: return 0 def getColumnCount(self): return 8 def getColumnName(self, columnIndex): data = ['#','Method', 'URL', 'Parameters', 'XSS', 'SQLi', "SSTI", "Request Time"] try: return data[columnIndex] except IndexError: return "" def getColumnClass(self, columnIndex): data = [Integer, String, String, Integer, String, String, String, String] try: return data[columnIndex] except IndexError: return "" #Get Data stored in log and display in the respective columns def getValueAt(self, rowIndex, columnIndex): logEntry = self._log.get(rowIndex) if columnIndex == 0: return rowIndex+1 if columnIndex == 1: return logEntry._method if columnIndex == 2: return logEntry._url.toString() if columnIndex == 3: return len(logEntry._parameter) if columnIndex == 4: return logEntry._XSSStatus if columnIndex == 5: return logEntry._SQLiStatus if columnIndex == 6: return logEntry._SSTIStatus if columnIndex == 7: return logEntry._req_time return "" def getHttpService(self): return self._currentlyDisplayedItem.getHttpService() def getRequest(self): return self._currentlyDisplayedItem.getRequest() def getResponse(self): return self._currentlyDisplayedItem.getResponse() #For Intercepted requests perform tests in scope def processHttpMessage(self, toolFlag, messageIsRequest, messageInf): if self.intercept == 1: if toolFlag == self._callbacks.TOOL_PROXY: if not messageIsRequest: requestInfo = self._helpers.analyzeRequest(messageInf) requeststr = requestInfo.getUrl() parameters = requestInfo.getParameters() param_new = [p for p in parameters if p.getType() != 2] if len(param_new) != 0: if self._callbacks.isInScope(URL(str(requeststr))): start_new_thread(self.sendRequestToTrishul,(messageInf,)) return # #Main processing of Trishul # def sendRequestToTrishul(self,messageInfo): request = messageInfo.getRequest() req_time = datetime.datetime.today() requestURL = self._helpers.analyzeRequest(messageInfo).getUrl() messageInfo = self._callbacks.makeHttpRequest(self._helpers.buildHttpService(str(requestURL.getHost()), int(requestURL.getPort()), requestURL.getProtocol() == "https"), request) resp_time = datetime.datetime.today() time_taken = (resp_time - req_time).total_seconds() response = messageInfo.getResponse() #initialozations of default value SQLiimp = self.NOT_FOUND SSTIimp = self.NOT_FOUND XSSimp = self.NOT_FOUND Comp_req = messageInfo requestInfo = self._helpers.analyzeRequest(messageInfo) self.content_resp = self._helpers.analyzeResponse(response) requestURL = requestInfo.getUrl() parameters = requestInfo.getParameters() requeststring = self._helpers.bytesToString(request) headers = requestInfo.getHeaders() #Used to obtain GET, POST and JSON parameters from burp api param_new = [p for p in parameters if p.getType() == 0 or p.getType() == 1 or p.getType() == 6] i = 0 xssflag=0 sqliflag=0 sstiflag=0 resultxss = [] resultsqli = [] resultssti = [] xssreqresp = [] sqlireqresp = [] sstireqresp = [] ssti_description = [] sqli_description = [] xss_description = [] for i in range(len(param_new)): name = param_new[i].getName() ptype = param_new[i].getType() param_value = param_new[i].getValue() #check XSS if ticked if self.xsscheck.isSelected(): score = 0 flag1 = 0 XSSimp = self.NOT_FOUND payload_array = ["<", ">", "\\\\'asd", "\\\\\"asd", "\\", "'\""] json_payload_array = ["<", ">", "\\\\'asd", "\\\"asd", "\\", "\'\\\""] payload_all = "" json_payload = "" rand_str = "testtest" for payload in payload_array: payload_all = payload_all+rand_str+payload payload_all = URLEncoder.encode(payload_all, "UTF-8") for payload in json_payload_array: json_payload = json_payload+rand_str+payload json_payload = URLEncoder.encode(json_payload, "UTF-8") if ptype == 0 or ptype == 1: new_paramters_value = self._helpers.buildParameter(name, payload_all, ptype) updated_request = self._helpers.updateParameter(request, new_paramters_value) else: jsonreq = re.search(r"\s([{\[].*?[}\]])$", requeststring).group(1) new = jsonreq.split(name+"\":",1)[1] if new.startswith('\"'): newjsonreq = jsonreq.replace(name+"\":\""+param_value,name+"\":\""+json_payload) else: newjsonreq = jsonreq.replace(name+"\":"+param_value,name+"\":\""+json_payload+"\"") updated_request = self._helpers.buildHttpMessage(headers, newjsonreq) attack = self.makeRequest(Comp_req, updated_request) response = attack.getResponse() response_str = self._helpers.bytesToString(response) xssreqresp.append(attack) if_found_payload = "" non_encoded_symbols = "" for check_payload in payload_array: if_found_payload = rand_str+check_payload if if_found_payload in response_str: non_encoded_symbols = non_encoded_symbols+"<br>"+check_payload.replace('<', '<') score = score+1 flag1 = 1 if score > 2: XSSimp = self.CHECK if score > 3: XSSimp = self.FOUND xssflag = self.checkBetterScore(score,xssflag) if non_encoded_symbols == " \\\\'asd": XSSimp = self.NOT_FOUND if non_encoded_symbols != '': xss_description.append("The Payload <b>" + payload_all.replace('<', '<') + "</b> was passed in the request for the paramater <b>" + self._helpers.urlDecode(name) + "</b>. Some Tags were observed in the output unfiltered. A payload can be generated with the observed tags.<br>Symbols not encoded for parameter <b>" + name + "</b>: " + non_encoded_symbols) else: xss_description.append("") else: XSSimp = "Disabled" resultxss.append(XSSimp) if self.sqlicheck.isSelected(): SQLiimp = self.NOT_FOUND score = 0 value = "%27and%28select%2afrom%28select%28sleep%285%29%29%29a%29--" orig_time = datetime.datetime.today() if ptype == 0 or ptype == 1: new_paramters_value = self._helpers.buildParameter(name, value, ptype) updated_request = self._helpers.updateParameter(request, new_paramters_value) else: jsonreq = re.search(r"\s([{\[].*?[}\]])$", requeststring).group(1) new = jsonreq.split(name+"\":",1)[1] if new.startswith('\"'): newjsonreq = jsonreq.replace(name+"\":\""+param_value,name+"\":\""+value) else: newjsonreq = jsonreq.replace(name+"\":"+param_value,name+"\":\""+value+"\"") updated_request = self._helpers.buildHttpMessage(headers, newjsonreq) attack1 = self.makeRequest(Comp_req, updated_request) response1 = attack1.getResponse() new_time = datetime.datetime.today() response_str1 = self._helpers.bytesToString(response1) sqlireqresp.append(attack1) diff = (new_time - orig_time).total_seconds() if (diff - time_taken) > 3: score = 4 self.error_array = ["check the manual that corresponds to your", "You have an error", "syntax error", "SQL syntax", "SQL statement", "ERROR:", "Error:", "MySQL","Warning:","mysql_fetch_array()"] found_text = "" for error in self.error_array: if error in response_str1: found_text = found_text + error score = score + 1 if score > 1: SQLiimp = self.CHECK if score > 2: SQLiimp = self.FOUND sqliflag = self.checkBetterScore(score,sqliflag) if found_text != '': sqli_description.append("The payload <b>"+self._helpers.urlDecode(value)+"</b> was passed in the request for parameter <b>"+self._helpers.urlDecode(name)+"</b>. Some errors were generated in the response which confirms that there is an Error based SQLi. Please check the request and response for this parameter") elif (diff - time_taken) > 3: sqli_description.append("The payload <b>"+self._helpers.urlDecode(value)+"</b> was passed in the request for parameter <b>"+self._helpers.urlDecode(name)+"</b>. The response was in a delay of <b>"+str(diff)+"</b> seconds as compared to original <b>"+str(time_taken)+"</b> seconds. This indicates that there is a time based SQLi. Please check the request and response for this parameter") else: sqli_description.append("") else: SQLiimp = "Disabled" resultsqli.append(SQLiimp) if self.ssticheck.isSelected(): score = 0 SSTIimp = self.NOT_FOUND payload_array = ["${123*456}", "<%=123*567%>", "{{123*678}}"] json_payload_array = ["$\{123*456\}", "<%=123*567%>", "\{\{123*678\}\}"] payload_all = "" rand_str = "jjjjjjj" json_payload = "" for payload in payload_array: payload_all = payload_all+rand_str+payload for payload in json_payload_array: json_payload = json_payload+rand_str+payload payload_all = URLEncoder.encode(payload_all, "UTF-8") json_payload = URLEncoder.encode(json_payload, "UTF-8") if ptype == 0 or ptype == 1: new_paramters_value = self._helpers.buildParameter(name, payload_all, ptype) updated_request = self._helpers.updateParameter(request, new_paramters_value) else: jsonreq = re.search(r"\s([{\[].*?[}\]])$", requeststring).group(1) new = jsonreq.split(name+"\":",1)[1] if new.startswith('\"'): newjsonreq = jsonreq.replace(name+"\":\""+param_value,name+"\":\""+json_payload) else: newjsonreq = jsonreq.replace(name+"\":"+param_value,name+"\":\""+json_payload+"\"") updated_request = self._helpers.buildHttpMessage(headers, newjsonreq) attack = self.makeRequest(Comp_req, updated_request) response = attack.getResponse() response_str = self._helpers.bytesToString(response) self.expected_output = ["56088","69741","83394","3885","777777777777777"] for output in self.expected_output: if_found_payload = rand_str+output if if_found_payload in response_str: if output == self.expected_output[0]: sstireqresp.append(attack) ssti_description.append("Parameter <b>" + self._helpers.urlDecode(name) + "</b> is using <b>Java</b> Template<br>The value <b>" + payload_new + "</b> was passed which gave result as <b>56088</b>") score = 2 if output == self.expected_output[1]: sstireqresp.append(attack) ssti_description.append("Parameter <b>" + self._helpers.urlDecode(name) + "</b> is using <b>Ruby</b> Template<br>The value <b>" + payload_new + "</b> was passed which gave result as <b>69741</b>") score = 2 if output == self.expected_output[2]: payload_new = "{{5*'777'}}" json_payload_ssti = "\{\{5*'777'\}\}" payload = URLEncoder.encode("{{5*'777'}}", "UTF-8") json_ssti = URLEncoder.encode("\{\{5*'777'\}\}", "UTF-8") if ptype == 0 or ptype == 1: new_paramters = self._helpers.buildParameter(name, payload, ptype) ssti_updated_request = self._helpers.updateParameter(request, new_paramters) else: jsonreq = re.search(r"\s([{\[].*?[}\]])$", requeststring).group(1) new = jsonreq.split(name+"\":",1)[1] if new.startswith('\"'): newjsonreq = jsonreq.replace(name+"\":\""+param_value,name+"\":\""+json_ssti) else: newjsonreq = jsonreq.replace(name+"\":"+param_value,name+"\":\""+json_ssti+"\"") ssti_updated_request = self._helpers.buildHttpMessage(headers, newjsonreq) self.ssti_attack = self.makeRequest(Comp_req, ssti_updated_request) ssti_response = self.ssti_attack.getResponse() ssti_response_str = self._helpers.bytesToString(ssti_response) if self.expected_output[3] in ssti_response_str: sstireqresp.append(self.ssti_attack) ssti_description.append("Parameter <b>" + self._helpers.urlDecode(name) + "</b> is using <b>Twig</b> Template<br>The value <b>" + payload_new + "</b> was passed which gave result as <b>3885</b>") score = 2 elif self.expected_output[4] in ssti_response_str: sstireqresp.append(self.ssti_attack) self.responseMarkString = "777777777777777" ssti_description.append("Parameter <b>" + self._helpers.urlDecode(name) + "</b> is using <b>Jinja2</b> Template<br>The value <b>" + payload_new + "</b> was passed which gave result as <b>777777777777777</b>") score = 2 if score > 0: SSTIimp = self.CHECK if score > 1: SSTIimp = self.FOUND sstiflag = self.checkBetterScore(score,sstiflag) else: SSTIimp = "Disabled" resultssti.append(SSTIimp) if self.blindxss.isSelected(): blindxss_value = self.BlindXSSText.getText() if ptype == 0 or ptype == 1: new_paramters_value = self._helpers.buildParameter(name, blindxss_value, ptype) updated_request = self._helpers.updateParameter(request, new_paramters_value) else: jsonreq = re.search(r"\s([{\[].*?[}\]])$", requeststring).group(1) new = jsonreq.split(name+"\":",1)[1] if new.startswith('\"'): newjsonreq = jsonreq.replace(name+"\":\""+param_value,name+"\":\""+blindxss_value) else: newjsonreq = jsonreq.replace(name+"\":"+param_value,name+"\":\""+blindxss_value+"\"") updated_request = self._helpers.buildHttpMessage(headers, newjsonreq) attack = self.makeRequest(Comp_req, updated_request) if XSSimp != "Disabled": if xssflag > 3: XSSimp = self.FOUND elif xssflag > 2: XSSimp = self.CHECK else: XSSimp = self.NOT_FOUND if SSTIimp != "Disabled": if sstiflag > 1: SSTIimp = self.FOUND elif sstiflag > 0: SSTIimp = self.CHECK else: SSTIimp = self.NOT_FOUND if SQLiimp != "Disabled": if sqliflag > 3: SQLiimp = self.FOUND elif sqliflag > 2: SQLiimp = self.CHECK else: SQLiimp = self.NOT_FOUND self.addToLog(messageInfo, XSSimp, SQLiimp, SSTIimp, param_new, resultxss, resultsqli, resultssti, xssreqresp, sqlireqresp, sstireqresp , xss_description, sqli_description, ssti_description, req_time.strftime('%H:%M:%S %m/%d/%y')) # #Function used to check if the score originally and mentioned is better # def checkBetterScore(self, score, ogscore): if score > ogscore: ogscore = score return ogscore def makeRequest(self, messageInfo, message): request = messageInfo.getRequest() requestURL = self._helpers.analyzeRequest(messageInfo).getUrl() return self._callbacks.makeHttpRequest(self._helpers.buildHttpService(str(requestURL.getHost()), int(requestURL.getPort()), requestURL.getProtocol() == "https"), message) def addToLog(self, messageInfo, XSSimp, SQLiimp, SSTIimp, parameters, resultxss, resultsqli, resultssti, xssreqresp, sqlireqresp, sstireqresp, xss_description, sqli_description, ssti_description, req_time): requestInfo = self._helpers.analyzeRequest(messageInfo) method = requestInfo.getMethod() self._lock.acquire() row = self._log.size() self._log.add(LogEntry(self._callbacks.saveBuffersToTempFiles(messageInfo), requestInfo.getUrl(),method,XSSimp,SQLiimp,SSTIimp,req_time, parameters,resultxss, resultsqli, resultssti, xssreqresp, sqlireqresp, sstireqresp, xss_description, sqli_description, ssti_description)) # same requests not include again. SwingUtilities.invokeLater(UpdateTableEDT(self,"insert",row,row)) self._lock.release()
class View: def __init__(self): self.data = Data() self.checklist = self.data.get_checklist() self.issues = self.data.get_issues() self.set_checklist_tree() self.set_tree() self.set_pane() self.set_tabbed_panes() self.set_settings() self.set_tsl() def set_checklist(self, file_name): self.data.set_checklist(file_name) self.checklist = self.data.get_checklist() def get_checklist(self): return self.checklist def get_issues(self): return self.issues # TODO: Create the checklist dynamically for all nodes based on JSON structure # Creates a DefaultMutableTreeNode using the JSON file data def set_checklist_tree(self): self.checklist_tree = DefaultMutableTreeNode("HUNT - Methodology") for item in self.checklist: node = DefaultMutableTreeNode(item) self.checklist_tree.add(node) is_functionality = node.toString() == "Functionality" if is_functionality: functionality_node = node functionality = self.checklist["Functionality"] # TODO: Sort the functionality by name and by test name for functionality_name in functionality: tests = functionality[functionality_name]["tests"] node = DefaultMutableTreeNode(functionality_name) for test_name in tests: node.add(DefaultMutableTreeNode(test_name)) functionality_node.add(node) def get_checklist_tree(self): return self.checklist_tree # Creates a JTree object from the checklist def set_tree(self): self.tree = JTree(self.checklist_tree) self.tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION) def get_tree(self): return self.tree # TODO: Change to briefcase icon for brief, P1-P5 icons for vulns, # bullseye icon for Targets, etc # Create a JSplitPlane with a JTree to the left and JTabbedPane to right def set_pane(self): status = JTextArea() status.setLineWrap(True) status.setText("Nothing selected") self.status = status self.pane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(self.tree), JTabbedPane()) self.pane.setDividerLocation(310) self.pane.getLeftComponent().setMinimumSize(Dimension(310, 300)) def get_pane(self): return self.pane # Creates the tabs dynamically using data from the JSON file def set_tabbed_panes(self): functionality = self.checklist["Functionality"] self.tabbed_panes = {} for functionality_name in functionality: tests = functionality[functionality_name]["tests"] for test_name in tests: key = functionality_name + "." + test_name tabbed_pane = self.set_tabbed_pane(functionality_name, test_name) self.tabbed_panes[key] = self.tabbed_pane def get_tabbed_panes(self): return self.tabbed_panes # Creates a JTabbedPane for each vulnerability per functionality def set_tabbed_pane(self, functionality_name, test_name): description_tab = self.set_description_tab(functionality_name, test_name) bugs_tab = self.set_bugs_tab() resources_tab = self.set_resource_tab(functionality_name, test_name) notes_tab = self.set_notes_tab() self.tabbed_pane = JTabbedPane() self.tabbed_pane.add("Description", description_tab) self.tabbed_pane.add("Bugs", bugs_tab) self.tabbed_pane.add("Resources", resources_tab) self.tabbed_pane.add("Notes", notes_tab) # Creates the description panel def set_description_tab(self, fn, vn): description_text = str( self.checklist["Functionality"][fn]["tests"][vn]["description"]) description_textarea = JTextArea() description_textarea.setLineWrap(True) description_textarea.setText(description_text) description_panel = JScrollPane(description_textarea) return description_panel # TODO: Add functionality to remove tabs # Creates the bugs panel def set_bugs_tab(self): bugs_tab = JTabbedPane() return bugs_tab # Creates the resources panel def set_resource_tab(self, fn, vn): resource_urls = self.checklist["Functionality"][fn]["tests"][vn][ "resources"] resource_text = "" for url in resource_urls: resource_text = resource_text + str(url) + "\n" resource_textarea = JTextArea() resource_textarea.setLineWrap(True) resource_textarea.setWrapStyleWord(True) resource_textarea.setText(resource_text) resources_panel = JScrollPane(resource_textarea) return resources_panel def set_notes_tab(self): notes_textarea = JTextArea() return notes_textarea def set_tsl(self): self.tsl = TSL(self) self.tree.addTreeSelectionListener(self.tsl) return def get_tsl(self): return self.tsl def set_settings(self): self.settings = JPanel() layout = GroupLayout(self.settings) self.settings.setLayout(layout) layout.setAutoCreateGaps(True) load_file_button = JButton("Load JSON File") load_file_button.setActionCommand("load") load_file_button.addActionListener( SettingsAction(self, load_file_button, None)) save_file_button = JButton("Save JSON File") save_file_button.setActionCommand("save") save_file_button.addActionListener( SettingsAction(None, save_file_button, self.tabbed_panes)) horizontal_group1 = layout.createParallelGroup( GroupLayout.Alignment.LEADING) horizontal_group1.addComponent(load_file_button) horizontal_group1.addComponent(save_file_button) horizontal_group = layout.createSequentialGroup() horizontal_group.addGroup(horizontal_group1) layout.setHorizontalGroup(horizontal_group) vertical_group1 = layout.createParallelGroup( GroupLayout.Alignment.BASELINE) vertical_group1.addComponent(load_file_button) vertical_group2 = layout.createParallelGroup( GroupLayout.Alignment.BASELINE) vertical_group2.addComponent(save_file_button) vertical_group = layout.createSequentialGroup() vertical_group.addGroup(vertical_group1) vertical_group.addGroup(vertical_group2) layout.setVerticalGroup(vertical_group) def get_settings(self): return self.settings def set_request_tab_pane(self, request_response): raw_request = request_response.getRequest() request_body = StringUtil.fromBytes(raw_request) request_body = request_body.encode("utf-8") request_tab_textarea = JTextArea(request_body) request_tab_textarea.setLineWrap(True) return JScrollPane(request_tab_textarea) def set_response_tab_pane(self, request_response): raw_response = request_response.getResponse() response_body = StringUtil.fromBytes(raw_response) response_body = response_body.encode("utf-8") response_tab_textarea = JTextArea(response_body) response_tab_textarea.setLineWrap(True) return JScrollPane(response_tab_textarea) def set_bugs_tabbed_pane(self, request_tab, response_tab): bugs_tabbed_pane = JTabbedPane() bugs_tabbed_pane.add("Request", request_tab) bugs_tabbed_pane.add("Response", response_tab) return bugs_tabbed_pane
class AtfAreaView(JPanel): ''' Initializes the ATF (edit/model) view and sets its layout. ''' def __init__(self, controller): ''' Creates default empty text area in a panel for ATF edition. It has syntax highlighting based on the ATF parser (pyoracc). It also highlights line numbers where there are validations errors returned by the ORACC server. ''' # Give reference to controller to delegate action response self.controller = controller # Make text area occupy all available space and resize with parent # window self.setLayout(BorderLayout()) # Short hand for edit area and line numbers area self.edit_area = self.controller.edit_area self.line_numbers_area = self.controller.line_numbers_area # Create secondary text area for split view self.secondary_area = self.controller.secondary_area self.secondary_line_numbers = self.controller.secondary_line_numbers # Set undo/redo manager to edit area self.undo_manager = UndoManager() self.undo_manager.limit = 3000 self.edit_listener = AtfUndoableEditListener(self.undo_manager) self.edit_area.getDocument().addUndoableEditListener( self.edit_listener) # Sort out layout by synch-ing line numbers and text area and putting # only the text area in a scroll pane as indicated in the # TextLineNumber tutorial. self.edit_area.setPreferredSize(Dimension(1, 500)) self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.add(self.container, BorderLayout.CENTER) self.vert_scroll = self.container.getVerticalScrollBar() self.vert_scroll.addAdjustmentListener(atfAreaAdjustmentListener(self)) # Key listener that triggers syntax highlighting, etc. upon key release self.edit_area.addKeyListener(AtfAreaKeyListener(self)) # Also needed in secondary area: self.secondary_area.addKeyListener(AtfAreaKeyListener(self)) # Add a document listener to track changes to files docListener = atfAreaDocumentListener(self) self.edit_area.getDocument().addDocumentListener(docListener) # instance variable to store a record of the text contents prior to the # most recent change. Needed so that the different listeners can access # this to handle error line updating. self.oldtext = '' def toggle_split(self, split_orientation=None): ''' Clear ATF edit area and repaint chosen layout (splitscreen/scrollpane). ''' # Remove all existent components in parent JPanel self.removeAll() # Check what editor view to toggle self.setup_edit_area(split_orientation) # Revalitate is needed in order to repaint the components self.revalidate() self.repaint() def setup_edit_area(self, split_orientation=None): ''' Check if the ATF text area is being displayed in a split editor. If so, resets to normal JScrollPane. If not, splits the screen. ''' if isinstance(self.container, JSplitPane): # If Nammu is already displaying a split pane, reset to original # setup self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.container.setVisible(True) self.add(self.container, BorderLayout.CENTER) else: # If there is not a split pane, create both panels and setup view main_editor = JScrollPane(self.edit_area) main_editor.setRowHeaderView(self.line_numbers_area) secondary_editor = JScrollPane(self.secondary_area) secondary_editor.setRowHeaderView(self.secondary_line_numbers) self.container = JSplitPane(split_orientation, main_editor, secondary_editor) self.container.setDividerSize(5) self.container.setVisible(True) self.container.setDividerLocation(0.5) self.container.setResizeWeight(0.5) self.add(self.container, BorderLayout.CENTER) def get_viewport_carets(self): ''' Get the top left and bottom left caret position of the current viewport ''' extent = self.container.getViewport().getExtentSize() top_left_position = self.container.getViewport().getViewPosition() top_left_char = self.edit_area.viewToModel(top_left_position) bottom_left_position = Point(top_left_position.x, top_left_position.y + extent.height) bottom_left_char = self.edit_area.viewToModel(bottom_left_position) # Something has gone wrong. Assume that top_left should be at the start # of the file if top_left_char >= bottom_left_char: top_left_char = 0 # Get the text in the full edit area text = self.controller.edit_area.getText() # Pad the top of the viewport to capture up to the nearest header and # the bottom by 2 lines top_ch = self.controller.pad_top_viewport_caret(top_left_char, text) bottom_ch = self.controller.pad_bottom_viewport_caret( bottom_left_char, text) return top_ch, bottom_ch def refresh(self): ''' Restyle edit area using user selected appearance settings. ''' config = self.controller.controller.config # Create a new font with the new size font = set_font(config['edit_area_style']['fontsize']['user']) # Update the sytnax highlighter font params, so our changes are not # superceded self.controller.syntax_highlighter.font = font self.controller.syntax_highlighter.setup_attribs() attrs = self.controller.edit_area.getInputAttributes() StyleConstants.setFontSize(attrs, font.getSize()) # Get the Styledoc so we can update it doc = self.controller.edit_area.getStyledDocument() # Apply the new fontsize to the whole document doc.setCharacterAttributes(0, doc.getLength() + 1, attrs, False)
class View: def __init__(self, issues): self.json = issues.get_json() self.issues_object = issues self.issues = issues.get_issues() self.scanner_issues = issues.get_scanner_issues() self.scanner_panes = {} self.scanner_table_models = {} self.scanner_tables = {} self.is_scanner_panes = [] self.set_vuln_tree() self.set_tree() self.set_scanner_table_models() self.set_scanner_panes() self.set_pane() self.set_settings() self.set_tsl() def get_issues_object(self): return self.issues_object def set_callbacks(self, callbacks): self.callbacks = callbacks def set_helpers(self, helpers): self.helpers = helpers def get_helpers(self): return self.helpers def get_issues(self): return self.issues def get_scanner_issues(self): return self.scanner_issues def set_is_scanner_pane(self, scanner_pane): self.is_scanner_panes.append(scanner_pane) def get_is_scanner_pane(self, scanner_pane): for pane in self.get_is_scanner_panes(): if pane == scanner_pane: return True return False def get_is_scanner_panes(self): return self.is_scanner_panes def set_vuln_tree(self): self.vuln_tree = DefaultMutableTreeNode("HUNT Scanner") vulns = self.json["issues"] # TODO: Sort the functionality by name and by vuln class for vuln_name in sorted(vulns): vuln = DefaultMutableTreeNode(vuln_name) self.vuln_tree.add(vuln) parameters = self.json["issues"][vuln_name]["params"] for parameter in sorted(parameters): param_node = DefaultMutableTreeNode(parameter) vuln.add(param_node) self.vuln_tree.add(DefaultMutableTreeNode("Settings")) # Creates a JTree object from the checklist def set_tree(self): self.tree = JTree(self.vuln_tree) self.tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION) def get_tree(self): return self.tree def set_scanner_table_models(self): issues = self.issues for issue in issues: issue_name = issue["name"] issue_param = issue["param"] self.create_scanner_table_model(issue_name, issue_param) # Creates the tabs dynamically using data from the JSON file def set_scanner_panes(self): for issue in self.issues: issue_name = issue["name"] issue_param = issue["param"] key = issue_name + "." + issue_param top_pane = self.create_request_list_pane(issue_name) bottom_pane = self.create_tabbed_pane() scanner_pane = JSplitPane(JSplitPane.VERTICAL_SPLIT, top_pane, bottom_pane) self.scanner_panes[key] = scanner_pane def get_scanner_panes(self): return self.scanner_panes def create_request_list_pane(self, issue_name): request_list_pane = JScrollPane() return request_list_pane # Creates a JTabbedPane for each vulnerability per functionality def create_tabbed_pane(self): tabbed_pane = JTabbedPane() tabbed_pane.add("Advisory", JScrollPane()) tabbed_pane.add("Request", JScrollPane()) tabbed_pane.add("Response", JScrollPane()) self.tabbed_pane = tabbed_pane return tabbed_pane def get_settings(self): return self.settings def set_settings(self): self.settings = JPanel() layout = GroupLayout(self.settings) self.settings.setLayout(layout) layout.setAutoCreateGaps(True) load_file_button = JButton("Load JSON File") load_file_button.setActionCommand("load") load_file_button.addActionListener( SettingsAction(self, load_file_button, None)) save_file_button = JButton("Save JSON File") save_file_button.setActionCommand("save") save_file_button.addActionListener( SettingsAction(self, save_file_button, self.scanner_panes)) horizontal_group1 = layout.createParallelGroup( GroupLayout.Alignment.LEADING) horizontal_group1.addComponent(load_file_button) horizontal_group1.addComponent(save_file_button) horizontal_group = layout.createSequentialGroup() horizontal_group.addGroup(horizontal_group1) layout.setHorizontalGroup(horizontal_group) vertical_group1 = layout.createParallelGroup( GroupLayout.Alignment.BASELINE) vertical_group1.addComponent(load_file_button) vertical_group2 = layout.createParallelGroup( GroupLayout.Alignment.BASELINE) vertical_group2.addComponent(save_file_button) vertical_group = layout.createSequentialGroup() vertical_group.addGroup(vertical_group1) vertical_group.addGroup(vertical_group2) layout.setVerticalGroup(vertical_group) def set_tsl(self): tsl = TSL(self) self.tree.addTreeSelectionListener(tsl) return def set_pane(self): status = JTextArea() status.setLineWrap(True) status.setText("Nothing selected") self.status = status request_list_pane = JScrollPane() scanner_pane = JSplitPane(JSplitPane.VERTICAL_SPLIT, request_list_pane, self.tabbed_pane) self.pane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(self.tree), scanner_pane) self.pane.setDividerLocation(310) self.pane.getLeftComponent().setMinimumSize(Dimension(310, 300)) def get_pane(self): return self.pane # TODO: Move all scanner table functions into its own ScannerTable class # as well as ScannerTableModel for all scanner table model functions def create_scanner_table_model(self, issue_name, issue_param): key = issue_name + "." + issue_param is_model_exists = key in self.scanner_table_models if is_model_exists: return scanner_table_model = ScannerTableModel() scanner_table_model.addColumn("") scanner_table_model.addColumn("Parameter") scanner_table_model.addColumn("Host") scanner_table_model.addColumn("Path") scanner_table_model.addColumn("ID") self.scanner_table_models[key] = scanner_table_model def set_scanner_table_model(self, scanner_issue, issue_name, issue_param, vuln_param): key = issue_name + "." + vuln_param scanner_issue_id = str( scanner_issue.getRequestResponse()).split("@")[1] scanner_table_model = self.scanner_table_models[key] # Using the addRow() method requires that the data type being passed to be of type # Vector() or Object(). Passing a Python object of type list in addRow causes a type # conversion error of sorts which presents as an ArrayOutOfBoundsException. Therefore, # row is an instantiation of Object() to avoid this error. row = Object() row = [ False, issue_param, scanner_issue.getHttpService().getHost(), scanner_issue.getPath(), scanner_issue_id ] scanner_table_model.addRow(row) # Wait for ScannerTableModel to update as to not get an ArrayOutOfBoundsException. Thread.sleep(500) scanner_table_model.fireTableDataChanged() scanner_table_model.fireTableStructureChanged() def get_scanner_table_model(self, issue_name, issue_param): key = issue_name + "." + issue_param return self.scanner_table_models[key] def set_scanner_pane(self, scanner_pane, issue_name, issue_param): key = issue_name + "." + issue_param request_table_pane = scanner_pane.getTopComponent() if key in self.scanner_tables: scanner_table = self.scanner_tables[key] else: scanner_table = self.create_scanner_table(scanner_pane, issue_name, issue_param) self.scanner_tables[key] = scanner_table request_table_pane.getViewport().setView(scanner_table) request_table_pane.revalidate() request_table_pane.repaint() def create_scanner_table(self, scanner_pane, issue_name, issue_param): scanner_table_model = self.get_scanner_table_model( issue_name, issue_param) scanner_table = JTable(scanner_table_model) scanner_table.getColumnModel().getColumn(0).setMaxWidth(10) scanner_table.putClientProperty("terminateEditOnFocusLost", True) scanner_table_listener = ScannerTableListener(self, scanner_table, issue_name, issue_param) scanner_table_model.addTableModelListener(scanner_table_listener) scanner_table_list_listener = IssueListener(self, scanner_table, scanner_pane, issue_name, issue_param) scanner_table.getSelectionModel().addListSelectionListener( scanner_table_list_listener) return scanner_table # Takes into account if there are more than one scanner issues that share the same hostname, path, name, param, and id def set_tabbed_pane(self, scanner_pane, request_list, issue_hostname, issue_path, issue_name, issue_param, scanner_issue_id): tabbed_pane = scanner_pane.getBottomComponent() scanner_issues = self.get_scanner_issues() current_issue = self.set_current_issue(scanner_issues, issue_hostname, issue_path, issue_name, issue_param, scanner_issue_id) advisory_tab_pane = self.set_advisory_tab_pane(current_issue) tabbed_pane.setComponentAt(0, advisory_tab_pane) request_tab_pane = self.set_request_tab_pane(current_issue) tabbed_pane.setComponentAt(1, request_tab_pane) response_tab_pane = self.set_response_tab_pane(current_issue) tabbed_pane.setComponentAt(2, response_tab_pane) def set_current_issue(self, scanner_issues, issue_hostname, issue_path, issue_name, issue_param, scanner_issue_id): for scanner_issue in scanner_issues: is_same_hostname = scanner_issue.getHostname() == issue_hostname is_same_path = scanner_issue.getPath() == issue_path is_same_name = scanner_issue.getIssueName() == issue_name is_same_param = scanner_issue.getParameter() == issue_param is_same_id = str(scanner_issue.getRequestResponse()).split( "@")[1] == scanner_issue_id is_same_issue = is_same_hostname and is_same_path and is_same_name and is_same_param and is_same_id if is_same_issue: return scanner_issue def set_advisory_tab_pane(self, scanner_issue): advisory_pane = JEditorPane() advisory_pane.setEditable(False) advisory_pane.setEnabled(True) advisory_pane.setContentType("text/html") link_listener = LinkListener() advisory_pane.addHyperlinkListener(link_listener) advisory = "<html><b>Location</b>: {}<br><br>{}</html>" advisory_pane.setText( advisory.format(scanner_issue.getUrl().encode("utf-8"), scanner_issue.getIssueDetail())) return JScrollPane(advisory_pane) def set_request_tab_pane(self, scanner_issue): request_response = scanner_issue.getRequestResponse() controller = MessageController(request_response) message_editor = self.callbacks.createMessageEditor(controller, True) message_editor.setMessage(request_response.getRequest(), True) component = message_editor.getComponent() return component def set_response_tab_pane(self, scanner_issue): request_response = scanner_issue.getRequestResponse() controller = MessageController(request_response) message_editor = self.callbacks.createMessageEditor(controller, True) message_editor.setMessage(request_response.getResponse(), False) component = message_editor.getComponent() return component def traverse_tree(self, tree, model, issue_name, issue_param, issue_count, total_count): root = model.getRoot() count = int(root.getChildCount()) traverse = {} for i in range(count): node = model.getChild(root, i) traverse["node"] = node tree_issue_name = node.toString() is_issue_name = re.search(issue_name, tree_issue_name) if is_issue_name: child_count = node.getChildCount() for j in range(child_count): child = node.getChildAt(j) traverse["child"] = child tree_param_name = child.toString() is_param_name = re.search(issue_param, tree_param_name) if is_param_name: traverse["param_text"] = issue_param + " (" + str( issue_count) + ")" break traverse["issue_text"] = issue_name + " (" + str( total_count) + ")" break return traverse def set_scanner_count(self, issue_name, issue_param, issue_count, total_count): tree = self.get_tree() model = tree.getModel() traverse = self.traverse_tree(tree, model, issue_name, issue_param, issue_count, total_count) node = traverse["node"] child = traverse["child"] child.setUserObject(traverse["param_text"]) model.nodeChanged(child) model.reload(node) node.setUserObject(traverse["issue_text"]) model.nodeChanged(node) model.reload(node)
class javadocInfo_10( java.lang.Runnable ) : #--------------------------------------------------------------------------- # Name: __init__() # Role: Constructor - initialize application variables #--------------------------------------------------------------------------- def __init__( self ) : self.prevText = None # Previously specified user input (text) #--------------------------------------------------------------------------- # Name: run() # Role: Instantiate the user class # Note: Invoked by the Swing Event Dispatch Thread #--------------------------------------------------------------------------- def run( self ) : #----------------------------------------------------------------------- # Size the frame to use 1/2 of the screen #----------------------------------------------------------------------- screenSize = Toolkit.getDefaultToolkit().getScreenSize() frameSize = Dimension( screenSize.width >> 1, screenSize.height >> 1 ) frame = JFrame( 'javadocInfo_10', size = frameSize, defaultCloseOperation = JFrame.EXIT_ON_CLOSE ) #----------------------------------------------------------------------- # Reposition the frame to be in the center of the screen #----------------------------------------------------------------------- frame.setLocation( ( screenSize.width - frameSize.width ) >> 1, ( screenSize.height - frameSize.height ) >> 1 ) #----------------------------------------------------------------------- # Initialize the list to have exactly 1 element #----------------------------------------------------------------------- model = DefaultListModel() model.addElement( 'One moment please...' ) self.List = JList( model, valueChanged = self.pick, selectionMode = ListSelectionModel.SINGLE_SELECTION ) #----------------------------------------------------------------------- # Put the List in a ScrollPane and place it in the middle of a pane #----------------------------------------------------------------------- pane = JPanel( layout = BorderLayout() ) pane.add( JScrollPane( self.List, minimumSize = ( 300, 50 ) ), BorderLayout.CENTER ) #----------------------------------------------------------------------- # Add a TextField [for the URL of the selected entry] at the bottom #----------------------------------------------------------------------- self.text = JTextField( 'Enter text...', caretUpdate = self.caretUpdate ) pane.add( self.text, BorderLayout.SOUTH ) #----------------------------------------------------------------------- # Add the pane and a scrollable TextArea to a SplitPane in the frame #----------------------------------------------------------------------- self.area = JEditorPane( 'text/html', '<html><h3>Nothing selected</h3></html>', editable = 0 ) self.splitPane = JSplitPane( JSplitPane.HORIZONTAL_SPLIT, pane, self.area ) self.splitPane.setDividerLocation( 234 ) frame.add( self.splitPane ) #----------------------------------------------------------------------- # Create a separate thread to locate & proces the remote URL #----------------------------------------------------------------------- self.Links = {} # Initialize the Links dictionary self.classes = None # complete list of all classes found soupTask( self.List, # The visible JList instance self.text, # User input field JAVADOC_URL, # Remote web page URL to be processed self.Links, # Dictionary of links found ).execute() frame.setVisible( 1 ) #--------------------------------------------------------------------------- # Name: pick() # Role: ListSelectionListener event handler #--------------------------------------------------------------------------- def pick( self, e ) : #----------------------------------------------------------------------- # Note: Ignore valueIsAdjusting events #----------------------------------------------------------------------- if not e.getValueIsAdjusting() : List = self.List model = List.getModel() #--------------------------------------------------------------- # Is a "valid" item selected? #--------------------------------------------------------------- index = List.getSelectedIndex() if index > -1 : choice = model.elementAt( index ) if self.Links.has_key( choice ) : url = self.Links[ choice ] headerTask( url, self.splitPane ).execute() else : message = 'Nothing selected' comp = self.splitPane.getRightComponent() Type = str( comp.getClass() ).split( '.' )[ -1 ] if Type == 'JEditorPane' : comp.setText( '<html><h3>%s</h3></html>' % message ) else : area = JEditorPane( 'text/html', '<html><h3>%s</h3></html>' % message, editable = 0 ) self.splitPane.setRightComponent( area ) #--------------------------------------------------------------------------- # Name: caretUpdate() # Role: CaretListener event handler used to monitor JTextField for user input #--------------------------------------------------------------------------- def caretUpdate( self, e ) : field = e.getSource() text = field.getText() if self.prevText == None : self.prevText = text if self.classes == None : result = self.Links.keys() if len( result ) > 0 : result.sort() self.classes = result #----------------------------------------------------------------------- # Did the user just move the cursor, or did they change the text field? #----------------------------------------------------------------------- if text != self.prevText : # print 'dot: %2d text: "%s"' % ( e.getDot(), text ) model = DefaultListModel() items = [ item for item in self.classes if item.find( text ) > -1 ] if len( items ) > 0 : for item in items : model.addElement( item ) else : model.addElement( 'No matching classes found.' ) self.List.setModel( model ) self.prevText = text
class AtfAreaView(JPanel): ''' Initializes the ATF (edit/model) view and sets its layout. ''' def __init__(self, controller): ''' Creates default empty text area in a panel for ATF edition. It has syntax highlighting based on the ATF parser (pyoracc). It also highlights line numbers where there are validations errors returned by the ORACC server. ''' # Give reference to controller to delegate action response self.controller = controller # Make text area occupy all available space and resize with parent # window self.setLayout(BorderLayout()) # Short hand for edit area and line numbers area self.edit_area = self.controller.edit_area self.line_numbers_area = self.controller.line_numbers_area # Create secondary text area for split view self.secondary_area = self.controller.secondary_area self.secondary_line_numbers = self.controller.secondary_line_numbers # Set undo/redo manager to edit area self.undo_manager = UndoManager() self.undo_manager.limit = 3000 self.edit_listener = AtfUndoableEditListener(self.undo_manager) self.edit_area.getDocument().addUndoableEditListener( self.edit_listener) # Sort out layout by synch-ing line numbers and text area and putting # only the text area in a scroll pane as indicated in the # TextLineNumber tutorial. self.edit_area.setPreferredSize(Dimension(1, 500)) self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.add(self.container, BorderLayout.CENTER) # Key listener that triggers syntax highlighting, etc. upon key release self.edit_area.addKeyListener(AtfAreaKeyListener(self.controller)) # Also needed in secondary area: self.secondary_area.addKeyListener(AtfAreaKeyListener(self.controller)) def toggle_split(self, split_orientation=None): ''' Clear ATF edit area and repaint chosen layout (splitscreen/scrollpane). ''' # Remove all existent components in parent JPanel self.removeAll() # Check what editor view to toggle self.setup_edit_area(split_orientation) # Revalitate is needed in order to repaint the components self.revalidate() self.repaint() def setup_edit_area(self, split_orientation=None): ''' Check if the ATF text area is being displayed in a split editor. If so, resets to normal JScrollPane. If not, splits the screen. ''' if isinstance(self.container, JSplitPane): # If Nammu is already displaying a split pane, reset to original # setup self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.container.setVisible(True) self.add(self.container, BorderLayout.CENTER) else: # If there is not a split pane, create both panels and setup view main_editor = JScrollPane(self.edit_area) main_editor.setRowHeaderView(self.line_numbers_area) secondary_editor = JScrollPane(self.secondary_area) secondary_editor.setRowHeaderView(self.secondary_line_numbers) self.container = JSplitPane(split_orientation, main_editor, secondary_editor) self.container.setDividerSize(5) self.container.setVisible(True) self.container.setDividerLocation(0.5) self.container.setResizeWeight(0.5) self.add(self.container, BorderLayout.CENTER)
def __init__(self): #obtain prefixes from folder self.dict1 = self.obtain_prefixes( ) #Run prefix selection function - sets source directory, requests prefix size, outputs prefix dictionary lst = list(self.dict1.keys()) #pull prefixes only, as list self.lang = lst self.lst = JList(self.lang, valueChanged=self.listSelect ) # pass prefix list to GUI selection list # general GUI layout parameters, no data processing here self.frame = JFrame("Image Selection") self.frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE) self.frame.setLocation(100, 100) self.frame.setSize(800, 350) self.frame.setLayout(BorderLayout()) self.frame.add(self.lst, BorderLayout.NORTH) self.lst.selectionMode = ListSelectionModel.MULTIPLE_INTERVAL_SELECTION self.button1 = JButton('Select item(s)', actionPerformed=self.clickhere) #Save option radio buttons and file extension selection #set main right panel (sub panels will fit within this) rightpanel = JPanel() rightpanel.setLayout(BoxLayout(rightpanel, BoxLayout.Y_AXIS)) #set up savestate panel buttonpanel = JPanel() self.radiobutton1 = JRadioButton( "Open selected 3D stacks and max projections \n and save max projections", True) self.radiobutton2 = JRadioButton( "Open selected 3D stacks and max projections \n and DO NOT save max projections" ) infoLabel = JLabel( "<html>Hold ctrl and click multiple prefixes to select multiple options. Will load stacks and MIPs separately <br><br> Type file extension in text field below:</html>", SwingConstants.LEFT) grp = ButtonGroup() grp.add(self.radiobutton1) grp.add(self.radiobutton2) #buttonpanel.setLayout(BoxLayout(buttonpanel, BoxLayout.Y_AXIS)) buttonpanel.add(Box.createVerticalGlue()) buttonpanel.add(infoLabel) buttonpanel.add(Box.createRigidArea(Dimension(0, 5))) buttonpanel.add(self.radiobutton1) buttonpanel.add(Box.createRigidArea(Dimension(0, 5))) buttonpanel.add(self.radiobutton2) #file extension instruction panel infopanel = JPanel() infopanel.setLayout(FlowLayout(FlowLayout.LEFT)) infopanel.setMaximumSize( infopanel.setPreferredSize(Dimension(650, 100))) infopanel.add(infoLabel) #file extension input inputPanel = JPanel() inputPanel.setLayout(BoxLayout(inputPanel, BoxLayout.X_AXIS)) self.filetype = JTextField(".tif", 15) self.filetype.setMaximumSize(self.filetype.getPreferredSize()) inputPanel.add(self.filetype) ########### WIP - integrate prefix selection with main pane, with dynamically updating prefix list ##infoLabel3 = JLabel("how long is the file prefix to group by?(integer value only)") ##self.prefix_init = JTextField() ##buttonpanel.add(infoLabel3) ##buttonpanel.add(self.prefix_init) ########### !WIP #add file extension and savestate panels to main panel rightpanel.add(infopanel) rightpanel.add(inputPanel) rightpanel.add(buttonpanel, BorderLayout.EAST) #split list and radiobutton pane (construct overall window) spl = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) spl.leftComponent = JScrollPane(self.lst) spl.setDividerLocation(150) spl.rightComponent = rightpanel self.frame.add(spl) self.frame.add(self.button1, BorderLayout.SOUTH) # GUI layout done, initialise GUI to select prefixes, file extension and save option self.frame.setVisible(True)
def dividerLocation(self, location): JSplitPane.setDividerLocation(self, location) newAuxPanelSize = self.flipLocation(location) if newAuxPanelSize >= self.minAuxSize): self.auxPanelVisibleSize = newAuxPanelSize
def __init__(self, ui): JSplitPane.__init__(self, JSplitPane.HORIZONTAL_SPLIT) self._ui = ui # create the executor object self._executor = Executor(self, ui.callbacks) #### # start Left Top split layout jLeftTopPanel = JPanel() jMenuPanel = JPanel() #Load button self.jLoad = JButton(Strings.jLoad_text) self.jLoad.addActionListener(self) #File name text field self.jFileName = JTextField(Strings.jFileName_default, 30) self.jFileName.setHorizontalAlignment(JTextField.CENTER) self.jFileName.setEditable(False) #Save button self.jSave = JButton(Strings.jSave_text) self.jSave.addActionListener(self) #Exit button self.jExit = JButton(Strings.jExit_text) self.jExit.addActionListener(self) #Wiki button (URL) self.jWiki = JButton(Strings.jWiki_title) self.jWiki.setToolTipText(Strings.jWiki_tooltip) self.jWiki.addActionListener(self) # make it borderless self.jWiki.setBorder(EmptyBorder(0, 0, 0, 0)) self.jWiki.setBorderPainted(False) self.jWiki.setContentAreaFilled(False) #Console text area jConsoleText = JTextArea() jConsoleText.setEditable(0) jConsoleText.setWrapStyleWord(1) jConsoleText.setRows(10) #set initial text jConsoleText.setText(Strings.jConsoleText_help) #make scrollable jScrollConsolePane = JScrollPane() jScrollConsolePane.setViewportView(jConsoleText) jMenuPanelLayout = GroupLayout(jMenuPanel) jMenuPanel.setLayout(jMenuPanelLayout) jMenuPanelLayout.setHorizontalGroup( jMenuPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING). addGroup(jMenuPanelLayout.createSequentialGroup().addContainerGap( ).addComponent(self.jLoad).addComponent( self.jFileName).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED).addComponent( self.jSave).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED). addComponent(self.jWiki).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED).addComponent( self.jExit).addContainerGap())) jMenuPanelLayout.setVerticalGroup( jMenuPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( jMenuPanelLayout.createSequentialGroup().addGroup( jMenuPanelLayout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( self.jLoad).addComponent( self.jFileName, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addComponent( self.jSave).addComponent( self.jWiki).addComponent( self.jExit)))) jLeftTopPanelLayout = GroupLayout(jLeftTopPanel) jLeftTopPanel.setLayout(jLeftTopPanelLayout) jLeftTopPanelLayout.setHorizontalGroup( jLeftTopPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( jMenuPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE).addComponent( jScrollConsolePane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, 32767)) jLeftTopPanelLayout.setVerticalGroup( jLeftTopPanelLayout. createParallelGroup(GroupLayout.Alignment.LEADING).addGroup( GroupLayout.Alignment.TRAILING, jLeftTopPanelLayout.createSequentialGroup().addComponent( jMenuPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED).addComponent( jScrollConsolePane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, 32767))) # end Left Top split layout #### #### # start Left Down split layout jLeftDownPanel = JPanel() jMenu2Panel = JPanel() #Clear button self.jClear = JButton(Strings.jClear_text) self.jClear.setToolTipText(Strings.jClear_tooltip) self.jClear.addActionListener(self) #Run button self.jRun = JButton(Strings.jRun_text) self.jRun.setToolTipText(Strings.jRun_tooltip) self.jRun.addActionListener(self) #Variables text area jVarsPane = JTextPane() jVarsPane.setFont(Font('Monospaced', Font.PLAIN, 11)) jVarsPane.addFocusListener(self) # set initial value jVarsPane.setText(Strings.jVarsPane_header) # make scrollable jScrollpaneLeftDown = JScrollPane() jScrollpaneLeftDown.setViewportView(jVarsPane) jMenu2PanelLayout = GroupLayout(jMenu2Panel) jMenu2Panel.setLayout(jMenu2PanelLayout) jMenu2PanelLayout.setHorizontalGroup( jMenu2PanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( jMenu2PanelLayout.createSequentialGroup().addContainerGap( ).addComponent(self.jClear).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED, 100, 32767).addComponent(self.jRun).addContainerGap())) jMenu2PanelLayout.setVerticalGroup( jMenu2PanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( jMenu2PanelLayout.createSequentialGroup().addGroup( jMenu2PanelLayout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( self.jClear).addComponent(self.jRun)))) jLeftDownPanelLayout = GroupLayout(jLeftDownPanel) jLeftDownPanel.setLayout(jLeftDownPanelLayout) jLeftDownPanelLayout.setHorizontalGroup( jLeftDownPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( jMenu2Panel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE).addComponent( jScrollpaneLeftDown, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, 32767)) jLeftDownPanelLayout.setVerticalGroup( jLeftDownPanelLayout. createParallelGroup(GroupLayout.Alignment.LEADING).addGroup( GroupLayout.Alignment.TRAILING, jLeftDownPanelLayout.createSequentialGroup().addComponent( jMenu2Panel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED).addComponent( jScrollpaneLeftDown, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, 32767))) # end Left Down split layout #### #### # start Left layout jSplitPaneLeft = JSplitPane(JSplitPane.VERTICAL_SPLIT, jLeftTopPanel, jLeftDownPanel) jSplitPaneLeft.setDividerLocation(300) # end Left layout #### #### # start Right layout jScriptPane = JTextPane() jScriptPane.setFont(Font('Monospaced', Font.PLAIN, 11)) # set initial value jScriptPane.setText(Strings.jScriptPane_header) #jScriptPane.addMouseListener(self) jScrollPaneRight = JScrollPane() jScrollPaneRight.setViewportView(jScriptPane) # end Right layout #### self.setLeftComponent(jSplitPaneLeft) self.setRightComponent(jScrollPaneRight) self.setDividerLocation(450) #Exported variables self.jConsoleText = jConsoleText self.jScrollConsolePane = jScrollConsolePane self.jScriptPane = jScriptPane self.jVarsPane = jVarsPane
class AtfAreaView(JPanel): ''' Initializes the ATF (edit/model) view and sets its layout. ''' def __init__(self, controller): ''' Creates default empty text area in a panel for ATF edition. It has syntax highlighting based on the ATF parser (pyoracc). It also highlights line numbers where there are validations errors returned by the ORACC server. ''' # Give reference to controller to delegate action response self.controller = controller # Make text area occupy all available space and resize with parent # window self.setLayout(BorderLayout()) # Short hand for edit area and line numbers area self.edit_area = self.controller.edit_area self.line_numbers_area = self.controller.line_numbers_area # Create secondary text area for split view self.secondary_area = self.controller.secondary_area self.secondary_line_numbers = self.controller.secondary_line_numbers # Set undo/redo manager to edit area self.undo_manager = UndoManager() self.undo_manager.limit = 3000 self.edit_listener = AtfUndoableEditListener(self.undo_manager) self.edit_area.getDocument().addUndoableEditListener( self.edit_listener) # Sort out layout by synch-ing line numbers and text area and putting # only the text area in a scroll pane as indicated in the # TextLineNumber tutorial. self.edit_area.setPreferredSize(Dimension(1, 500)) self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.add(self.container, BorderLayout.CENTER) self.vert_scroll = self.container.getVerticalScrollBar() self.vert_scroll.addAdjustmentListener(atfAreaAdjustmentListener(self)) # Key listener that triggers syntax highlighting, etc. upon key release self.edit_area.addKeyListener(AtfAreaKeyListener(self)) # Also needed in secondary area: self.secondary_area.addKeyListener(AtfAreaKeyListener(self)) # Add a document listener to track changes to files docListener = atfAreaDocumentListener(self) self.edit_area.getDocument().addDocumentListener(docListener) # instance variable to store a record of the text contents prior to the # most recent change. Needed so that the different listeners can access # this to handle error line updating. self.oldtext = '' def toggle_split(self, split_orientation=None): ''' Clear ATF edit area and repaint chosen layout (splitscreen/scrollpane). ''' # Remove all existent components in parent JPanel self.removeAll() # Check what editor view to toggle self.setup_edit_area(split_orientation) # Revalitate is needed in order to repaint the components self.revalidate() self.repaint() def setup_edit_area(self, split_orientation=None): ''' Check if the ATF text area is being displayed in a split editor. If so, resets to normal JScrollPane. If not, splits the screen. ''' if isinstance(self.container, JSplitPane): # If Nammu is already displaying a split pane, reset to original # setup self.container = JScrollPane(self.edit_area) self.container.setRowHeaderView(self.line_numbers_area) self.container.setVisible(True) self.add(self.container, BorderLayout.CENTER) else: # If there is not a split pane, create both panels and setup view main_editor = JScrollPane(self.edit_area) main_editor.setRowHeaderView(self.line_numbers_area) secondary_editor = JScrollPane(self.secondary_area) secondary_editor.setRowHeaderView(self.secondary_line_numbers) self.container = JSplitPane(split_orientation, main_editor, secondary_editor) self.container.setDividerSize(5) self.container.setVisible(True) self.container.setDividerLocation(0.5) self.container.setResizeWeight(0.5) self.add(self.container, BorderLayout.CENTER) def get_viewport_carets(self): ''' Get the top left and bottom left caret position of the current viewport ''' extent = self.container.getViewport().getExtentSize() top_left_position = self.container.getViewport().getViewPosition() top_left_char = self.edit_area.viewToModel(top_left_position) bottom_left_position = Point(top_left_position.x, top_left_position.y + extent.height) bottom_left_char = self.edit_area.viewToModel(bottom_left_position) # Something has gone wrong. Assume that top_left should be at the start # of the file if top_left_char >= bottom_left_char: top_left_char = 0 # Get the text in the full edit area text = self.controller.edit_area.getText() # Pad the top of the viewport to capture up to the nearest header and # the bottom by 2 lines top_ch = self.controller.pad_top_viewport_caret(top_left_char, text) bottom_ch = self.controller.pad_bottom_viewport_caret(bottom_left_char, text) return top_ch, bottom_ch def refresh(self): ''' Restyle edit area using user selected appearance settings. ''' config = self.controller.controller.config # Create a new font with the new size font = set_font(config['edit_area_style']['fontsize']['user']) # Update the sytnax highlighter font params, so our changes are not # superceded self.controller.syntax_highlighter.font = font self.controller.syntax_highlighter.setup_attribs() attrs = self.controller.edit_area.getInputAttributes() StyleConstants.setFontSize(attrs, font.getSize()) # Get the Styledoc so we can update it doc = self.controller.edit_area.getStyledDocument() # Apply the new fontsize to the whole document doc.setCharacterAttributes(0, doc.getLength() + 1, attrs, False)
class View: def __init__(self, issues): self.json = issues.get_json() self.issues_object = issues self.issues = issues.get_issues() self.scanner_issues = issues.get_scanner_issues() self.scanner_panes = {} self.scanner_tables = {} self.is_scanner_panes = [] self.set_vuln_tree() self.set_tree() self.set_scanner_panes() self.set_pane() self.set_tsl() def set_callbacks(self, callbacks): self.callbacks = callbacks def set_helpers(self, helpers): self.helpers = helpers def get_helpers(self): return self.helpers def get_issues(self): return self.issues def get_scanner_issues(self): return self.scanner_issues def set_scanner_count(self, is_checked, issue_name, issue_param): self.issues_object.set_scanner_count(self, is_checked, issue_name, issue_param) def set_is_scanner_pane(self, scanner_pane): self.is_scanner_panes.append(scanner_pane) def get_is_scanner_pane(self, scanner_pane): for pane in self.get_is_scanner_panes(): if pane == scanner_pane: return True return False def get_is_scanner_panes(self): return self.is_scanner_panes def set_vuln_tree(self): self.vuln_tree = DefaultMutableTreeNode("Vulnerability Classes") vulns = self.json["issues"] # TODO: Sort the functionality by name and by vuln class for vuln_name in vulns: vuln = DefaultMutableTreeNode(vuln_name) self.vuln_tree.add(vuln) parameters = self.json["issues"][vuln_name]["params"] for parameter in parameters: param_node = DefaultMutableTreeNode(parameter) vuln.add(param_node) # Creates a JTree object from the checklist def set_tree(self): self.tree = JTree(self.vuln_tree) self.tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION ) def get_tree(self): return self.tree # Creates the tabs dynamically using data from the JSON file def set_scanner_panes(self): issues = self.issues for issue in issues: issue_name = issue["name"] issue_param = issue["param"] key = issue_name + "." + issue_param top_pane = self.create_request_list_pane(issue_name) bottom_pane = self.create_tabbed_pane() scanner_pane = JSplitPane(JSplitPane.VERTICAL_SPLIT, top_pane, bottom_pane) self.scanner_panes[key] = scanner_pane def get_scanner_panes(self): return self.scanner_panes def create_request_list_pane(self, issue_name): request_list_pane = JScrollPane() return request_list_pane # Creates a JTabbedPane for each vulnerability per functionality def create_tabbed_pane(self): tabbed_pane = JTabbedPane() tabbed_pane.add("Advisory", JScrollPane()) tabbed_pane.add("Request", JScrollPane()) tabbed_pane.add("Response", JScrollPane()) self.tabbed_pane = tabbed_pane return tabbed_pane def set_tsl(self): tsl = TSL(self) self.tree.addTreeSelectionListener(tsl) return def set_pane(self): status = JTextArea() status.setLineWrap(True) status.setText("Nothing selected") self.status = status request_list_pane = JScrollPane() scanner_pane = JSplitPane(JSplitPane.VERTICAL_SPLIT, request_list_pane, self.tabbed_pane ) self.pane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, JScrollPane(self.tree), scanner_pane ) self.pane.setDividerLocation(310) self.pane.getLeftComponent().setMinimumSize(Dimension(310, 300)) def get_pane(self): return self.pane def set_scanner_table(self, scanner_pane, scanner_table): self.scanner_tables[scanner_pane] = scanner_table def get_scanner_table(self, scanner_pane): return self.scanner_tables[scanner_pane] def set_scanner_pane(self, scanner_pane): request_table_pane = scanner_pane.getTopComponent() scanner_table = self.get_scanner_table(scanner_pane) request_table_pane.getViewport().setView(scanner_table) request_table_pane.revalidate() request_table_pane.repaint() def create_scanner_pane(self, scanner_pane, issue_name, issue_param): scanner_issues = self.get_scanner_issues() request_table_pane = scanner_pane.getTopComponent() scanner_table_model = ScannerTableModel() scanner_table_model.addColumn("Checked") scanner_table_model.addColumn("Host") scanner_table_model.addColumn("Path") # Search all issues for the correct issue. Once found, add it into # the scanner table model to be showed in the UI. for scanner_issue in scanner_issues: is_same_name = scanner_issue.getIssueName() == issue_name is_same_param = scanner_issue.getParameter() == issue_param is_same_issue = is_same_name and is_same_param if is_same_issue: scanner_table_model.addRow([ False, scanner_issue.getHttpService().getHost(), scanner_issue.getUrl() ]) scanner_table = JTable(scanner_table_model) scanner_table.getColumnModel().getColumn(0).setCellEditor(DefaultCellEditor(JCheckBox())) scanner_table.putClientProperty("terminateEditOnFocusLost", True) scanner_table_listener = ScannerTableListener(self, scanner_table, issue_name, issue_param) scanner_table_model.addTableModelListener(scanner_table_listener) scanner_table_list_listener = IssueListener(self, scanner_table, scanner_pane, issue_name, issue_param) scanner_table.getSelectionModel().addListSelectionListener(scanner_table_list_listener) self.set_scanner_table(scanner_pane, scanner_table) request_table_pane.getViewport().setView(scanner_table) request_table_pane.revalidate() request_table_pane.repaint() def set_tabbed_pane(self, scanner_pane, request_list, issue_url, issue_name, issue_param): tabbed_pane = scanner_pane.getBottomComponent() scanner_issues = self.get_scanner_issues() for scanner_issue in scanner_issues: is_same_url = scanner_issue.getUrl() == issue_url is_same_name = scanner_issue.getIssueName() == issue_name is_same_param = scanner_issue.getParameter() == issue_param is_same_issue = is_same_url and is_same_name and is_same_param if is_same_issue: current_issue = scanner_issue self.set_context_menu(request_list, scanner_issue) break advisory_tab_pane = self.set_advisory_tab_pane(current_issue) tabbed_pane.setComponentAt(0, advisory_tab_pane) request_tab_pane = self.set_request_tab_pane(current_issue) tabbed_pane.setComponentAt(1, request_tab_pane) response_tab_pane = self.set_response_tab_pane(current_issue) tabbed_pane.setComponentAt(2, response_tab_pane) def set_advisory_tab_pane(self, scanner_issue): advisory_pane = JEditorPane() advisory_pane.setEditable(False) advisory_pane.setEnabled(True) advisory_pane.setContentType("text/html") link_listener = LinkListener() advisory_pane.addHyperlinkListener(link_listener) advisory_pane.setText("<html>" + "<b>Location</b>: " + scanner_issue.getUrl() + "<br><br>" + scanner_issue.getIssueDetail() + "</html>" ) # Set a context menu self.set_context_menu(advisory_pane, scanner_issue) return JScrollPane(advisory_pane) def set_request_tab_pane(self, scanner_issue): raw_request = scanner_issue.getRequestResponse().getRequest() request_body = StringUtil.fromBytes(raw_request) request_body = request_body.encode("utf-8") request_tab_textarea = JTextArea(request_body) request_tab_textarea.setLineWrap(True) # Set a context menu self.set_context_menu(request_tab_textarea, scanner_issue) return JScrollPane(request_tab_textarea) def set_response_tab_pane(self, scanner_issue): raw_response = scanner_issue.getRequestResponse().getResponse() response_body = StringUtil.fromBytes(raw_response) response_body = response_body.encode("utf-8") response_tab_textarea = JTextArea(response_body) response_tab_textarea.setLineWrap(True) # Set a context menu self.set_context_menu(response_tab_textarea, scanner_issue) return JScrollPane(response_tab_textarea) # Pass scanner_issue as argument def set_context_menu(self, component, scanner_issue): self.context_menu = JPopupMenu() repeater = JMenuItem("Send to Repeater") repeater.addActionListener(PopupListener(scanner_issue, self.callbacks)) intruder = JMenuItem("Send to Intruder") intruder.addActionListener(PopupListener(scanner_issue, self.callbacks)) hunt = JMenuItem("Send to HUNT") self.context_menu.add(repeater) self.context_menu.add(intruder) context_menu_listener = ContextMenuListener(component, self.context_menu) component.addMouseListener(context_menu_listener) def get_context_menu(self): return self.context_menu
class BurpExtender(IBurpExtender, IExtensionStateListener, IHttpListener, ITab, FocusListener, ActionListener, MouseAdapter): _version = "0.2" _name = "PyRules" _varsStorage = _name + "_vars" _scriptStorage = _name + "_script" _enabled = 0 _vars = {} def registerExtenderCallbacks(self, callbacks): print "Load:" + self._name + " " + self._version self.callbacks = callbacks self.helpers = callbacks.helpers #Create Tab layout self.jVarsPane = JTextPane() self.jVarsPane.setFont(Font('Monospaced', Font.PLAIN, 11)) self.jVarsPane.addFocusListener(self) self.jMenuPanel = JPanel() self.jLeftUpPanel = JPanel() self.jEnable = JCheckBox() self.jEnable.setFont(Font('Monospaced', Font.BOLD, 11)) self.jEnable.setForeground(Color(0, 0, 204)) self.jEnable.setText(self._name) self.jEnable.addActionListener(self) self.jDocs = JLabel() self.jDocs.setFont(Font('Monospaced', Font.PLAIN, 11)) self.jDocs.setForeground(Color(51, 102, 255)) self.jDocs.setText(Strings.docs_titel) self.jDocs.setToolTipText(Strings.docs_tooltip) self.jDocs.addMouseListener(self) self.jConsoleText = JTextArea() self.jConsoleText.setFont(Font('Monospaced', Font.PLAIN, 10)) self.jConsoleText.setBackground(Color(244, 246, 247)) self.jConsoleText.setEditable(0) self.jConsoleText.setWrapStyleWord(1) self.jConsoleText.setRows(10) self.jScrollConsolePane = JScrollPane() self.jScrollConsolePane.setViewportView(self.jConsoleText) #set initial text self.jConsoleText.setText(Strings.console_disable) self.jMenuPanelLayout = GroupLayout(self.jMenuPanel) self.jMenuPanel.setLayout(self.jMenuPanelLayout) self.jMenuPanelLayout.setHorizontalGroup( self.jMenuPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( self.jMenuPanelLayout.createSequentialGroup().addComponent( self.jEnable).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED, 205, 32767).addComponent(self.jDocs))) self.jMenuPanelLayout.setVerticalGroup( self.jMenuPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( self.jMenuPanelLayout.createSequentialGroup().addGroup( self.jMenuPanelLayout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( self.jEnable).addComponent(self.jDocs)).addGap( 0, 7, 32767))) self.jConsolePane = JPanel() self.jConsoleLayout = GroupLayout(self.jConsolePane) self.jConsolePane.setLayout(self.jConsoleLayout) self.jConsoleLayout.setHorizontalGroup( self.jConsoleLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( self.jScrollConsolePane)) self.jConsoleLayout.setVerticalGroup( self.jConsoleLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( GroupLayout.Alignment.TRAILING, self.jConsoleLayout.createSequentialGroup().addComponent( self.jScrollConsolePane, GroupLayout.DEFAULT_SIZE, 154, 32767).addContainerGap())) self.jLeftUpPanelLayout = GroupLayout(self.jLeftUpPanel) self.jLeftUpPanel.setLayout(self.jLeftUpPanelLayout) self.jLeftUpPanelLayout.setHorizontalGroup( self.jLeftUpPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( self.jConsolePane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, 32767).addComponent(self.jMenuPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) self.jLeftUpPanelLayout.setVerticalGroup( self.jLeftUpPanelLayout. createParallelGroup(GroupLayout.Alignment.LEADING).addGroup( GroupLayout.Alignment.TRAILING, self.jLeftUpPanelLayout.createSequentialGroup().addComponent( self.jMenuPanel, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED).addComponent( self.jConsolePane, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, 32767))) self.jScrollpaneLeftDown = JScrollPane() self.jScrollpaneLeftDown.setViewportView(self.jVarsPane) self.jSplitPaneLeft = JSplitPane(JSplitPane.VERTICAL_SPLIT, self.jLeftUpPanel, self.jScrollpaneLeftDown) self.jSplitPaneLeft.setDividerLocation(300) self.jScriptPane = JTextPane() self.jScriptPane.setFont(Font('Monospaced', Font.PLAIN, 11)) self.jScriptPane.addMouseListener(self) self.JScrollPaneRight = JScrollPane() self.JScrollPaneRight.setViewportView(self.jScriptPane) self.jSplitPane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, self.jSplitPaneLeft, self.JScrollPaneRight) self.jSplitPane.setDividerLocation(400) #Load saved saved settings ##Load vars vars = callbacks.loadExtensionSetting(self._varsStorage) if vars: vars = base64.b64decode(vars) else: # try to load the example try: with open("examples/Simple-CSRF-vars.py") as fvars: vars = fvars.read() # load the default text except: vars = Strings.vars ## initiate the persistant variables locals_ = {} try: exec(vars, {}, locals_) except Exception as e: print e self._vars = locals_ ## update the vars screen self.jVarsPane.document.insertString(self.jVarsPane.document.length, vars, SimpleAttributeSet()) ##Load script script = callbacks.loadExtensionSetting(self._scriptStorage) if script: script = base64.b64decode(script) else: # try to load the example try: with open("examples/Simple-CSRF-script.py") as fscript: script = fscript.read() # load the default text except: script = Strings.script ## compile the rules self._script = script self._code = '' try: self._code = compile(script, '<string>', 'exec') except Exception as e: print( '{}\nReload extension after you correct the error.'.format(e)) ## update the rules screen self.jScriptPane.document.insertString( self.jScriptPane.document.length, script, SimpleAttributeSet()) #Register Extension callbacks.customizeUiComponent(self.getUiComponent()) callbacks.addSuiteTab(self) callbacks.registerExtensionStateListener(self) callbacks.registerHttpListener(self) self.jScriptPane.requestFocus() def getUiComponent(self): return self.jSplitPane def getTabCaption(self): return self._name def actionPerformed(self, event): #Check box was clicked if self.jEnable == event.getSource(): if self._enabled == 1: self._enabled = 0 # console content shows help self.jConsoleText.setText(Strings.console_disable) else: self._enabled = 1 # console content displays the current persistent variable state self.jConsoleText.setText(Strings.console_state) self.jConsoleText.append(pformat(self._vars)) self.jConsoleText.append(Strings.extra_line) self.jConsoleText.append(Strings.console_log) return def mouseClicked(self, event): if event.source == self.jDocs: uri = URI.create("https://github.com/DanNegrea/PyRules") if uri and Desktop.isDesktopSupported() and Desktop.getDesktop( ).isSupported(Desktop.Action.BROWSE): Desktop.getDesktop().browse(uri) return def focusGained(self, event): if self.jConsolePane == event.getSource(): pass #print "Status pane gained focus" #debug return def focusLost(self, event): #Reinitialize the persistent values if self.jVarsPane == event.getSource(): # get the text from the pane end = self.jVarsPane.document.length vars = self.jVarsPane.document.getText(0, end) # compute the new values locals_ = {} exec(vars, {}, locals_) self._vars = locals_ # display the new result in console self.jConsoleText.append(Strings.console_state) self.jConsoleText.append(pformat(self._vars)) self.jConsoleText.append(Strings.extra_line) self.jConsoleText.append(Strings.console_log) # scroll to bottom verticalScrollBar = self.jScrollConsolePane.getVerticalScrollBar() verticalScrollBar.setValue(verticalScrollBar.getMaximum()) return def extensionUnloaded(self): try: #Save the latestest vars and script text ## save vars end = self.jVarsPane.document.length vars = self.jVarsPane.document.getText(0, end) vars = base64.b64encode(vars) self.callbacks.saveExtensionSetting(self._varsStorage, vars) ## save script/rules end = self.jScriptPane.document.length script = self.jScriptPane.document.getText(0, end) script = base64.b64encode(script) self.callbacks.saveExtensionSetting(self._scriptStorage, script) except Exception: traceback.print_exc(file=self.callbacks.getStderr()) print "Unloaded" #debug return def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): if self._enabled == 0: return try: locals_ = { 'extender': self, 'callbacks': self.callbacks, 'helpers': self.helpers, 'toolFlag': toolFlag, 'messageIsRequest': messageIsRequest, 'messageInfo': messageInfo, 'log': self.log } # add the _vars as gloval variables locals_ = dict(locals_, **self._vars) # execute the script/rules try: exec(self.getCode, {}, locals_) # catch exit() call inside the rule except SystemExit: pass # update the persistant variables by searching the local variables with the same name for key in self._vars: # assumption self._vars dictionary is smaller than locals_ if key in locals_: self._vars[key] = locals_[key] except Exception: traceback.print_exc(file=self.callbacks.getStderr()) return #Returns the compiled script @property def getCode(self): end = self.jScriptPane.document.length script = self.jScriptPane.document.getText(0, end) # if the script hasn't changed return the already compile text if script == self._script: return self._code self._script = script # compile, store and return the result self._code = compile(script, '<string>', 'exec') return self._code #Log the information into the console screen def log(self, obj): # if string just append. else use pformat from pprint if isinstance(obj, str): self.jConsoleText.append(obj + "\n") else: self.jConsoleText.append(pformat(obj) + "\n") # scroll to bottom verticalScrollBar = self.jScrollConsolePane.getVerticalScrollBar() verticalScrollBar.setValue(verticalScrollBar.getMaximum()) return
def __init__(self, kconfig_file="Kconfig", config_file=".config", systemLogger=None): """[summary] Parameters ---------- kconfig_file : string (default: "Kconfig") The Kconfig configuration file config_file : string (default: ".config") The save file which will be used for loading and saving the settings systemLogger (default: None) A system logger object. If None then print statements are used for logging. """ global log if systemLogger: log = systemLogger # Load Kconfig configuration files self.kconfig = Kconfig(kconfig_file) setKConfig(self.kconfig) if os.path.isfile(config_file): log.info(self.kconfig.load_config(config_file)) elif os.path.isfile(".config"): log.info(self.kconfig.load_config(".config")) self.tree = KConfigTree(self.kconfig) self.tree.addTreeSelectionListener(self.treeSelectionChanged) jTreeSP = JScrollPane(self.tree) self.jta = JTextArea() self.jta.setEditable(False) jTextSP = JScrollPane(self.jta) toolPanel = JPanel() toolPanel.setLayout(BoxLayout(toolPanel, BoxLayout.X_AXIS)) toolPanel.setBorder(BorderFactory.createEmptyBorder(2, 0, 2, 0)) toolPanel.add(JLabel("Search: ")) jSearchPanel = JPanel() jSearchPanel.setLayout(BoxLayout(jSearchPanel, BoxLayout.X_AXIS)) self.jSearchField = JTextField() jSearchPanel.setBackground(self.jSearchField.getBackground()) jSearchPanel.setBorder(self.jSearchField.getBorder()) self.jSearchField.setBorder(None) self.jSearchField.getDocument().addDocumentListener( SearchListener(self.tree)) jSearchPanel.add(self.jSearchField) clearSearchButton = JButton(u'\u00d7', actionPerformed=self.clearSearch) d = clearSearchButton.getPreferredSize() clearSearchButton.setPreferredSize(Dimension(d.height, d.height)) clearSearchButton.setBackground(self.jSearchField.getBackground()) clearSearchButton.setBorder(None) clearSearchButton.setOpaque(False) clearSearchButton.setContentAreaFilled(False) clearSearchButton.setFocusPainted(False) jSearchPanel.add(clearSearchButton) toolPanel.add(jSearchPanel) self.showAllCheckBox = JCheckBox("Show all", actionPerformed=self.OnShowAllCheck) toolPanel.add(self.showAllCheckBox) splitPane = JSplitPane(JSplitPane.VERTICAL_SPLIT, jTreeSP, jTextSP) splitPane.setOneTouchExpandable(True) splitPane.setDividerLocation(300) treePanel = JPanel(BorderLayout()) treePanel.add(toolPanel, BorderLayout.NORTH) treePanel.add(splitPane, BorderLayout.CENTER) loadSavePanel = JPanel() loadSavePanel.setLayout(BoxLayout(loadSavePanel, BoxLayout.X_AXIS)) loadSavePanel.add( JButton("Load", actionPerformed=self.loadConfigDialog)) loadSavePanel.add( JButton("Save as", actionPerformed=self.writeConfigDialog)) self.rootPanel = JPanel() self.rootPanel.setLayout(BorderLayout()) self.rootPanel.add(loadSavePanel, BorderLayout.PAGE_START) self.rootPanel.add(treePanel, BorderLayout.CENTER)
class BurpExtender(IBurpExtender, IContextMenuFactory, ITab, IHttpListener, IMessageEditorController, AbstractTableModel): def registerExtenderCallbacks(self, callbacks): self.messages = [] self._callbacks = callbacks self._helpers = callbacks.getHelpers() self._callbacks.setExtensionName('TPLogScan') self._log = ArrayList() self._lock = Lock() self.jSplitPaneV = JSplitPane(JSplitPane.VERTICAL_SPLIT, True) self.jSplitPaneV.setDividerLocation(300) self.jSplitPaneV.setOneTouchExpandable(True) self.jPanel_top = JPanel() self.jTabbedPane = JTabbedPane(JTabbedPane.TOP) self.iRequestTextEditor = self._callbacks.createMessageEditor(self, False) self.iResponseTextEditor = self._callbacks.createMessageEditor(self, False) self.jTable = CustomTable(self) self.jTable.setShowGrid(True) self.jTable.setAutoCreateRowSorter(True) self.jTable.setAutoResizeMode(JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS) first_column_model = self.jTable.getColumnModel().getColumn(0) first_column_model.setPreferredWidth(60); first_column_model.setMaxWidth(60) first_column_model.setMinWidth(60) self.jTable.getColumnModel().getColumn(1).setPreferredWidth(300) third_column_model = self.jTable.getColumnModel().getColumn(2) third_column_model.setPreferredWidth(100) third_column_model.setMinWidth(100) self.jTable.getColumnModel().getColumn(3).setPreferredWidth(600) self.jTable.getColumnModel().getColumn(4).setPreferredWidth(100) self.jTable.getColumnModel().getColumn(5).setPreferredWidth(100) self.jScrollPane1 = JScrollPane(self.jTable) self.jScrollPane1.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED) self.jScrollPane1.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED) self.jTabbedPane.addTab("Log", self.jScrollPane1) self.jPanel_top.add(self.jTabbedPane) self.jPanel_top.setLayout(GridLayout(1,1)) self.jSplitPaneInfo = JSplitPane(JSplitPane.HORIZONTAL_SPLIT, True) self.jSplitPaneInfo.setDividerLocation(650) self.jSplitPaneInfo.setOneTouchExpandable(True) self.jPanel_reqInfo_left = JPanel() self.jPanel_respInfo_right = JPanel() self.jPanel_reqInfo_left.setLayout(BorderLayout()) self.jPanel_respInfo_right.setLayout(BorderLayout()) self.jPanel_reqInfo_left.add(self.iRequestTextEditor.getComponent(), BorderLayout.CENTER) self.jPanel_respInfo_right.add(self.iResponseTextEditor.getComponent(), BorderLayout.CENTER) self.jSplitPaneInfo.add(self.jPanel_reqInfo_left, JSplitPane.LEFT) self.jSplitPaneInfo.add(self.jPanel_respInfo_right, JSplitPane.RIGHT) self.jSplitPaneV.add(self.jPanel_top, JSplitPane.TOP) self.jSplitPaneV.add(self.jSplitPaneInfo, JSplitPane.BOTTOM) self._callbacks.customizeUiComponent(self.jSplitPaneV) self._callbacks.customizeUiComponent(self.jPanel_top) self._callbacks.customizeUiComponent(self.jTabbedPane) self._callbacks.customizeUiComponent(self.jTable) self._callbacks.customizeUiComponent(self.jScrollPane1) self._callbacks.customizeUiComponent(self.jSplitPaneInfo) self._callbacks.customizeUiComponent(self.jPanel_reqInfo_left) self._callbacks.customizeUiComponent(self.jPanel_respInfo_right) self._callbacks.addSuiteTab(self) self._callbacks.registerHttpListener(self) self._callbacks.registerContextMenuFactory(self) return def getTabCaption(self): return 'TPLogScan' def getUiComponent(self): return self.jSplitPaneV def getRowCount(self): try: return self._log.size() except: return 0 def getColumnCount(self): return 6 def getColumnName(self, columnIndex): if columnIndex == 0: return "#" if columnIndex == 1: return "Host" if columnIndex == 2: return "Method" if columnIndex == 3: return "URL" if columnIndex == 4: return "Status" if columnIndex == 5: return "Length" return "" def getValueAt(self, rowIndex, columnIndex): logEntry = self._log.get(rowIndex) url = logEntry._url.toString() url_parse = urlparse.urlparse(url) if url_parse.netloc.find(':') != -1: netloc = url_parse.netloc[:url_parse.netloc.find(':')] host = url_parse.scheme + '://' + netloc path = url_parse.path if columnIndex == 0: return rowIndex+1 if columnIndex == 1: return host if columnIndex == 2: return logEntry._method if columnIndex == 3: return path if columnIndex == 4: return logEntry._status_code if columnIndex == 5: return logEntry._length return "" def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): # tool_name = self._callbacks.getToolName(toolFlag) # if tool_name != 'Extender': if toolFlag != 1024: return if messageIsRequest: return request_info = self._helpers.analyzeRequest(messageInfo) response_info = self._helpers.analyzeResponse(messageInfo.getResponse()) response_headers = response_info.getHeaders() response_length = 0 for header in response_headers: header = header.encode('utf-8') if header.startswith("Content-Length"): response_length = int(header.replace('Content-Length: ', '')) length = response_length if response_length > 0 else 0 self._lock.acquire() row = self._log.size() self._log.add(LogEntry(toolFlag, self._callbacks.saveBuffersToTempFiles(messageInfo), request_info.getUrl(),request_info.getMethod(),response_info.getStatusCode(),length)) self.fireTableRowsInserted(row, row) self._lock.release() def getHttpService(self): return self._currentlyDisplayedItem.getHttpService() def getRequest(self): return self._currentlyDisplayedItem.getRequest() def getResponse(self): return self._currentlyDisplayedItem.getResponse() def loadMenus(self): self.menus = [] self.mainMenu = JMenu("TPLogScan") self.menus.append(self.mainMenu) menu = JMenuItem('ThinkPHP v3', None, actionPerformed=lambda x: self.eventHandler(x)) self.mainMenu.add(menu) menu = JMenuItem('ThinkPHP v5', None, actionPerformed=lambda x: self.eventHandler(x)) self.mainMenu.add(menu) def createMenuItems(self, invocation): self.loadMenus() self.messages = invocation.getSelectedMessages() return self.menus if self.menus else None def eventHandler(self, x): menuName = x.getSource().text if menuName == 'ThinkPHP v3': version = 3 elif menuName == 'ThinkPHP v5': version = 5 else: print("chose error") return for message in self.messages: url = str(self._helpers.analyzeRequest(message).getUrl()) url_parse = urlparse.urlparse(url) url = url_parse.scheme + '://' + url_parse.netloc print("[*] url: {}".format(url)) datetime_now = datetime.datetime.now() year = (datetime_now - datetime.timedelta(days=30)).year month = (datetime_now - datetime.timedelta(days=30)).month day = (datetime_now - datetime.timedelta(days=30)).day tplogscan = TPLogScan(url, version, year, month, day) log_path = tplogscan.checkLogPath() if not log_path: print("[-] {} can't get log file! ".format(url)) self._callbacks.issueAlert("{} can't get log file".format(url)) return filename_list = tplogscan.genFileName() t = threading.Thread(target=self.logScan, args=(message, version, log_path, filename_list)) t.start() def logScan(self, message, version, log_path, filename_list): http_service = message.getHttpService() old_request = self._helpers.bytesToString(message.getRequest()) old_path = self._helpers.analyzeRequest(message).getUrl().getPath() for filename in filename_list: try: new_request = old_request.replace(" " + old_path + " HTTP/", " " + log_path+filename + " HTTP/") response, status_code = self.sendRequest(http_service, new_request) if status_code != 200: continue tmp_filename = filename now_filename = '' pattern = re.compile(r"\[ (\d{4}-\d{2}-\d{2})T((\d{2}:){2}\d{2})\+08:00 \]") flag = True while flag: match_result = pattern.search(response) if not match_result: break time_str = match_result.group(1) + ' ' + match_result.group(2) timeArray = time.strptime(time_str, "%Y-%m-%d %H:%M:%S") timestamp = int(time.mktime(timeArray)) timestamp_list = [str(timestamp), str(timestamp-1), str(timestamp-2), str(timestamp-3)] for timestamp in timestamp_list: if version == 3: tmp_filename = timestamp + '-' + filename else: tmp_filename = filename[:filename.find('/')] + '/' + timestamp + '-' + filename[filename.find('/')+1:] if tmp_filename == now_filename: flag = False break new_request = old_request.replace(" " + old_path + " HTTP/", " " + log_path+tmp_filename + " HTTP/") response, status_code = self.sendRequest(http_service, new_request) if status_code == 200: now_filename = tmp_filename break except Exception as e: print("[-] error: {}".format(e)) print('[*] Log Scan complete!') def sendRequest(self, http_service, new_request): checkRequestResponse = self._callbacks.makeHttpRequest(http_service, self._helpers.stringToBytes(new_request)) status_code = self._helpers.analyzeResponse(checkRequestResponse.getResponse()).getStatusCode() print('[*] {} | {}'.format(self._helpers.analyzeRequest(checkRequestResponse).getUrl(), status_code)) return self._helpers.bytesToString(checkRequestResponse.getResponse()), status_code
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, IContextMenuFactory, ActionListener, IMessageEditorController, ITab, ITextEditor, IHttpService, IScanIssue, IHttpRequestResponseWithMarkers): def __init__(self): self.menuItem = JMenuItem('Generate Finding') self.menuItem.addActionListener(self) # implement IBurpExtender def registerExtenderCallbacks(self, callbacks): # keep a reference to our callbacks object (Burp Extensibility Feature) self._callbacks = callbacks self._helpers = callbacks.getHelpers() # set our extension name callbacks.setExtensionName("Generate Finding") callbacks.registerContextMenuFactory(self) # -- Request Response Viewers -- # # create the lower half for the Request Response tabs... # Request and response from selection self._tabbedPane = JTabbedPane() tabs = self._tabbedPane self._requestViewer = callbacks.createMessageEditor(self, True) self._responseViewer = callbacks.createMessageEditor(self, True) self._requestHighlight = callbacks.createTextEditor() self._responseHighlight = callbacks.createTextEditor() tabs.addTab("Supporting Request", self._requestViewer.getComponent()) tabs.addTab("Supporting Response", self._responseViewer.getComponent()) tabs.addTab("Request Marker Selection", self._requestHighlight.getComponent()) tabs.addTab("Response Marker Selection", self._responseHighlight.getComponent()) #self._mainFrame.setRightComponent(tabs) # set to the lower split pane print "*" * 60 print "[+] Request/Response tabs created" # -- Define Issue Details GUI & Layout-- # # Labels and Input boxes... # Issue Name self.issueNameLabel = JLabel(" Issue Name:") self.issueNameValue = JTextArea(text = str(issueNamePlaceholder), editable = True, wrapStyleWord = True, lineWrap = True, alignmentX = Component.LEFT_ALIGNMENT, size = (1, 20) ) # Issue Detail self.issueDetailLabel = JLabel(" Issue Detail:") #self.issueDetailValue = JTextField(str(issueDetailPlaceholder), 15) self.issueDetailValue = JTextArea(text = str(issueDetailPlaceholder), editable = True, wrapStyleWord = True, lineWrap = True, alignmentX = Component.LEFT_ALIGNMENT, size = (100, 20) ) # IssueBackground self.issueBackgroundLabel = JLabel(" Issue Background:") self.issueBackgroundValue = JTextArea(text = str(issueBackgroundPlaceholder), editable = True, wrapStyleWord = True, lineWrap = True, alignmentX = Component.LEFT_ALIGNMENT, size = (100, 20) ) # Remediation Detail self.issueRemediationLabel = JLabel(" Remediation Detail:") self.issueRemediationValue = JTextArea(text = str(remediationDetailPlaceholder), editable = True, wrapStyleWord = True, lineWrap = True, alignmentX = Component.LEFT_ALIGNMENT, size = (100, 20) ) # Remediation Background self.issueRemBackgroundLabel = JLabel(" Remediation Background:") self.issueRemBackgroundValue = JTextArea(text = str(remediationBackgroundPlaceholder), editable = True, wrapStyleWord = True, lineWrap = True, alignmentX = Component.LEFT_ALIGNMENT, size = (100, 20) ) # Issue URL self.issueURLLabel = JLabel(" URL (path = http://domain/path):") self.issueURLValue = JTextArea(text = str(issueURLPlaceholder), editable = True, wrapStyleWord = True, lineWrap = True, alignmentX = Component.LEFT_ALIGNMENT, size = (1, 20) ) # Issue Port self.issuePortLabel = JLabel(" Port:") self.issuePortValue = JTextArea(text = str(issuePortPlaceholder), editable = True, wrapStyleWord = True, lineWrap = True, alignmentX = Component.LEFT_ALIGNMENT, size = (1, 20) ) # Confidence self.confidenceValuesList = ("Certain","Firm","Tentative") self.issueConfienceLabel = JLabel(" Confidence [Certain, Firm or Tentative]") self.issueConfidenceValue = JComboBox(self.confidenceValuesList) # Severity self.severityValuesList = ("High","Medium","Low","Information") self.issueSeverityLabel = JLabel(" Severity [High, Medium Low or Informational]") self.issueSeverityValue = JComboBox(self.severityValuesList) # Add Finding button self.addFindingButton = JButton("Generate Finding", actionPerformed=self.createScanIssue, alignmentX=Component.CENTER_ALIGNMENT) # -- Group items for display -- # # Group items self.grpIssueSummary = JPanel(GridLayout(0,1)) self.grpIssueSummary.add(self.issueNameLabel) self.grpIssueSummary.add(self.issueNameValue) self.grpIssueSummary.add(self.issueDetailLabel) self.grpIssueSummary.add(self.issueDetailValue) self.grpIssueSummary.add(self.issueBackgroundLabel) self.grpIssueSummary.add(self.issueBackgroundValue) self.grpIssueSummary.add(self.issueRemediationLabel) self.grpIssueSummary.add(self.issueRemediationValue) self.grpIssueSummary.add(self.issueRemBackgroundLabel) self.grpIssueSummary.add(self.issueRemBackgroundValue) self.grpIssueSummary.add(self.issueURLLabel) self.grpIssueSummary.add(self.issueURLValue) self.grpIssueSummary.add(self.issuePortLabel) self.grpIssueSummary.add(self.issuePortValue) self.grpIssueSummary.add(self.issueURLLabel) self.grpIssueSummary.add(self.issueURLValue) self.grpIssueSummary.add(self.issuePortLabel) self.grpIssueSummary.add(self.issuePortValue) self.grpRatingBoxes = JPanel() self.grpRatingBoxes.add(self.issueSeverityLabel) self.grpRatingBoxes.add(self.issueSeverityValue) self.grpRatingBoxes.add(self.issueConfienceLabel) self.grpRatingBoxes.add(self.issueConfidenceValue) self.grpRatingBoxes.add(self.addFindingButton) # add grps to details frame self._detailsPanel = JPanel(GridLayout(0,1)) self._detailsPanel.add(self.grpIssueSummary) self._detailsPanel.add(self.grpRatingBoxes) self._findingDetailsPane = JScrollPane(self._detailsPanel) # create the main frame to hold details self._detailsViewer = self._findingDetailsPane # creates a form for details #tabs.addTab("Finding Details", self._detailsViewer) self._mainFrame = JSplitPane(JSplitPane.VERTICAL_SPLIT, self._detailsViewer, tabs) self._mainFrame.setOneTouchExpandable(True); self._mainFrame.setDividerLocation(0.5) self._mainFrame.setResizeWeight(0.50) print "[+] Finding details panel created" print "[+] Rendering..." # customize our UI components callbacks.customizeUiComponent(self._mainFrame) callbacks.customizeUiComponent(self._tabbedPane) callbacks.customizeUiComponent(self._detailsPanel) callbacks.customizeUiComponent(tabs) # add the custom tab to Burp's UI callbacks.addSuiteTab(self) print "[+] Done" print "[!] Added suite tab initialize complete!" return def getTabCaption(self): return "Generate Finding" def getUiComponent(self): return self._mainFrame # initiaizes when button is clicked in 'Generate Finding Tab' def createScanIssue(self, event): print "[!] Finding Detail: " print "\t[+] Name:\n\t\t", self.issueNameValue.getText().strip() name = self.issueNameValue.getText() print "\t[+] Description:\n\t\t", self.issueDetailValue.getText().strip() description = self.issueDetailValue.getText() print "\t[+] Background:\n\t\t", self.issueBackgroundValue.getText().strip() background = self.issueBackgroundValue.getText() print "\t[+] Remediation:\n\t\t", self.issueRemediationValue.getText().strip() remediation = self.issueRemediationValue.getText() print "\t[+] Remediation Background:\n\t\t", self.issueRemBackgroundValue.getText().strip() remBackground = self.issueRemBackgroundValue.getText() print "\t[+] URL Detail:\n\t\t", self.issueURLValue.getText() urlDetail = self.issueURLValue.getText() print "\t[+] Port Number:\n\t\t", self.issuePortValue.getText() portNumber = self.issuePortValue.getText() print "\t[+] Confidence Rating:\n\t\t", self.issueConfidenceValue.getSelectedItem() confidenceRating = self.issueConfidenceValue.getSelectedItem() print "\t[+] Severity Rating:\n\t\t", self.issueSeverityValue.getSelectedItem() severityRating = self.issueSeverityValue.getSelectedItem() #print "\t[+] Payload Markers:\n\t\t", self.getSelectionBounds() # get highlighted data from request/response tabs in 'Generate Finding' #print "[!] Request Selected data:", self._requestViewer.getSelectedData() #highRequest = self._requestViewer.getSelectedData() #print "converted:", self._helpers.bytesToString(highRequest) #print "[!] Response Selected data:", self._responseViewer.getSelectedData() #highResponse = self._responseViewer.getSelectedData() #print "converted:", self._helpers.bytesToString(highResponse) # current message is used - should work as long as menu item 'Generate Finding' is not reset or used before finding has been generated. requestResponse = self.current_message print "\t[+] RequestResponse:\n\t\t", requestResponse print "\t[+] Service:\n\t\t", requestResponse.getHttpService() # Collect request and Response Markers... #print "[**] Request Bounds: ", self._requestHighlight.getSelectionBounds() requestBounds = self._requestHighlight.getSelectionBounds() #print "[**] Response Bounds: ", self._responseHighlight.getSelectionBounds() responseBounds = self._responseHighlight.getSelectionBounds() # applyMarkers to request/response # callbacks.applyMarkers(requestResponse, None, [array('i', (data[1], data[2]))]) self.reqMarkers = [requestBounds[0],requestBounds[1]] print "\t[+] Request Reporting Markers:\n\t\t", self.reqMarkers self.resMarkers = [responseBounds[0],responseBounds[1]] print "\t[+] Response Reporting Markers:\n\t\t", self.resMarkers print "*" * 60 print "[!] Attempting to create custom scan issue." # Call AddScanItem class to create scan issue!! finding_array = [urlDetail, name, 134217728, severityRating, confidenceRating, background, remBackground, description, remediation, requestResponse] issue = ScanIssue(self, finding_array, self.current_message, self.reqMarkers, self.resMarkers, self._helpers, self._callbacks) self._callbacks.addScanIssue(issue) # Done print "[+] Finding Generated!" def getRequestResponseText(self): messages = self.ctxMenuInvocation.getSelectedMessages() # parses currently selected finding to a string if len(messages) == 1 : for self.m in messages: requestResponse = self.m # add requestResponseWithMarkers to be global so can be included in scanIssue self.current_message = requestResponse # get request data and convert to string requestDetail = requestResponse.getRequest() try: requestData = self._helpers.bytesToString(requestDetail) # converts & Prints out the entire request as string except: requestData = '[-] No Request Detail in this RequestResponse' pass # get response data and convert to string responseDetail = requestResponse.getResponse() try: responseData = self._helpers.bytesToString(responseDetail) # converts & Prints out the entire request as string except: responseData = '[-] No Response Detail in this RequestResponse' pass requestData = self._helpers.bytesToString(requestDetail) # converts & Prints out the entire request as string # send request string to 'Supporting Request' tab - 'True' because it is a request! self._requestViewer.setMessage(requestData, True) # for higlighting markers.. self._requestHighlight.setText(requestData) # send response string to 'Supporting Response' tab self._responseViewer.setMessage(responseData, False) # set False as is a response not request... # for higlighting markers.. self._responseHighlight.setText(responseData) def getFindingDetails(self): messages = self.ctxMenuInvocation.getSelectedMessages() print "*" * 60 print "[+] Handling selected request: ", self.current_message if len(messages) == 1: for m in messages: # URL #print "[!] Selected Request's URL: \n", self._helpers.analyzeRequest(m).getUrl() self.issueURLValue.setText(str(self._helpers.analyzeRequest(m).getUrl())) # update finding info # Protocol #print "[!] Request's Protocol: \n", m.getProtocol() # Request Port #print "[!] Request's Port: \n", m.getPort() self.issuePortValue.setText(str(m.getPort())) # update finding info print "*" * 60 # API hook... def getHttpMessages(self): return [self.m] # Actions on menu click... def actionPerformed(self, actionEvent): print "*" * 60 print "[+] Request sent to 'Generate Finding'" try: # When clicked!! self.getRequestResponseText() self.getFindingDetails() except: tb = traceback.format_exc() print tb # create Menu def createMenuItems(self, ctxMenuInvocation): self.ctxMenuInvocation = ctxMenuInvocation return [self.menuItem]