├── README.md └── rexsser.py /README.md: -------------------------------------------------------------------------------- 1 | # rexsser 2 | This is a burp plugin (python) that extracts keywords from response using regexes and test for reflected XSS on the target scope. Valid parameters reflected, vulnerable parameters are show in results in the rexsser extension tab. 3 | 4 | ### Regexes 5 | - extract all javascript 'var' names from response page 6 | - ... 7 | 8 | ### Screenshots 9 | 10 |  11 | 12 | ### Requirements 13 | - Jython 14 | - BurpSuite 15 | 16 | ### Todo 17 | 18 | - [ ] Add Multiple regexes to extract words (Example: input elements in the page response) 19 | - [x] Content-Type filter 20 | - [x] Scope checkbox 21 | - [x] Process only given status-codes 22 | - [x] Turn off/on 23 | -------------------------------------------------------------------------------- /rexsser.py: -------------------------------------------------------------------------------- 1 | from burp import IBurpExtender 2 | from burp import IHttpListener 3 | from burp import IProxyListener 4 | from burp import IExtensionHelpers 5 | from burp import IScannerListener 6 | from burp import IExtensionStateListener 7 | from burp import IParameter 8 | from java.io import PrintWriter 9 | from java.net import URLEncoder 10 | from burp import ITab 11 | from threading import Thread 12 | from burp import IHttpListener 13 | from burp import IMessageEditorController 14 | from java.awt import Component; 15 | from java.io import PrintWriter; 16 | from java.awt.event import MouseAdapter 17 | from java.awt.event import ItemListener 18 | from javax.swing import RowFilter 19 | from java.util import ArrayList; 20 | from java.util import List; 21 | from javax.swing import JScrollPane; 22 | from javax.swing import JSplitPane; 23 | from javax.swing import JTabbedPane; 24 | from javax.swing import JCheckBox 25 | from javax.swing import JTable 26 | from javax.swing import JButton 27 | from javax.swing import JTextArea 28 | from javax.swing import JToggleButton 29 | from javax.swing import JPanel 30 | from javax.swing import JLabel 31 | from javax.swing import SwingUtilities; 32 | from javax.swing import BoxLayout 33 | from javax.swing.table import AbstractTableModel; 34 | from threading import Lock 35 | from java.awt import Color 36 | 37 | import re 38 | import threading 39 | 40 | 41 | 42 | class BurpExtender(IBurpExtender, IHttpListener, IProxyListener, IScannerListener, IExtensionStateListener, ITab, IMessageEditorController, AbstractTableModel): 43 | 44 | def registerExtenderCallbacks(self, callbacks): 45 | # set our extension name 46 | self._callbacks = callbacks 47 | self.ATTRIBUTE_QUOTES = "(\".*\")|(\'.*\')" 48 | callbacks.setExtensionName("Rexsser") 49 | # obtain our output stream 50 | self._stdout = PrintWriter(callbacks.getStdout(), True) 51 | self._helpers = callbacks.getHelpers() 52 | # register ourselves as an HTTP listener 53 | 54 | self._log = ArrayList() 55 | self._lock = Lock() 56 | 57 | # main split pane 58 | self._splitpane = JSplitPane(JSplitPane.VERTICAL_SPLIT) 59 | 60 | # table of log entries 61 | logTable = Table(self) 62 | scrollPane = JScrollPane(logTable) 63 | self.logTable = logTable 64 | self._splitpane.setLeftComponent(scrollPane) 65 | 66 | 67 | splane = JSplitPane(JSplitPane.HORIZONTAL_SPLIT) 68 | btn = JToggleButton("Turn on/off") 69 | self._btn = btn 70 | panel = JPanel() 71 | panel1 = JPanel() 72 | 73 | chxbox = JCheckBox("In Scope Only") 74 | self.chxbox = chxbox 75 | panel1.add(self._btn) 76 | panel1.add(chxbox) 77 | panel.add(panel1) 78 | 79 | panel2 = JPanel() 80 | panel2.setLayout(BoxLayout(panel2, BoxLayout.Y_AXIS)) 81 | textarea = JTextArea("text/html\napplication/json") 82 | textarea.setRows(5) 83 | textarea.setColumns(5) 84 | textarea.setLineWrap(1); 85 | panel2.add(JLabel("Content Types: ")) 86 | panel2.add(textarea) 87 | panel.add(panel2) 88 | self.content_types = textarea 89 | 90 | panel3 = JPanel() 91 | 92 | panel3.add(JLabel("Status Codes: ")) 93 | txtarea = JTextArea("200,500") 94 | txtarea.setRows(3) 95 | txtarea.setLineWrap(1) 96 | self.status_codes = txtarea 97 | panel3.add(txtarea) 98 | panel3.setLayout(BoxLayout(panel3, BoxLayout.Y_AXIS)) 99 | panel.add(panel3) 100 | 101 | panel.setLayout(BoxLayout(panel,BoxLayout.Y_AXIS)) 102 | tabs = JTabbedPane() 103 | splane.setLeftComponent(panel) 104 | 105 | self._requestViewer = callbacks.createMessageEditor(self, False) 106 | self._responseViewer = callbacks.createMessageEditor(self, False) 107 | tabs.addTab("Request", self._requestViewer.getComponent()) 108 | tabs.addTab("Response", self._responseViewer.getComponent()) 109 | splane.setRightComponent(tabs) 110 | 111 | self._splitpane.setRightComponent(splane) 112 | 113 | # customize our UI components 114 | callbacks.customizeUiComponent(self._splitpane) 115 | callbacks.customizeUiComponent(logTable) 116 | callbacks.customizeUiComponent(scrollPane) 117 | callbacks.customizeUiComponent(splane) 118 | 119 | # add the custom tab to Burp's UI 120 | callbacks.addSuiteTab(self) 121 | callbacks.registerHttpListener(self) 122 | 123 | return 124 | 125 | def getTabCaption(self): 126 | return "Rexsser" 127 | 128 | def getUiComponent(self): 129 | return self._splitpane 130 | 131 | 132 | def getRowCount(self): 133 | try: 134 | return self._log.size() 135 | except: 136 | return 0 137 | 138 | def getColumnCount(self): 139 | return 4 140 | 141 | def getColumnName(self, columnIndex): 142 | if columnIndex == 0: 143 | return "Detail" 144 | if columnIndex == 1: 145 | return "Parameter" 146 | if columnIndex == 2: 147 | return "URL" 148 | if columnIndex == 3: 149 | return "WAF Status" 150 | return "" 151 | 152 | def getValueAt(self, rowIndex, columnIndex): 153 | logEntry = self._log.get(rowIndex) 154 | if columnIndex == 0: 155 | return logEntry._detail 156 | if columnIndex == 1: 157 | return logEntry._parameter 158 | if columnIndex == 2: 159 | return logEntry._url 160 | if columnIndex == 3: 161 | return logEntry._waf 162 | return "" 163 | 164 | 165 | def getHttpService(self): 166 | return self._currentlyDisplayedItem.getHttpService() 167 | 168 | def getRequest(self): 169 | return self._currentlyDisplayedItem.getRequest() 170 | 171 | def getResponse(self): 172 | return self._currentlyDisplayedItem.getResponse() 173 | 174 | def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo): 175 | if messageIsRequest: 176 | return 177 | if not self._btn.isSelected(): 178 | return 179 | code = self._helpers.analyzeResponse(messageInfo.getResponse()).getStatusCode() 180 | content_type = self._helpers.analyzeResponse(messageInfo.getResponse()).getStatedMimeType() 181 | statuscodes = self.status_codes.getText().split(",") 182 | content_types = self.content_types.getText().split("\n") 183 | 184 | cts = [x.split("/")[1].upper() for x in content_types] 185 | print(content_type+str(cts)) 186 | if not str(code) in statuscodes: 187 | return 188 | if not content_type in cts: 189 | return 190 | self.toolFlag = toolFlag 191 | patt = "var (\w+).*=.*(.*)" 192 | payloads = ["fixedvaluehopefullyexists","random1'ss","random2\"ss","dummss","