Ejemplo n.º 1
0
class TypeStack(object):
    class Pair(object):
        def __init__(self, first, second):
            self.first = first
            self.second = second

    def __init__(self):
        self.stack = ArrayList()

    def push(self, first, second):
        self.stack.append(self.Pair(first, second))

    def pop(self, first, second):
        if len(self.stack):
            self.stack.pop()
        #v = len(self.stack) - 1
        #if v in self.stack: self.stack.remove(v)

    def contains(self, first, second):
        for p in self.stack:
            if (p.first is first
                    and p.second is second) or (p.first is second
                                                and p.second is first):
                return True
        return False
Ejemplo n.º 2
0
class BurpExtender(IBurpExtender, ITab, IHttpListener, AbstractTableModel, IContextMenuFactory):
    
    #
    # implement IBurpExtender
    #
    
    def registerExtenderCallbacks(self, callbacks):
        # set default values
        ## Pre-defined
        callbacks.setExtensionName("Body2Header")
        self._imenu_description = "Add this URL to the scope of Body2Header"
        self._remove_description = "Remove this URL from the scope"
        self._scopes = ArrayList()
        ## User-defined
        self._header_name_default = "X-CSRF-Token"
        self._value_source_regex_default = re.compile("<meta name=\"csrf-token\" content=\"(.*?)\">", re.MULTILINE)
        self._csrf_token = ""



        # store callbacks set an alias for stdout and helpers
        self._callbacks = callbacks
        self._out = callbacks.getStdout()
        self._helpers = callbacks.getHelpers()

        # initialize GUI
        callbacks.registerContextMenuFactory(self)
        self.initializeGUI()
        callbacks.addSuiteTab(self)
        
        # register ourselves as an HTTP listener
        callbacks.registerHttpListener(self)

      
    def log(self, message):
        self._out.write("[{0}] {1}\n".format(datetime.now().isoformat(),message))        
    #
    # implement IHttpListener
    #
    
    def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
        # only process if tools are in the setting
        if not self._checkboxes[toolFlag].isSelected():
            return None

        request_url = self._helpers.analyzeRequest(messageInfo).getUrl()

        if not messageIsRequest:
            body = self._helpers.bytesToString(messageInfo.getResponse()).encode('utf-8')
            for scope in self._scopes:
                if not scope.isMatch(request_url): continue
                csrf_token_b = scope.value_regex.search(body)
                if csrf_token_b != None:
                    scope.stored_value = csrf_token_b.group(1)
                    self.log("New value for {0}: {1}".format(scope.header_name, scope.stored_value))

        # only process requests/responses in the scope
        for scope in self._scopes:
            if not scope.isMatch(request_url): continue
            # Intercept and modify the request
            if messageIsRequest:            
                request = messageInfo.getRequest() 
                requestInfo = self._helpers.analyzeRequest(request)
            
                # update headers
                headers = requestInfo.getHeaders()
                headers = [h for h in headers if not h.startswith(scope.header_name+':')]
                if scope.header_name != "" and scope.stored_value != "":
                    headers.append(scope.header_name + ': ' + scope.stored_value)
                    self.log("{0} was added to the current request.".format(scope.header_name))


                # fetching body to rebubild the request
                body = request[requestInfo.getBodyOffset():]
                updatedRequest = self._helpers.buildHttpMessage(headers, body)
                messageInfo.setRequest(updatedRequest)                



    # Utilities
    def updateTokenSourceRegex(self, e):
        row = self._url_table.getSelectedRow()
        if row == -1:
            return
        self._scopes[row].value_regex = re.compile(self._form_value_regex.getText(), re.MULTILINE)
        self._label_value_regex_now_2.setText(self._scopes[row].value_regex.pattern)
        self.fireTableRowsUpdated(row, row)

        
    def updateHeaderName(self, e):
        row = self._url_table.getSelectedRow()
        if row == -1:
            return
        self._scopes[row].header_name = self._form_header.getText()
        self._label_header_now_2.setText(self._scopes[row].header_name)
        self.fireTableRowsUpdated(row, row)
        
    def addURLDirectly(self, e):
        row = self._scopes.size()
        self._scopes.add(ScopeInfo(self._form_add_url.getText(), self._value_source_regex_default, 
                                   url_regex = re.compile(self._form_add_url.getText(), re.MULTILINE), header_name = self._header_name_default))
        self._form_add_url.setText("")
        self.fireTableRowsInserted(row, row)
    
    def removeFromScope(self, invocation):
        index_to_delete = self._url_table.getSelectedRow()
        self._scopes.pop(index_to_delete)
        self.fireTableRowsDeleted(index_to_delete, index_to_delete)

    def addToScope(self, invocation):
        messagesInfo = self._add_invocation.getSelectedMessages()
        row = self._scopes.size()
        for messageInfo in messagesInfo:
            self._scopes.add(ScopeInfo(self._helpers.analyzeRequest(messageInfo).getUrl(), self._value_source_regex_default, header_name = self._header_name_default))
        self.fireTableRowsInserted(row, row)

    #
    # implement IContextMenuFactory
    #

    def createMenuItems(self, invocation):
        self._add_invocation = invocation
        self._imenu = JMenuItem(self._imenu_description, actionPerformed=self.addToScope)
        return [self._imenu]

    #
    # extend AbstractTableModel
    #
    
    def getRowCount(self):
        try:
            return self._scopes.size()
        except:
            return 0

    def getColumnCount(self):
        return 3

    def getColumnName(self, columnIndex):
        if columnIndex == 0:
            return "URL Regex"
        if columnIndex == 1:
            return "Value Regex"
        if columnIndex == 2:
            return "Header Name"
        return ""

    def getValueAt(self, rowIndex, columnIndex):
        if columnIndex == 0:
            return self._scopes[rowIndex].url_regex.pattern
        if columnIndex == 1:
            return self._scopes[rowIndex].value_regex.pattern
        if columnIndex == 2:
            return self._scopes[rowIndex].header_name
        return ""

    #
    # implement ITab
    #    

    def getTabCaption(self):
        return "Body2Header"
    
    def getUiComponent(self):
        return self._splitpane

    #
    # GUI settings
    #

    def initializeGUI(self):
        # table panel of scope entries
        self._url_table = Table(self)
        table_popup = JPopupMenu();
        remove_item_menu = JMenuItem(self._remove_description, actionPerformed=self.removeFromScope)
        table_popup.add(remove_item_menu)
        self._url_table.setComponentPopupMenu(table_popup)
        self._url_table.addMouseListener(TableMouseListener(self._url_table))
        scrollPane = JScrollPane(self._url_table)

        # setting panel              

        ##  locate checkboxes
        ### for constants, see: https://portswigger.net/burp/extender/api/constant-values.html#burp.IBurpExtenderCallbacks.TOOL_PROXY          
        self._checkboxes = {
            2:    JCheckBox('Target'),
            4:    JCheckBox('Proxy'),
            8:    JCheckBox('Spider'),
            16:   JCheckBox('Scanner'),
            32:   JCheckBox('Intruder'),            
            64:   JCheckBox('Repeater'),
            128:  JCheckBox('Sequencer'),
            1024: JCheckBox('Extender')
        }
        checkboxes_components = {0: dict(zip(range(1,len(self._checkboxes) + 1), self._checkboxes.values()))}

        self._label_value_regex_now_1 = JLabel("(1) Regex for the value to store: ")
        self._label_value_regex_now_2 = JLabel("")
        self._label_value_regex = JLabel("(1) New regex:")
        self._form_value_regex = JTextField("", 64)
        self._button_value_regex = JButton('Update', actionPerformed=self.updateTokenSourceRegex)        
        self._label_header_now_1 = JLabel("(2) Header for sending the value: ")
        self._label_header_now_2 = JLabel("")
        self._label_header = JLabel("(2) New header key: ")
        self._form_header = JTextField("", 64)
        self._button_header = JButton('Update', actionPerformed=self.updateHeaderName)
        self._label_add_url = JLabel("Add this URL: ")
        self._form_add_url = JTextField("", 64)
        self._button_add_url = JButton('Add', actionPerformed=self.addURLDirectly)
                
        ## logate regex settings
        ui_components_for_settings_pane = {
            0: { 0: JLabel("Local Settings:") },
            1: { 0: self._label_value_regex_now_1, 1: self._label_value_regex_now_2 },
            2: { 0: self._label_value_regex, 1: self._form_value_regex, 2: self._button_value_regex},
            3: { 0: self._label_header_now_1, 1: self._label_header_now_2 },
            4: { 0: self._label_header, 1: self._form_header, 2: self._button_header},
            5: { 0: {'item': JSeparator(JSeparator.HORIZONTAL), 'width': 3, }},
            6: { 0: JLabel("General Settings:") },
            7: { 0: self._label_add_url, 1: self._form_add_url, 2: self._button_add_url},
            8: { 0: JLabel("Use this extender in:"), 1: {'item': self.compose_ui(checkboxes_components), 'width': 3} }
        }
        # build a split panel & set UI component
        self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT)
        self._splitpane.setResizeWeight(0.85)
        self._splitpane.setLeftComponent(scrollPane)
        self._splitpane.setRightComponent(self.compose_ui(ui_components_for_settings_pane))
        self._callbacks.customizeUiComponent(self._splitpane)
     
    def compose_ui(self, components):
        panel = JPanel() 
        panel.setLayout(GridBagLayout())
        constraints= GridBagConstraints()
        constraints.fill = GridBagConstraints.HORIZONTAL
        constraints.insets = Insets(2, 1, 2, 1)
        for i in components:
            for j in components[i]:
                constraints.gridy, constraints.gridx = i, j
                constraints.gridwidth = components[i][j]['width'] if type(components[i][j]) == dict and 'width' in components[i][j] else 1
                constraints.gridheight = components[i][j]['height'] if type(components[i][j]) == dict and 'height' in components[i][j] else 1
                item = components[i][j]['item'] if type(components[i][j]) == dict and 'item' in components[i][j] else components[i][j]
                panel.add(item, constraints)
        return panel