class PrefsPanel(JPanel): """JPanle with gui for tool preferences """ def __init__(self, app): strings = app.strings self.setLayout(GridLayout(3, 2, 5, 5)) userLbl = JLabel(strings.getString("osmose_pref_username")) self.userTextField = JTextField(20) self.userTextField.setToolTipText( strings.getString("osmose_pref_username_tooltip")) levelLbl = JLabel(strings.getString("osmose_pref_level")) self.levels = ["1", "1,2", "1,2,3", "2", "3"] self.levelsCombo = JComboBox(self.levels) self.levelsCombo.setToolTipText( strings.getString("osmose_pref_level_tooltip")) limitLbl = JLabel(strings.getString("osmose_pref_limit")) self.limitTextField = JTextField(20) self.limitTextField.setToolTipText( strings.getString("osmose_pref_limit_tooltip")) self.add(userLbl) self.add(self.userTextField) self.add(levelLbl) self.add(self.levelsCombo) self.add(limitLbl) self.add(self.limitTextField) def update_gui(self, preferences): """Update preferences gui """ self.userTextField.setText(preferences["username"]) self.levelsCombo.setSelectedIndex( self.levels.index(preferences["level"])) self.limitTextField.setText(str(preferences["limit"])) def read_gui(self): """Read preferences from gui """ username = self.userTextField.getText() level = self.levelsCombo.getSelectedItem() limit = self.limitTextField.getText() try: limit = Integer.parseInt(limit) if limit > 500: limit = 500 limit = str(limit) except NumberFormatException: limit = "" preferences = { "username": username.strip(), "level": level, "limit": limit } return preferences
class PrefsPanel(JPanel): """JPanle with gui for tool preferences """ def __init__(self, app): strings = app.strings self.setLayout(GridLayout(3, 2, 5, 5)) userLbl = JLabel(strings.getString("osmose_pref_username")) self.userTextField = JTextField(20) self.userTextField.setToolTipText(strings.getString("osmose_pref_username_tooltip")) levelLbl = JLabel(strings.getString("osmose_pref_level")) self.levels = ["1", "1,2", "1,2,3", "2", "3"] self.levelsCombo = JComboBox(self.levels) self.levelsCombo.setToolTipText(strings.getString("osmose_pref_level_tooltip")) limitLbl = JLabel(strings.getString("osmose_pref_limit")) self.limitTextField = JTextField(20) self.limitTextField.setToolTipText(strings.getString("osmose_pref_limit_tooltip")) self.add(userLbl) self.add(self.userTextField) self.add(levelLbl) self.add(self.levelsCombo) self.add(limitLbl) self.add(self.limitTextField) def update_gui(self, preferences): """Update preferences gui """ self.userTextField.setText(preferences["username"]) self.levelsCombo.setSelectedIndex(self.levels.index(preferences["level"])) self.limitTextField.setText(str(preferences["limit"])) def read_gui(self): """Read preferences from gui """ username = self.userTextField.getText() level = self.levelsCombo.getSelectedItem() limit = self.limitTextField.getText() try: limit = Integer.parseInt(limit) if limit > 500: limit = 500 limit = str(limit) except NumberFormatException: limit = "" preferences = {"username": username.strip(), "level": level, "limit": limit} return preferences
def addDetails(self): jf0 = JFrame() jf0.setTitle("Add Issue"); jf0.setLayout(None); txtEnterIssue = JTextField(); txtEnterIssue.setName("Enter Issue Name"); txtEnterIssue.setToolTipText("Enter Issue Name Here"); txtEnterIssue.setBounds(182, 58, 473, 40); jf0.add(txtEnterIssue); txtEnterIssue.setColumns(10); btnNewButton = JButton("Add"); btnNewButton.setBounds(322, 178, 139, 41); jf0.add(btnNewButton); comboBox = JComboBox(); comboBox.setMaximumRowCount(20); comboBox.setEditable(True); comboBox.setToolTipText("Objective Name"); comboBox.setBounds(182, 125, 473, 40); jf0.add(comboBox); lblNewLabel = JLabel("Issue Name Here"); lblNewLabel.setFont(Font("Tahoma", Font.PLAIN, 16)); lblNewLabel.setBounds(25, 58, 130, 40); jf0.add(lblNewLabel); lblNewLabel_1 = JLabel("Objective Name"); lblNewLabel_1.setFont(Font("Tahoma", Font.PLAIN, 16)); lblNewLabel_1.setBounds(25, 125, 130, 40); jf0.add(lblNewLabel_1); jf0.setVisible(True) jf0.setBounds(400, 300, 700, 300) jf0.EXIT_ON_CLOSE txtEnterIssue.addKeyListener(self)
class BurpExtender(IBurpExtender, IHttpListener, IMessageEditorTabFactory, ITab): # # implement IBurpExtender # def registerExtenderCallbacks(self, callbacks): global EXTENSION_NAME sys.stdout = callbacks.getStdout() sys.stderr = callbacks.getStderr() # keep a reference to our callbacks object self._callbacks = callbacks # obtain an extension helpers object self._helpers = callbacks.getHelpers() # set our extension name callbacks.setExtensionName(EXTENSION_NAME) # register ourselves as a Http Listener callbacks.registerHttpListener(self) # register ourselves as a message editor tab factory callbacks.registerMessageEditorTabFactory(self) # setup the UI self.initGui() # add the custom tab to Burp's UI self._callbacks.addSuiteTab(self) return # # create the Gui # def initGui(self): #~ if DEBUG: #~ import pdb; #~ pdb.set_trace() tabPane = JTabbedPane(JTabbedPane.TOP) CreditsText = "<html># Burp Custom Deserializer<br/># Copyright (c) 2016, Marco Tinari<br/>#<br/># This program is free software: you can redistribute it and/or modify<br/># it under the terms of the GNU General Public License as published by<br/># the Free Software Foundation, either version 3 of the License, or<br/># (at your option) any later version.<br/>#<br/># This program is distributed in the hope that it will be useful,<br/># but WITHOUT ANY WARRANTY; without even the implied warranty of<br/># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br/># GNU General Public License for more details.<br/>#<br/># You should have received a copy of the GNU General Public License<br/># along with this program. If not, see <http://www.gnu.org/licenses/>.)<br/></html>" label1 = JLabel( "<html>Usage:<br>1 - Select the desired encoding functions<br>2 - Enter the name of the parameter in the input field below and press the Apply button!</html>" ) label2 = JLabel(CreditsText) panel1 = JPanel() #set layout panel1.setLayout(GridLayout(11, 1)) panel2 = JPanel() panel1.add(label1) panel2.add(label2) tabPane.addTab("Configuration", panel1) tabPane.addTab("Credits", panel2) applyButton = JButton('Apply', actionPerformed=self.reloadConf) panel1.add(applyButton, BorderLayout.SOUTH) #define GET/POST/COOKIE radio button self.GETparameterTypeRadioButton = JRadioButton('GET parameter') self.POSTparameterTypeRadioButton = JRadioButton('POST parameter') self.COOKIEparameterTypeRadioButton = JRadioButton('COOKIE parameter') self.POSTparameterTypeRadioButton.setSelected(True) group = ButtonGroup() group.add(self.GETparameterTypeRadioButton) group.add(self.POSTparameterTypeRadioButton) group.add(self.COOKIEparameterTypeRadioButton) self.base64Enabled = JCheckBox("Base64 encode") self.URLEnabled = JCheckBox("URL encode") self.ASCII2HexEnabled = JCheckBox("ASCII to Hex") self.ScannerEnabled = JCheckBox( "<html>Enable serialization in Burp Scanner<br>Usage:<br>1.Place unencoded values inside intruder request and define the placeholder positions<br>2.rightclick->Actively scan defined insertion points)</html>" ) self.IntruderEnabled = JCheckBox( "<html>Enable serialization in Burp Intruder<br>Usage:<br>1.Place unencoded values inside intruder request and define the placeholder positions<br>2.Start the attack</html>" ) self.parameterName = JTextField("Parameter name goes here...", 60) #set the tooltips self.parameterName.setToolTipText( "Fill in the parameter name and apply") self.base64Enabled.setToolTipText("Enable base64 encoding/decoding") self.ASCII2HexEnabled.setToolTipText( "Enable ASCII 2 Hex encoding/decoding") self.URLEnabled.setToolTipText("Enable URL encoding/decoding") self.IntruderEnabled.setToolTipText( "Check this if You want the extension to intercept and modify every request made by the Burp Intruder containing the selected paramter" ) self.ScannerEnabled.setToolTipText( "Check this if You want the extension to intercept and modify every request made by the Burp Scanner containing the selected paramter" ) #add checkboxes to the panel panel1.add(self.parameterName) panel1.add(self.POSTparameterTypeRadioButton) panel1.add(self.GETparameterTypeRadioButton) panel1.add(self.COOKIEparameterTypeRadioButton) panel1.add(self.base64Enabled) panel1.add(self.URLEnabled) panel1.add(self.ASCII2HexEnabled) panel1.add(self.IntruderEnabled) panel1.add(self.ScannerEnabled) #assign tabPane self.tab = tabPane def reloadConf(self, event): #~ if DEBUG: #~ import pdb; pdb.set_trace() source = event.getSource() print 'APPLY button clicked. New configuration loaded.' global MAGIC_PARAMETER global PARAMETERISPOST global PARAMETERISGET global PARAMETERISCOOKIE global BASE64ENCODINGENABLED global ASCII2HEXENCODINGENABLED global URLENCODINGENABLED global INTRUDERENABLED global SCANNERENABLED MAGIC_PARAMETER = self.parameterName.getText() print 'Base64 checkbox is: ' + str(self.base64Enabled.isSelected()) if self.base64Enabled.isSelected(): BASE64ENCODINGENABLED = True else: BASE64ENCODINGENABLED = False print 'ASCII2Hex checkbox is: ' + str( self.ASCII2HexEnabled.isSelected()) if self.ASCII2HexEnabled.isSelected(): ASCII2HEXENCODINGENABLED = True else: ASCII2HEXENCODINGENABLED = False print 'URL checkbox is: ' + str(self.URLEnabled.isSelected()) if self.URLEnabled.isSelected(): URLENCODINGENABLED = True else: URLENCODINGENABLED = False print 'New Magic parameter is: ' + str(MAGIC_PARAMETER) if self.POSTparameterTypeRadioButton.isSelected(): #BODYPARAM PARAMETERISPOST = True print "parameterispost has been set to: " + str(PARAMETERISPOST) else: PARAMETERISPOST = False print "parameterispost has been set to: " + str(PARAMETERISPOST) if self.GETparameterTypeRadioButton.isSelected(): #GETPARAM PARAMETERISGET = True print "parameterisget has been set to: " + str(PARAMETERISGET) else: PARAMETERISGET = False print "parameterisget has been set to: " + str(PARAMETERISGET) if self.COOKIEparameterTypeRadioButton.isSelected(): #COOKIEPARAM PARAMETERISCOOKIE = True print "parameteriscookie has been set to: " + str( PARAMETERISCOOKIE) else: PARAMETERISCOOKIE = False print "parameteriscookie has been set to: " + str( PARAMETERISCOOKIE) if self.ScannerEnabled.isSelected(): SCANNERENABLED = True print "Scanner Enabled" else: SCANNERENABLED = False if self.IntruderEnabled.isSelected(): INTRUDERENABLED = True print "Intruder Enabled" else: INTRUDERENABLED = False # # implement IHTTPListener # def processHttpMessage(self, toolFlag, messageIsRequest, currentRequest): global PARAMETERISPOST global PARAMETERISGET global PARAMETERISCOOKIE global URLENCODINGENABLED global BASE64ENCODINGENABLED global ASCII2HEXENCODINGENABLED global INTRUDERENABLED global SCANNERENABLED #only process requests if not messageIsRequest: return #only process messages from Intruder and Scanner, otherwise exit #if (not self._callbacks.TOOL_INTRUDER == toolFlag): if ((not ( (self._callbacks.TOOL_INTRUDER == toolFlag) and INTRUDERENABLED)) and (not ((self._callbacks.TOOL_SCANNER == toolFlag) and SCANNERENABLED))): #print "exiting- toolflag:"+str(toolFlag)+' INTRUDERENABLED='+str(INTRUDERENABLED)+' SCANNERENABLED='+str(SCANNERENABLED) return #if ((not self._callbacks.TOOL_INTRUDER == toolFlag)) and ((not self._callbacks.TOOL_SCANNER == toolFlag)):#remove the comment to always enable if DEBUG: print "IHTTPListener Enabled in: " + str(toolFlag) requestInfo = self._helpers.analyzeRequest(currentRequest) timestamp = datetime.now() if DEBUG: print "Intercepting message at: ", timestamp.isoformat() #parameters = requestInfo.getParameters() dataParameter = self._helpers.getRequestParameter( currentRequest.getRequest(), MAGIC_PARAMETER) #FIXME: add exception handling for multiple parameters with the same name and/or in a different position!!! if DEBUG: print 'dataparameter:' + str(dataParameter) if (dataParameter == None): if DEBUG: print 'Parameter does not exist' return serializedValue = dataParameter.getValue() #FIXME: substitute '[AND]' placeholder with '&' charachter - we should do something more elegant here :/ serializedValue = re.sub(r'\[AND\]', '&', serializedValue) print "unserialized parameter value: ", str(serializedValue) if BASE64ENCODINGENABLED: #if base64Encode is selected serializedValue = self._helpers.base64Encode(serializedValue) if DEBUG: print "base64 encoded parameter value: ", str(serializedValue) if URLENCODINGENABLED: #if URLEncode is selected serializedValue = self._helpers.urlEncode(serializedValue) if DEBUG: print "URL ecoded parameter value: ", str(serializedValue) if ASCII2HEXENCODINGENABLED: #if ASCII2HexEncode is selected serializedValue = convert_ascii2hex(serializedValue) if DEBUG: print "ASCII2Hex ecoded parameter value: ", str( serializedValue) print "serialized parameter value: ", serializedValue if PARAMETERISPOST: if DEBUG: print "parameter is BODY" currentRequest.setRequest( self._helpers.updateParameter( currentRequest.getRequest(), self._helpers.buildParameter(MAGIC_PARAMETER, serializedValue, IParameter.PARAM_BODY))) elif PARAMETERISGET: if DEBUG: print "parameter is in URL" currentRequest.setRequest( self._helpers.updateParameter( currentRequest.getRequest(), self._helpers.buildParameter(MAGIC_PARAMETER, serializedValue, IParameter.PARAM_URL))) elif PARAMETERISCOOKIE: if DEBUG: print "parameter is a COOKIE" currentRequest.setRequest( self._helpers.updateParameter( currentRequest.getRequest(), self._helpers.buildParameter(MAGIC_PARAMETER, serializedValue, IParameter.PARAM_COOKIE))) return # # implement ITab # def getTabCaption(self): global EXTENSION_TABCAPTION return (EXTENSION_TABCAPTION) def getUiComponent(self): #~ return self._splitpane return self.tab # # implement IMessageEditorTabFactory # def createNewInstance(self, controller, editable): # create a new instance of our custom editor tab return CustomInputTab(self, controller, editable)
class BurpExtender(IBurpExtender, IScannerCheck, IScanIssue, ITab): def registerExtenderCallbacks(self, callbacks): self.callbacks = callbacks self.helpers = callbacks.getHelpers() callbacks.setExtensionName("Missing Scanner Checks") self.out = callbacks.getStdout() # define all checkboxes self.cbPassiveChecks = self.defineCheckBox("Passive Scanner Checks") self.cbDOMXSS = self.defineCheckBox("DOM XSS", False) self.cbDOMXSSSources = self.defineCheckBox("Sources", False) self.cbDOMXSSSinks = self.defineCheckBox("Sinks") self.cbDOMXSSjQuerySinks = self.defineCheckBox("jQuery Sinks", False) self.grpDOMXSSSettings = JPanel() self.grpDOMXSSSettings.add(self.cbDOMXSSSources) self.grpDOMXSSSettings.add(self.cbDOMXSSSinks) self.grpDOMXSSSettings.add(self.cbDOMXSSjQuerySinks) self.cbSTS = self.defineCheckBox("Strict Transport Security") self.lblSTSMin = JLabel("Minimum acceptable max-age") self.inSTSMin = JTextField(str(STSMinimum), 9, actionPerformed=self.setSTSMinimum) # TODO: actionPerformed only fires on enter key - focus lost would be better self.inSTSMin.setToolTipText("Enter the minimum max-age value which is considered as acceptable. Press return to change setting!") self.grpSTSSettings = JPanel() self.grpSTSSettings.add(self.lblSTSMin) self.grpSTSSettings.add(self.inSTSMin) self.cbXCTO = self.defineCheckBox("Content Sniffing") self.cbXXP = self.defineCheckBox("Client-side XSS Filter Configuration") self.cbRedirToHTTPS = self.defineCheckBox("Redirection from HTTP to HTTPS") self.btnSave = JButton("Set as default", actionPerformed=self.saveConfig) self.btnRestore = JButton("Restore", actionPerformed=self.restoreConfig) self.grpConfig = JPanel() self.grpConfig.add(self.btnSave) self.grpConfig.add(self.btnRestore) self.restoreConfig() # definition of config tab self.tab = JPanel() layout = GroupLayout(self.tab) self.tab.setLayout(layout) layout.setAutoCreateGaps(True) layout.setAutoCreateContainerGaps(True) layout.setHorizontalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(self.cbPassiveChecks) ) .addGroup(layout.createParallelGroup() .addComponent(self.cbDOMXSS) .addComponent(self.cbSTS) .addComponent(self.cbXCTO) .addComponent(self.cbXXP) .addComponent(self.cbRedirToHTTPS) ) .addGroup(layout.createParallelGroup() .addComponent(self.grpDOMXSSSettings, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(self.grpSTSSettings, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(self.grpConfig, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ) ) layout.setVerticalGroup( layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(self.cbPassiveChecks) .addComponent(self.cbDOMXSS) .addComponent(self.grpDOMXSSSettings, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ) .addGroup(layout.createParallelGroup() .addComponent(self.cbSTS) .addComponent(self.grpSTSSettings, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ) .addComponent(self.cbXCTO) .addComponent(self.cbXXP) .addComponent(self.cbRedirToHTTPS) .addComponent(self.grpConfig, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE) ) self.domXSSSourcesRE = re.compile("(location\s*[\[.])|([.\[]\s*[\"']?\s*(arguments|dialogArguments|innerHTML|write(ln)?|open(Dialog)?|showModalDialog|cookie|URL|documentURI|baseURI|referrer|name|opener|parent|top|content|self|frames)\W)|(localStorage|sessionStorage|Database)") # NOTE: done some optimizations here, original RE caused too much noise # - added leading dot in the first part - original recognized "<a href=..." etc. # - removed "value" in first part self.domXSSSinksRE = re.compile("(\.(src|href|data|location|code|action)\s*[\"'\]]*\s*\+?\s*=)|((replace|assign|navigate|getResponseHeader|open(Dialog)?|showModalDialog|eval|evaluate|execCommand|execScript|setTimeout|setInterval)\s*[\"'\]]*\s*\()") self.domXSSjQuerySinksRE = re.compile("after\(|\.append\(|\.before\(|\.html\(|\.prepend\(|\.replaceWith\(|\.wrap\(|\.wrapAll\(|\$\(|\.globalEval\(|\.add\(|jQUery\(|\$\(|\.parseHTML\(") self.headerSTSRE = re.compile("^Strict-Transport-Security:.*?max-age=\"?(\d+)\"?", re.I) # TODO: multiple max-age directives cause confusion! self.headerXCTORE = re.compile("^X-Content-Type-Options:\s*nosniff\s*$", re.I) self.headerXXP = re.compile("^X-XSS-Protection:\s*(\d)(?:\s*;\s*mode\s*=\s*\"?(block)\"?)?", re.I) self.headerLocationHTTPS = re.compile("^(?:Content-)?Location:\s*(https://.*)$", re.I) callbacks.registerScannerCheck(self) callbacks.addSuiteTab(self) def defineCheckBox(self, caption, selected=True, enabled=True): checkBox = JCheckBox(caption) checkBox.setSelected(selected) checkBox.setEnabled(enabled) return checkBox def setSTSMinimum(self, e=None): val = self.inSTSMin.text if re.match("^\d+$", val): STSMinimum = int(val) else: self.inSTSMin.setText(str(STSMinimum)) # TODO: doesn't works as desired def saveConfig(self, e=None): config = { 'passiveChecks': self.cbPassiveChecks.isSelected(), 'DOMXSS': self.cbDOMXSS.isSelected(), 'DOMXSSSources': self.cbDOMXSSSources.isSelected(), 'DOMXSSSinks': self.cbDOMXSSSinks.isSelected(), 'DOMXSSjQuerySinks': self.cbDOMXSSjQuerySinks.isSelected(), 'STS': self.cbSTS.isSelected(), 'STSMin': self.inSTSMin.text, 'XCTO': self.cbXCTO.isSelected(), 'XXP': self.cbXXP.isSelected(), 'RedirToHTTPS': self.cbRedirToHTTPS.isSelected(), } self.callbacks.saveExtensionSetting("config", pickle.dumps(config)) def restoreConfig(self, e=None): storedConfig = self.callbacks.loadExtensionSetting("config") if storedConfig != None: try: config = pickle.loads(storedConfig) self.cbPassiveChecks.setSelected(config['passiveChecks']) self.cbDOMXSS.setSelected(config['DOMXSS']) self.cbDOMXSSSources.setSelected(config['DOMXSSSources']) self.cbDOMXSSSinks.setSelected(config['DOMXSSSinks']) self.cbDOMXSSjQuerySinks.setSelected(config['DOMXSSjQuerySinks']) self.cbSTS.setSelected(config['STS']) self.inSTSMin.text = config['STSMin'] self.cbXCTO.setSelected(config['XCTO']) self.cbXXP.setSelected(config['XXP']) self.cbRedirToHTTPS.setSelected(config['RedirToHTTPS']) self.setSTSMinimum() except: print("Classical case of \"shouldn't happen\": something went wrong with config restore. Submit a bug or patch and keep your eyes open for Zombies. Something is really strange here.\nConfig contained: " + storedConfig) ### ITab ### def getTabCaption(self): return("Additional Scanner Checks") def getUiComponent(self): return self.tab ### IScannerCheck ### def doPassiveScan(self, baseRequestResponse): if not self.cbPassiveChecks.isSelected(): return None scanIssues = list() requestProtocol = baseRequestResponse.getHttpService().getProtocol() analyzedResponse = self.helpers.analyzeResponse(baseRequestResponse.getResponse()) responseHeaders = analyzedResponse.getHeaders() bodyOffset = analyzedResponse.getBodyOffset() responseBody = baseRequestResponse.getResponse()[analyzedResponse.getBodyOffset():].tostring() # Identify DOMXSS sources and sinks domXSSSources = list() domXSSSinks = list() domXSSjQuerySinks = list() if self.cbDOMXSS.isSelected(): if self.cbDOMXSSSources.isSelected(): domXSSSources = self.domXSSSourcesRE.finditer(responseBody) if self.cbDOMXSSSinks.isSelected(): domXSSSinks = self.domXSSSinksRE.finditer(responseBody) if self.cbDOMXSSjQuerySinks.isSelected(): domXSSjQuerySinks = self.domXSSjQuerySinksRE.finditer(responseBody) domXSSSourcesPos = extractMatchPositions(domXSSSources, bodyOffset) domXSSSinksPos = extractMatchPositions(domXSSSinks, bodyOffset) domXSSjQuerySinksPos = extractMatchPositions(domXSSjQuerySinks, bodyOffset) if len(domXSSSourcesPos) + len(domXSSSinksPos) + len(domXSSjQuerySinksPos) > 0: # One of the DOMXSS REs matched scanIssues.append(DOMXSSScanIssue( baseRequestResponse, domXSSSourcesPos, domXSSSinksPos, domXSSjQuerySinksPos, self.helpers, self.callbacks )) # Identify missing, wrong or multiple occurring HTTP headers headersSTS = list() headersXCTO = list() headersXXP = list() headersLocationHTTPS = list() offset = 0 for header in responseHeaders: if self.cbSTS.isSelected(): match = self.headerSTSRE.match(header) if match: headersSTS.append((match, offset)) if self.cbXCTO.isSelected(): match = self.headerXCTORE.match(header) if match: headersXCTO.append(match) if self.cbXXP.isSelected(): match = self.headerXXP.match(header) if match: headersXXP.append((match, offset)) if self.cbRedirToHTTPS.isSelected() and requestProtocol == 'http': match = self.headerLocationHTTPS.match(header) if match: headersLocationHTTPS.append((match, offset)) offset += len(header) + 2 # TODO: assumption that CRLF is always used. The world is ugly, make a real check. if requestProtocol != "https": pass # HSTS only valid in HTTPS responses. elif self.cbSTS.isSelected(): if len(headersSTS) == 0: # No HSTS header scanIssues.append(STSScanIssue( baseRequestResponse, STSScanIssue.caseNoHeader, None, self.helpers, self.callbacks )) elif len(headersSTS) == 1 and int(headersSTS[0][0].group(1)) < STSMinimum: # HSTS header present, but time frame too short scanIssues.append(STSScanIssue( baseRequestResponse, STSScanIssue.caseTooLow, (int(headersSTS[0][0].group(1)), headersSTS[0][1] + headersSTS[0][0].start(1), headersSTS[0][1] + headersSTS[0][0].end(1)), self.helpers, self.callbacks )) elif len(headersSTS) > 1: # multiple HSTS headers scanIssues.append(STSScanIssue( baseRequestResponse, STSScanIssue.caseMultipleHeaders, headersSTS, self.helpers, self.callbacks )) # Redirection from HTTP to HTTPS if self.cbRedirToHTTPS.isSelected() and len(headersLocationHTTPS) > 0: scanIssues.append(RedirectFromHTTP2HTTPSScanIssue( baseRequestResponse, headersLocationHTTPS, self.helpers, self.callbacks )) if self.cbXXP.isSelected(): if len(headersXXP) == 0: # No XSS protection header scanIssues.append(XXPScanIssue( baseRequestResponse, XXPScanIssue.caseNoHeader, None, self.helpers, self.callbacks )) elif len(headersXXP) == 1 and int(headersXXP[0][0].group(1)) == 1 and headersXXP[0][0].group(2) != "block": # Activated but not in block mode scanIssues.append(XXPScanIssue( baseRequestResponse, XXPScanIssue.caseNoBlockMode, headersXXP, self.helpers, self.callbacks )) elif len(headersXXP) > 1: # Multiple XXP headers scanIssues.append(XXPScanIssue( baseRequestResponse, XXPScanIssue.caseMultipleHeaders, headersXXP, self.helpers, self.callbacks )) # "X-XSS-Protection: 0" already catched by Burp # X-Content-Type-Options missing # NOTE: it is assumed that multiple "X-Content-Type-Options: nosniff" headers can't cause confusion at browser side because they all have the same meaning. if self.cbXCTO.isSelected() and len(headersXCTO) == 0: scanIssues.append(XCTOScanIssue( baseRequestResponse, self.helpers, self.callbacks )) return scanIssues def consolidateDuplicateIssues(self, existingIssue, newIssue): if existingIssue.getIssueName() == newIssue.getIssueName(): if newIssue.getIssueName() == issueNameDOMXSS: # DOMXSS issues are different if response content is different. responseExisting = existingIssue.getHttpMessages()[0].getResponse() analyzedResponseExisting = self.helpers.analyzeResponse(responseExisting) bodyOffsetExisting = analyzedResponseExisting.getBodyOffset() responseBodyExisting = responseExisting.getResponse()[analyzedResponseExisting.getBodyOffset():].tostring() responseNew = newIssue.getHttpMessages()[0].getResponse() analyzedResponseNew = self.helpers.analyzeResponse(responseNew) bodyOffsetNew = analyzedResponseNew.getBodyOffset() responseBodyNew = responseNew.getResponse()[analyzedResponseNew.getBodyOffset():].tostring() if responseBodyExisting == responseBodyNew: return -1 else: return 0 elif newIssue.getIssueName() == issueNameRedirectFromHTTP2HTTPS: # Redirection issues are different if target URLs differ if existingIssue.getIssueDetail() == newIssue.getIssueDetail(): return -1 else: return 0 else: # In all other cases: keep existing issue return -1 return 0
class BurpExtender(IBurpExtender, IHttpListener, IMessageEditorTabFactory, ITab): # # implement IBurpExtender # def registerExtenderCallbacks(self, callbacks): global EXTENSION_NAME sys.stdout = callbacks.getStdout() sys.stderr = callbacks.getStderr() # keep a reference to our callbacks object self._callbacks = callbacks # obtain an extension helpers object self._helpers = callbacks.getHelpers() # set our extension name callbacks.setExtensionName(EXTENSION_NAME) # register ourselves as a Http Listener callbacks.registerHttpListener(self) # register ourselves as a message editor tab factory callbacks.registerMessageEditorTabFactory(self) # setup the UI self.initGui() # add the custom tab to Burp's UI self._callbacks.addSuiteTab(self) return # # create the Gui # def initGui(self): #~ if DEBUG: #~ import pdb; #~ pdb.set_trace() tabPane = JTabbedPane(JTabbedPane.TOP) CreditsText = "<html># Burp Custom Deserializer<br/># Copyright (c) 2016, Marco Tinari<br/>#<br/># This program is free software: you can redistribute it and/or modify<br/># it under the terms of the GNU General Public License as published by<br/># the Free Software Foundation, either version 3 of the License, or<br/># (at your option) any later version.<br/>#<br/># This program is distributed in the hope that it will be useful,<br/># but WITHOUT ANY WARRANTY; without even the implied warranty of<br/># MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br/># GNU General Public License for more details.<br/>#<br/># You should have received a copy of the GNU General Public License<br/># along with this program. If not, see <http://www.gnu.org/licenses/>.)<br/></html>" label1 = JLabel("<html>Usage:<br>1 - Select the desired encoding functions<br>2 - Enter the name of the parameter in the input field below and press the Apply button!</html>") label2 = JLabel(CreditsText) panel1 = JPanel() #set layout panel1.setLayout(GridLayout(11,1)) panel2 = JPanel() panel1.add(label1) panel2.add(label2) tabPane.addTab("Configuration", panel1) tabPane.addTab("Credits", panel2) applyButton = JButton('Apply',actionPerformed=self.reloadConf) panel1.add(applyButton, BorderLayout.SOUTH) #define GET/POST/COOKIE radio button self.GETparameterTypeRadioButton = JRadioButton('GET parameter') self.POSTparameterTypeRadioButton = JRadioButton('POST parameter') self.COOKIEparameterTypeRadioButton = JRadioButton('COOKIE parameter') self.POSTparameterTypeRadioButton.setSelected(True) group = ButtonGroup() group.add(self.GETparameterTypeRadioButton) group.add(self.POSTparameterTypeRadioButton) group.add(self.COOKIEparameterTypeRadioButton) self.base64Enabled = JCheckBox("Base64 encode") self.URLEnabled = JCheckBox("URL encode") self.ASCII2HexEnabled = JCheckBox("ASCII to Hex") self.ScannerEnabled = JCheckBox("<html>Enable serialization in Burp Scanner<br>Usage:<br>1.Place unencoded values inside intruder request and define the placeholder positions<br>2.rightclick->Actively scan defined insertion points)</html>") self.IntruderEnabled = JCheckBox("<html>Enable serialization in Burp Intruder<br>Usage:<br>1.Place unencoded values inside intruder request and define the placeholder positions<br>2.Start the attack</html>") self.parameterName = JTextField("Parameter name goes here...",60) #set the tooltips self.parameterName.setToolTipText("Fill in the parameter name and apply") self.base64Enabled.setToolTipText("Enable base64 encoding/decoding") self.ASCII2HexEnabled.setToolTipText("Enable ASCII 2 Hex encoding/decoding") self.URLEnabled.setToolTipText("Enable URL encoding/decoding") self.IntruderEnabled.setToolTipText("Check this if You want the extension to intercept and modify every request made by the Burp Intruder containing the selected paramter") self.ScannerEnabled.setToolTipText("Check this if You want the extension to intercept and modify every request made by the Burp Scanner containing the selected paramter") #add checkboxes to the panel panel1.add(self.parameterName) panel1.add(self.POSTparameterTypeRadioButton) panel1.add(self.GETparameterTypeRadioButton) panel1.add(self.COOKIEparameterTypeRadioButton) panel1.add(self.base64Enabled) panel1.add(self.URLEnabled) panel1.add(self.ASCII2HexEnabled) panel1.add(self.IntruderEnabled) panel1.add(self.ScannerEnabled) #assign tabPane self.tab = tabPane def reloadConf(self,event): #~ if DEBUG: #~ import pdb; pdb.set_trace() source = event.getSource() print 'APPLY button clicked. New configuration loaded.' global MAGIC_PARAMETER global PARAMETERISPOST global PARAMETERISGET global PARAMETERISCOOKIE global BASE64ENCODINGENABLED global ASCII2HEXENCODINGENABLED global URLENCODINGENABLED global INTRUDERENABLED global SCANNERENABLED MAGIC_PARAMETER=self.parameterName.getText() print 'Base64 checkbox is: '+str(self.base64Enabled.isSelected()) if self.base64Enabled.isSelected(): BASE64ENCODINGENABLED=True else: BASE64ENCODINGENABLED=False print 'ASCII2Hex checkbox is: '+str(self.ASCII2HexEnabled.isSelected()) if self.ASCII2HexEnabled.isSelected(): ASCII2HEXENCODINGENABLED=True else: ASCII2HEXENCODINGENABLED=False print 'URL checkbox is: '+str(self.URLEnabled.isSelected()) if self.URLEnabled.isSelected(): URLENCODINGENABLED=True else: URLENCODINGENABLED=False print 'New Magic parameter is: '+str(MAGIC_PARAMETER) if self.POSTparameterTypeRadioButton.isSelected(): #BODYPARAM PARAMETERISPOST=True print "parameterispost has been set to: " + str(PARAMETERISPOST) else: PARAMETERISPOST=False print "parameterispost has been set to: " + str(PARAMETERISPOST) if self.GETparameterTypeRadioButton.isSelected(): #GETPARAM PARAMETERISGET=True print "parameterisget has been set to: " + str(PARAMETERISGET) else: PARAMETERISGET=False print "parameterisget has been set to: " + str(PARAMETERISGET) if self.COOKIEparameterTypeRadioButton.isSelected(): #COOKIEPARAM PARAMETERISCOOKIE=True print "parameteriscookie has been set to: " + str(PARAMETERISCOOKIE) else: PARAMETERISCOOKIE=False print "parameteriscookie has been set to: " + str(PARAMETERISCOOKIE) if self.ScannerEnabled.isSelected(): SCANNERENABLED=True print "Scanner Enabled" else: SCANNERENABLED=False if self.IntruderEnabled.isSelected(): INTRUDERENABLED=True print "Intruder Enabled" else: INTRUDERENABLED=False # # implement IHTTPListener # def processHttpMessage(self, toolFlag, messageIsRequest, currentRequest): global PARAMETERISPOST global PARAMETERISGET global PARAMETERISCOOKIE global URLENCODINGENABLED global BASE64ENCODINGENABLED global ASCII2HEXENCODINGENABLED global INTRUDERENABLED global SCANNERENABLED #only process requests if not messageIsRequest: return #only process messages from Intruder and Scanner, otherwise exit #if (not self._callbacks.TOOL_INTRUDER == toolFlag): if ((not ((self._callbacks.TOOL_INTRUDER == toolFlag) and INTRUDERENABLED)) and (not ((self._callbacks.TOOL_SCANNER == toolFlag) and SCANNERENABLED))): #print "exiting- toolflag:"+str(toolFlag)+' INTRUDERENABLED='+str(INTRUDERENABLED)+' SCANNERENABLED='+str(SCANNERENABLED) return #if ((not self._callbacks.TOOL_INTRUDER == toolFlag)) and ((not self._callbacks.TOOL_SCANNER == toolFlag)):#remove the comment to always enable if DEBUG: print "IHTTPListener Enabled in: " + str(toolFlag) requestInfo = self._helpers.analyzeRequest(currentRequest) timestamp = datetime.now() if DEBUG: print "Intercepting message at: ", timestamp.isoformat() #parameters = requestInfo.getParameters() dataParameter = self._helpers.getRequestParameter(currentRequest.getRequest(), MAGIC_PARAMETER) #FIXME: add exception handling for multiple parameters with the same name and/or in a different position!!! if DEBUG: print 'dataparameter:'+str(dataParameter) if (dataParameter == None): if DEBUG: print 'Parameter does not exist' return serializedValue = dataParameter.getValue() #FIXME: substitute '[AND]' placeholder with '&' charachter - we should do something more elegant here :/ serializedValue = re.sub(r'\[AND\]', '&', serializedValue) print "unserialized parameter value: ", str(serializedValue) if BASE64ENCODINGENABLED: #if base64Encode is selected serializedValue = self._helpers.base64Encode(serializedValue) if DEBUG: print "base64 encoded parameter value: ", str(serializedValue) if URLENCODINGENABLED: #if URLEncode is selected serializedValue = self._helpers.urlEncode(serializedValue) if DEBUG: print "URL ecoded parameter value: ", str(serializedValue) if ASCII2HEXENCODINGENABLED: #if ASCII2HexEncode is selected serializedValue = convert_ascii2hex(serializedValue) if DEBUG: print "ASCII2Hex ecoded parameter value: ", str(serializedValue) print "serialized parameter value: ", serializedValue if PARAMETERISPOST: if DEBUG: print "parameter is BODY" currentRequest.setRequest(self._helpers.updateParameter(currentRequest.getRequest(),self._helpers.buildParameter(MAGIC_PARAMETER, serializedValue,IParameter.PARAM_BODY))) elif PARAMETERISGET: if DEBUG: print "parameter is in URL" currentRequest.setRequest(self._helpers.updateParameter(currentRequest.getRequest(),self._helpers.buildParameter(MAGIC_PARAMETER, serializedValue,IParameter.PARAM_URL))) elif PARAMETERISCOOKIE: if DEBUG: print "parameter is a COOKIE" currentRequest.setRequest(self._helpers.updateParameter(currentRequest.getRequest(),self._helpers.buildParameter(MAGIC_PARAMETER, serializedValue,IParameter.PARAM_COOKIE))) return # # implement ITab # def getTabCaption(self): global EXTENSION_TABCAPTION return(EXTENSION_TABCAPTION) def getUiComponent(self): #~ return self._splitpane return self.tab # # implement IMessageEditorTabFactory # def createNewInstance(self, controller, editable): # create a new instance of our custom editor tab return CustomInputTab(self, controller, editable)
class CumulusUI(JFrame): '''Java Swing used to create a JFrame UI. On init the objects will be populated with information derived from URL requests to CUMULUS and the open CWMS watershed. ''' def __init__(self, arg_dict): super(CumulusUI, self).__init__() # Load argument from the command line self.start_time = arg_dict['start_time'] self.end_time = arg_dict['end_time'] self.dss_path = arg_dict['dss_path'] self.cwms_home = arg_dict['cwms_home'] self.config = arg_dict['config'] # Get the DSS Path if one was saved in the "cumulus.config" file if os.path.isfile(self.config): with open(os.path.join(APPDATA, "cumulus.config")) as f: self.dss_path = f.read() # Get the basins and products, load JSON, create lists for JList, and create dictionaries self.basin_download = json.loads(self.http_get(url_basins)) self.jlist_basins = ["{}:{}".format(b['office_symbol'], b['name']) for b in self.basin_download] self.basin_meta = dict(zip(self.jlist_basins, self.basin_download)) self.jlist_basins.sort() self.product_download = json.loads(self.http_get(url_products)) self.jlist_products = ["{}".format(p['name'].replace("_", " ").title()) for p in self.product_download] self.product_meta = dict(zip(self.jlist_products, self.product_download)) self.jlist_products.sort() btn_submit = JButton() lbl_start_date = JLabel() lbl_end_date = JLabel() self.txt_select_file = JTextField() btn_select_file = JButton() lbl_origin = JLabel() lbl_extent = JLabel() lbl_select_file = JLabel() self.txt_start_time = JTextField() self.txt_end_time = JTextField() jScrollPane1 = JScrollPane() self.lst_product = JList() self.lst_product = JList(self.jlist_products, valueChanged = self.choose_product) jScrollPane2 = JScrollPane() self.lst_watershed = JList() self.lst_watershed = JList(self.jlist_basins, valueChanged = self.choose_watershed) self.cwms_dssname = JCheckBox() self.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE) self.setTitle("Cumulus CAVI UI") self.setLocation(Point(10, 10)) self.setLocationByPlatform(True) self.setName("CumulusCaviUi") self.setResizable(False) btn_submit.setFont(Font("Tahoma", 0, 18)) btn_submit.setText("Submit") btn_submit.actionPerformed = self.submit lbl_start_date.setText("Start Date/Time") lbl_end_date.setText("End Date/Time") self.txt_select_file.setToolTipText("FQPN to output file (.dss)") btn_select_file.setText("...") btn_select_file.setToolTipText("Select File...") btn_select_file.actionPerformed = self.select_file lbl_origin.setText("Minimum (x,y):") lbl_extent.setText("Maximum (x,y):") lbl_select_file.setText("Output File Location") self.txt_start_time.setToolTipText("Start Time") self.txt_end_time.setToolTipText("End Time") self.lst_product.setBorder(BorderFactory.createTitledBorder(None, "Available Products", TitledBorder.CENTER, TitledBorder.TOP, Font("Tahoma", 0, 14))) self.lst_product.setFont(Font("Tahoma", 0, 14)) jScrollPane1.setViewportView(self.lst_product) self.lst_product.getAccessibleContext().setAccessibleName("Available Products") self.lst_product.getAccessibleContext().setAccessibleParent(jScrollPane2) self.lst_watershed.setBorder(BorderFactory.createTitledBorder(None, "Available Watersheds", TitledBorder.CENTER, TitledBorder.TOP, Font("Tahoma", 0, 14))) self.lst_watershed.setFont(Font("Tahoma", 0, 14)) self.lst_watershed.setSelectionMode(ListSelectionModel.SINGLE_SELECTION) jScrollPane2.setViewportView(self.lst_watershed) self.cwms_dssname.setText("CWMS DSS filename") self.cwms_dssname.setToolTipText("Parameter.yyyy.mm.dss") self.cwms_dssname.setVisible(False) layout = GroupLayout(self.getContentPane()); self.getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING, False) .addComponent(lbl_select_file) .addComponent(jScrollPane1) .addComponent(jScrollPane2) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.TRAILING) .addComponent(btn_submit) .addComponent(self.txt_select_file, GroupLayout.PREFERRED_SIZE, 377, GroupLayout.PREFERRED_SIZE)) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addComponent(btn_select_file)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(lbl_start_date) .addComponent(self.txt_start_time, GroupLayout.PREFERRED_SIZE, 170, GroupLayout.PREFERRED_SIZE)) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(self.txt_end_time, GroupLayout.PREFERRED_SIZE, 170, GroupLayout.PREFERRED_SIZE) .addComponent(lbl_end_date)))) .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ) layout.setVerticalGroup( layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addGroup(GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(25, 25, 25) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(lbl_start_date) .addComponent(lbl_end_date)) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING) .addComponent(self.txt_start_time, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(self.txt_end_time, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) .addComponent(jScrollPane2, GroupLayout.PREFERRED_SIZE, 201, GroupLayout.PREFERRED_SIZE) .addGap(18, 18, 18) .addComponent(jScrollPane1, GroupLayout.PREFERRED_SIZE, 201, GroupLayout.PREFERRED_SIZE) .addGap(18, 18, Short.MAX_VALUE) .addComponent(lbl_select_file) .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(GroupLayout.Alignment.BASELINE) .addComponent(self.txt_select_file, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE) .addComponent(btn_select_file)) .addGap(18, 18, 18) .addComponent(btn_submit) .addContainerGap()) ) self.txt_select_file.setText(self.dss_path) self.txt_start_time.setText(self.start_time) self.txt_end_time.setText(self.end_time) self.pack() self.setLocationRelativeTo(None) def http_get(self, url): '''Return java.lang.String JSON Input: java.lang.String URL ''' start_timer = System.currentTimeMillis() try: url = URL(url) urlconnect = url.openConnection() br = BufferedReader( InputStreamReader( urlconnect.getInputStream(), "UTF-8" ) ) s = br.readLine() br.close() except MalformedURLException() as ex: cumulus_logger.error(str(ex)) MessageBox.showError(str(ex), "Exception") raise except IOException as ex: cumulus_logger.error(str(ex)) MessageBox.showError(str(ex), "Exception") raise end_timer = System.currentTimeMillis() cumulus_logger.debug( "HTTP GET (milliseconds): {}".format( (end_timer - start_timer) ) ) return s def http_post(self, json_string, url): '''Return java.lang.String JSON Input: java.lang.String JSON, java.lang.String URL ''' start_timer = System.currentTimeMillis() try: # Get a connection and set the request properties url = URL(url) urlconnect = url.openConnection() urlconnect.setDoOutput(True) urlconnect.setRequestMethod("POST") urlconnect.setRequestProperty("Content-Type", "application/json; UTF-8") urlconnect.setRequestProperty("Accept", "application/json") # Write to the body bw = BufferedWriter( OutputStreamWriter( urlconnect.getOutputStream() ) ) bw.write(json_string) bw.flush() bw.close() # Read the result from the POST br = BufferedReader( InputStreamReader( urlconnect.getInputStream(), "UTF-8" ) ) s = br.readLine() br.close() except MalformedURLException() as ex: cumulus_logger.error(str(ex)) MessageBox.showError(str(ex), "Exception") raise Exception(ex) except IOException as ex: cumulus_logger.error(str(ex)) MessageBox.showError(str(ex), "Exception") raise Exception(ex) end_timer = System.currentTimeMillis() cumulus_logger.debug( "HTTP GET (milliseconds): {}".format( (end_timer - start_timer) ) ) return s def json_build(self): '''Return JSON string or 'None' if failed The returning JSON string is from the UI and used when POSTing to the Cumulus API. ''' conf = { 'datetime_start': None, 'datetime_end': None, 'watershed_id': None, 'product_id': None, } try: tf = TimeFormatter() tz = tf.zid st = tf.parse_zoned_date_time(self.txt_start_time.getText(), tz) et = tf.parse_zoned_date_time(self.txt_end_time.getText(), tz) conf['datetime_start'] = st.format(tf.iso_instant()) conf['datetime_end'] = et.format(tf.iso_instant()) except DateTimeParseException as ex: MessageBox.showWarning(ex, "Exception") selected_watershed = self.lst_watershed.getSelectedValue() selected_products = self.lst_product.getSelectedValues() if selected_watershed is not None: watershed_id = self.basin_meta[selected_watershed]['id'] conf['watershed_id'] = watershed_id else: MessageBox.showWarning( "No Watershed Selected", "Exception" ) return None product_ids = list() if len(selected_products) > 0: for p in selected_products: product_ids.append(self.product_meta[p]['id']) conf['product_id'] = product_ids else: MessageBox.showWarning( "No Products Selected", "Exception" ) return None return json.dumps(conf) def choose_product(self, event): '''The event here is a javax.swing.event.ListSelectionEvent because it comes from a Jlist. Use getValueIsAdjusting() to only get the mouse up value. ''' output_str = '''{name} After: {after} Before: {before} Parameter: {para} Unit: {u} ''' index = self.lst_product.selectedIndex if not event.getValueIsAdjusting(): pnames = self.lst_product.getSelectedValues() for pname in pnames: cumulus_logger.info("~" * 50) cumulus_logger.info("Product: {}".format(pname)) cumulus_logger.info( "After time: {}".format(self.product_meta[pname]['after'])) cumulus_logger.info( "Before time: {}".format(self.product_meta[pname]['before'])) cumulus_logger.info( "Parameter: {}".format(self.product_meta[pname]['parameter'])) cumulus_logger.info( "unit: {}".format(self.product_meta[pname]['unit'])) def choose_watershed(self, event): '''The event here is a javax.swing.event.ListSelectionEvent because it comes from a Jlist. Use getValueIsAdjusting() to only get the mouse up value. ''' index = self.lst_watershed.selectedIndex if not event.getValueIsAdjusting(): _dict = self.basin_meta[self.lst_watershed.getSelectedValue()] def select_file(self, event): '''Provide the user a JFileChooser to select the DSS file data is to download to. Event is a java.awt.event.ActionEvent ''' fc = FileChooser(self.txt_select_file) fc.title = "Select Output DSS File" _dir = os.path.dirname(self.dss_path) fc.set_current_dir(File(_dir)) fc.show() def submit(self, event): '''Collect user inputs and initiate download of DSS files to process. Event is a java.awt.event.ActionEvent ''' start_timer = end_timer = System.currentTimeMillis() # Build the JSON from the UI inputs and POST if we have JSON json_string = self.json_build() cumulus_logger.debug("JSON String Builder: {}".format(json_string)) if json_string is not None: cumulus_logger.info("*" * 50) cumulus_logger.info("Initiated Cumulus Product Request") cumulus_logger.info("*" * 50) post_result = self.http_post(json_string, url_downloads) json_post_result = json.loads(post_result) id = json_post_result['id'] max_timeout = 180 while max_timeout > 0: get_result = self.http_get("/".join([url_downloads, id])) if get_result is not None: json_get_result = json.loads(get_result) progress = json_get_result['progress'] #100% stat = json_get_result['status'] #SUCCESS fname = json_get_result['file'] # not null cumulus_logger.info("Status: {:>10}; Progress: {:>4.1f}%; Timeout: {:>4}".format(stat, progress, max_timeout)) if stat == 'FAILED': cumulus_logger.error("Failed to load grid products.") MessageBox.showError( "Failed to load grid products.", "Failed Download" ) break if int(progress) == 100 and stat == 'SUCCESS' and fname is not None: dest_dssfile = self.txt_select_file.getText() cumulus_logger.debug("DSS Download Filname: {}".format(fname)) downloaded_dssfile = download_dss(fname) if downloaded_dssfile is not None: cumulus_logger.info("DSS file downloaded.") merged_dssfiles = merge_dss(downloaded_dssfile, dest_dssfile) if len(merged_dssfiles) > 0: end_timer = System.currentTimeMillis() msg = "DSS file downloaded and merged to: {}".format( '\n'.join([f for f in merged_dssfiles]) ) cumulus_logger.info(msg) MessageBox.showInformation(msg, "Successful Processing" ) else: msg = "DSS file merge unsuccessful" cumulus_logger.warning(msg) MessageBox.showWarning(msg, "Unsuccessful Merge" ) else: msg = "Downloading and processing the DSS file failed!" cumulus_logger.error(msg) MessageBox.showError(msg, "Failed Processing" ) break else: Thread.sleep(2000) max_timeout -= 1 cumulus_logger. info( "Submit time duration (milliseconds): {}".format( (end_timer - start_timer) ) ) # Try to clean up any dss6 and dss7 files in the temp try: tempdir = tempfile.gettempdir() dss_temp_files = os.listdir(tempdir) for f in dss_temp_files: if (f.endswith(".dss") or f.endswith(".dss")): os.remove(os.path.join(tempdir, f)) except OSError as ex: cumulus_logger.warning(str(ex))
class BurpExtender(IBurpExtender, ITab, IScannerCheck, IContextMenuFactory, IParameter, IIntruderPayloadGeneratorFactory): def registerExtenderCallbacks(self, callbacks): self.callbacks = callbacks self.helpers = callbacks.getHelpers() callbacks.setExtensionName("Session Authentication Tool") self.out = callbacks.getStdout() # definition of suite tab self.tab = JPanel(GridBagLayout()) self.tabledata = MappingTableModel(callbacks) self.table = JTable(self.tabledata) #self.table.getColumnModel().getColumn(0).setPreferredWidth(50); #self.table.getColumnModel().getColumn(1).setPreferredWidth(100); self.tablecont = JScrollPane(self.table) c = GridBagConstraints() c.fill = GridBagConstraints.HORIZONTAL c.anchor = GridBagConstraints.FIRST_LINE_START c.gridx = 0 c.gridy = 0 c.gridheight = 6 c.weightx = 0.3 c.weighty = 0.5 self.tab.add(self.tablecont, c) c = GridBagConstraints() c.weightx = 0.1 c.anchor = GridBagConstraints.FIRST_LINE_START c.gridx = 1 c.gridy = 0 label_id = JLabel("Identifier:") self.tab.add(label_id, c) self.input_id = JTextField(20) self.input_id.setToolTipText("Enter the identifier which is used by the application to identifiy a particular test user account, e.g. a numerical user id or a user name.") c.gridy = 1 self.tab.add(self.input_id, c) c.gridy = 2 label_content = JLabel("Content:") self.tab.add(label_content, c) self.input_content = JTextField(20, actionPerformed=self.btn_add_id) self.input_content.setToolTipText("Enter some content which is displayed in responses of the application and shows that the current session belongs to a particular user, e.g. the full name of the user.") c.gridy = 3 self.tab.add(self.input_content, c) self.btn_add = JButton("Add/Edit Identity", actionPerformed=self.btn_add_id) c.gridy = 4 self.tab.add(self.btn_add, c) self.btn_del = JButton("Delete Identity", actionPerformed=self.btn_del_id) c.gridy = 5 self.tab.add(self.btn_del, c) callbacks.customizeUiComponent(self.tab) callbacks.customizeUiComponent(self.table) callbacks.customizeUiComponent(self.tablecont) callbacks.customizeUiComponent(self.btn_add) callbacks.customizeUiComponent(self.btn_del) callbacks.customizeUiComponent(label_id) callbacks.customizeUiComponent(self.input_id) callbacks.addSuiteTab(self) callbacks.registerScannerCheck(self) callbacks.registerIntruderPayloadGeneratorFactory(self) callbacks.registerContextMenuFactory(self) def btn_add_id(self, e): ident = self.input_id.text self.input_id.text = "" content = self.input_content.text self.input_content.text = "" self.tabledata.add_mapping(ident, content) self.input_id.requestFocusInWindow() def btn_del_id(self, e): rows = self.table.getSelectedRows().tolist() self.tabledata.del_rows(rows) ### ITab ### def getTabCaption(self): return("SessionAuth") def getUiComponent(self): return self.tab ### IContextMenuFactory ### def createMenuItems(self, invocation): menuitems = list() msgs = invocation.getSelectedMessages() if msgs != None: if len(msgs) == 1: # "add as object id/as content to last id" context menu items bounds = invocation.getSelectionBounds() if bounds != None and bounds[0] != bounds[1]: msg = None if invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST or invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_VIEWER_REQUEST: msg = msgs[0].getRequest().tostring() if invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_RESPONSE or invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_VIEWER_RESPONSE: msg = msgs[0].getResponse().tostring() if msg != None: selection = msg[bounds[0]:bounds[1]] shortSelection = selection[:20] if len(selection) > len(shortSelection): shortSelection += "..." menuitems.append(JMenuItem("Add '" + shortSelection + "' as object id", actionPerformed=self.gen_menu_add_id(selection))) if self.tabledata.lastadded != None: menuitems.append(JMenuItem("Add '" + shortSelection + "' as content to last added id", actionPerformed=self.gen_menu_add_content(selection))) if len(msgs) > 0: # "Send to Intruder" context menu items requestsWithIds = list() for msg in msgs: if isinstance(msg.getRequest(), array) and self.tabledata.containsId(msg.getRequest().tostring()): requestsWithIds.append(msg) if len(requestsWithIds) > 0: menuitems.append(JMenuItem("Send to Intruder and preconfigure id injection points", actionPerformed=self.gen_menu_send_intruder(requestsWithIds))) return menuitems def gen_menu_add_id(self, ident): def menu_add_id(e): self.tabledata.add_mapping(ident, "") return menu_add_id def gen_menu_add_content(self, content): def menu_add_content(e): self.tabledata.set_lastadded_content(content) return menu_add_content def gen_menu_send_intruder(self, requestResponses): def menu_send_intruder(e): for requestResponse in requestResponses: httpService = requestResponse.getHttpService() request = requestResponse.getRequest() injectionPoints = list() for ident in self.tabledata.getIds(): newInjectionPoints = findAll(request.tostring(), ident) if newInjectionPoints != None: injectionPoints += newInjectionPoints if len(injectionPoints) > 0: self.callbacks.sendToIntruder(httpService.getHost(), httpService.getPort(), httpService.getProtocol() == "https", request, injectionPoints) return menu_send_intruder ### IIntruderPayloadGeneratorFactory ### def getGeneratorName(self): return "SessionAuth Identifiers" def createNewInstance(self, attack): return IdentifiersPayloadGenerator(self.tabledata) ### IScannerCheck ### def doPassiveScan(self, baseRequestResponse): analyzedRequest = self.helpers.analyzeRequest(baseRequestResponse) params = analyzedRequest.getParameters() ids = self.tabledata.getIds() issues = list() for param in params: value = param.getValue() for ident in ids: if value == ident: issues.append(SessionAuthPassiveScanIssue( analyzedRequest.getUrl(), baseRequestResponse, param, ident, self.tabledata.getValue(ident), SessionAuthPassiveScanIssue.foundEqual, self.callbacks )) elif value.find(ident) >= 0: issues.append(SessionAuthPassiveScanIssue( analyzedRequest.getUrl(), baseRequestResponse, param, ident, self.tabledata.getValue(ident), SessionAuthPassiveScanIssue.foundInside, self.callbacks )) if len(issues) > 0: return issues else: return None def doActiveScan(self, baseRequestResponse, insertionPoint): ids = self.tabledata.getIds() if len(ids) <= 1: # active check only possible if multiple ids were given return None baseVal = insertionPoint.getBaseValue() url = baseRequestResponse.getUrl() idFound = list() for ident in ids: # find all identifiers in base value if baseVal.find(ident) >= 0: idFound.append(ident) if len(idFound) == 0: # no given identifier found, nothing to do return None baseResponse = baseRequestResponse.getResponse().tostring() baseResponseBody = baseResponse[self.helpers.analyzeResponse(baseResponse).getBodyOffset():] issues = list() scannedCombos = list() for replaceId in idFound: # scanner checks: replace found id by other given ids for scanId in ids: if replaceId == scanId or set([replaceId, scanId]) in scannedCombos: continue scannedCombos.append(set([replaceId, scanId])) scanPayload = baseVal.replace(replaceId, scanId) scanRequest = insertionPoint.buildRequest(scanPayload) scanRequestResponse = self.callbacks.makeHttpRequest(baseRequestResponse.getHttpService(), scanRequest) scanResponse = scanRequestResponse.getResponse().tostring() scanResponseBody = scanResponse[self.helpers.analyzeResponse(scanResponse).getBodyOffset():] if baseResponseBody == scanResponseBody: # response hasn't changed - no issue continue # Analyze responses replaceValue = self.tabledata.getValue(replaceId) scanValue = self.tabledata.getValue(scanId) # naming convention: # first word: base || scan (response) # second word: Replace || Scan (value) if replaceValue != "": baseReplaceValueCount = len(baseResponseBody.split(replaceValue)) - 1 scanReplaceValueCount = len(scanResponseBody.split(replaceValue)) - 1 else: baseReplaceValueCount = 0 scanReplaceValueCount = 0 if scanValue != "": baseScanValueCount = len(baseResponseBody.split(scanValue)) - 1 scanScanValueCount = len(scanResponseBody.split(scanValue)) - 1 else: baseScanValueCount = 0 scanScanValueCount = 0 if scanScanValueCount == 0: # Scan identifier content value doesn't appears, but responses differ issueCase = SessionAuthActiveScanIssue.caseScanValueNotFound elif baseReplaceValueCount > 0 and baseScanValueCount == 0 and scanReplaceValueCount == 0 and scanScanValueCount == baseReplaceValueCount: # Scan identifier replaces all occurrences of the original identifier in the response issueCase = SessionAuthActiveScanIssue.caseScanValueAppearsExactly elif baseReplaceValueCount > 0 and baseScanValueCount == 0 and scanReplaceValueCount == 0 and scanScanValueCount > 0: # Scan identfiers value appears, replaced ids value disappears issueCase = SessionAuthActiveScanIssue.caseScanValueAppearsFuzzy elif baseReplaceValueCount > scanReplaceValueCount and baseScanValueCount < scanScanValueCount: # Occurence count of replaced id value decreases, scan id value increases issueCase = SessionAuthActiveScanIssue.caseDecreaseIncrease elif baseScanValueCount < scanScanValueCount: # Occurence count of scan id value increases issueCase = SessionAuthActiveScanIssue.caseScanValueIncrease else: # Remainingg cases issueCase = SessionAuthActiveScanIssue.caseOther issues.append(SessionAuthActiveScanIssue( url, baseRequestResponse, insertionPoint, scanPayload, scanRequestResponse, replaceId, replaceValue, scanId, scanValue, issueCase, self.callbacks )) if len(issues) > 0: return issues else: return None def consolidateDuplicateIssues(self, existingIssue, newIssue): if existingIssue.getIssueDetail() == newIssue.getIssueDetail(): return 1 else: return 0
class NewZoneDialog(JDialog, ActionListener, WindowListener): """Dialog for favourite zone editing """ def __init__(self, app): from java.awt import Dialog from java.awt import CardLayout JDialog.__init__(self, app.preferencesFrame, app.strings.getString("Create_a_new_favourite_zone"), Dialog.ModalityType.DOCUMENT_MODAL) self.app = app border = BorderFactory.createEmptyBorder(5, 7, 7, 7) self.getContentPane().setBorder(border) self.setLayout(BoxLayout(self.getContentPane(), BoxLayout.Y_AXIS)) self.FAVAREALAYERNAME = "Favourite zone editing" info = JLabel(self.app.strings.getString("Create_a_new_favourite_zone")) info.setAlignmentX(Component.LEFT_ALIGNMENT) #Name nameLbl = JLabel(self.app.strings.getString("fav_zone_name")) self.nameTextField = JTextField(20) self.nameTextField.setMaximumSize(self.nameTextField.getPreferredSize()) self.nameTextField.setToolTipText(self.app.strings.getString("fav_zone_name_tooltip")) namePanel = JPanel() namePanel.setLayout(BoxLayout(namePanel, BoxLayout.X_AXIS)) namePanel.add(nameLbl) namePanel.add(Box.createHorizontalGlue()) namePanel.add(self.nameTextField) #Country countryLbl = JLabel(self.app.strings.getString("fav_zone_country")) self.countryTextField = JTextField(20) self.countryTextField.setMaximumSize(self.countryTextField.getPreferredSize()) self.countryTextField.setToolTipText(self.app.strings.getString("fav_zone_country_tooltip")) countryPanel = JPanel() countryPanel.setLayout(BoxLayout(countryPanel, BoxLayout.X_AXIS)) countryPanel.add(countryLbl) countryPanel.add(Box.createHorizontalGlue()) countryPanel.add(self.countryTextField) #Type modeLbl = JLabel(self.app.strings.getString("fav_zone_type")) RECTPANEL = "rectangle" POLYGONPANEL = "polygon" BOUNDARYPANEL = "boundary" self.modesStrings = [RECTPANEL, POLYGONPANEL, BOUNDARYPANEL] modesComboModel = DefaultComboBoxModel() for i in (self.app.strings.getString("rectangle"), self.app.strings.getString("delimited_by_a_closed_way"), self.app.strings.getString("delimited_by_an_administrative_boundary")): modesComboModel.addElement(i) self.modesComboBox = JComboBox(modesComboModel, actionListener=self, editable=False) #- Rectangle self.rectPanel = JPanel() self.rectPanel.setLayout(BoxLayout(self.rectPanel, BoxLayout.Y_AXIS)) capturePane = JPanel() capturePane.setLayout(BoxLayout(capturePane, BoxLayout.X_AXIS)) capturePane.setAlignmentX(Component.LEFT_ALIGNMENT) josmP = JPanel() self.captureRBtn = JRadioButton(self.app.strings.getString("capture_area")) self.captureRBtn.addActionListener(self) self.captureRBtn.setSelected(True) self.bboxFromJosmBtn = JButton(self.app.strings.getString("get_current_area"), actionPerformed=self.on_bboxFromJosmBtn_clicked) self.bboxFromJosmBtn.setToolTipText(self.app.strings.getString("get_capture_area_tooltip")) josmP.add(self.bboxFromJosmBtn) capturePane.add(self.captureRBtn) capturePane.add(Box.createHorizontalGlue()) capturePane.add(self.bboxFromJosmBtn) manualPane = JPanel() manualPane.setLayout(BoxLayout(manualPane, BoxLayout.X_AXIS)) manualPane.setAlignmentX(Component.LEFT_ALIGNMENT) self.manualRBtn = JRadioButton(self.app.strings.getString("use_this_bbox")) self.manualRBtn.addActionListener(self) self.bboxTextField = JTextField(20) self.bboxTextField.setMaximumSize(self.bboxTextField.getPreferredSize()) self.bboxTextField.setToolTipText(self.app.strings.getString("fav_bbox_tooltip")) self.bboxTextFieldDefaultBorder = self.bboxTextField.getBorder() self.bboxTextField.getDocument().addDocumentListener(TextListener(self)) manualPane.add(self.manualRBtn) manualPane.add(Box.createHorizontalGlue()) manualPane.add(self.bboxTextField) group = ButtonGroup() group.add(self.captureRBtn) group.add(self.manualRBtn) previewPane = JPanel() previewPane.setLayout(BoxLayout(previewPane, BoxLayout.X_AXIS)) previewPane.setAlignmentX(Component.LEFT_ALIGNMENT) bboxPreviewInfo = JTextField(self.app.strings.getString("coordinates"), editable=0, border=None) bboxPreviewInfo.setMaximumSize(bboxPreviewInfo.getPreferredSize()) self.bboxPreviewTextField = JTextField(20, editable=0, border=None) self.bboxPreviewTextField.setMaximumSize(self.bboxPreviewTextField.getPreferredSize()) previewPane.add(bboxPreviewInfo) previewPane.add(Box.createHorizontalGlue()) previewPane.add(self.bboxPreviewTextField) self.rectPanel.add(capturePane) self.rectPanel.add(Box.createRigidArea(Dimension(0, 10))) self.rectPanel.add(manualPane) self.rectPanel.add(Box.createRigidArea(Dimension(0, 20))) self.rectPanel.add(previewPane) #- Polygon (closed way) drawn by hand self.polygonPanel = JPanel(BorderLayout()) self.polygonPanel.setLayout(BoxLayout(self.polygonPanel, BoxLayout.Y_AXIS)) polyInfo = JLabel("<html>%s</html>" % self.app.strings.getString("polygon_info")) polyInfo.setFont(polyInfo.getFont().deriveFont(Font.ITALIC)) polyInfo.setAlignmentX(Component.LEFT_ALIGNMENT) editPolyPane = JPanel() editPolyPane.setAlignmentX(Component.LEFT_ALIGNMENT) editPolyBtn = JButton(self.app.strings.getString("create_fav_layer"), actionPerformed=self.create_new_zone_editing_layer) editPolyBtn.setToolTipText(self.app.strings.getString("create_fav_layer_tooltip")) editPolyPane.add(editPolyBtn) self.polygonPanel.add(polyInfo) self.polygonPanel.add(Box.createRigidArea(Dimension(0, 15))) self.polygonPanel.add(editPolyPane) self.polygonPanel.add(Box.createRigidArea(Dimension(0, 15))) #- Administrative Boundary self.boundaryPanel = JPanel() self.boundaryPanel.setLayout(BoxLayout(self.boundaryPanel, BoxLayout.Y_AXIS)) boundaryInfo = JLabel("<html>%s</html>" % app.strings.getString("boundary_info")) boundaryInfo.setFont(boundaryInfo.getFont().deriveFont(Font.ITALIC)) boundaryInfo.setAlignmentX(Component.LEFT_ALIGNMENT) boundaryTagsPanel = JPanel(GridLayout(3, 3, 5, 5)) boundaryTagsPanel.setAlignmentX(Component.LEFT_ALIGNMENT) boundaryTagsPanel.add(JLabel("name =")) self.nameTagTextField = JTextField(20) boundaryTagsPanel.add(self.nameTagTextField) boundaryTagsPanel.add(UrlLabel("http://wiki.openstreetmap.org/wiki/Key:admin_level#admin_level", "admin_level =")) self.adminLevelTagTextField = JTextField(20) self.adminLevelTagTextField.setToolTipText(self.app.strings.getString("adminLevel_tooltip")) boundaryTagsPanel.add(self.adminLevelTagTextField) boundaryTagsPanel.add(JLabel(self.app.strings.getString("other_tag"))) self.optionalTagTextField = JTextField(20) self.optionalTagTextField.setToolTipText("key=value") boundaryTagsPanel.add(self.optionalTagTextField) downloadBoundariesPane = JPanel() downloadBoundariesPane.setAlignmentX(Component.LEFT_ALIGNMENT) downloadBoundariesBtn = JButton(self.app.strings.getString("download_boundary"), actionPerformed=self.on_downloadBoundariesBtn_clicked) downloadBoundariesBtn.setToolTipText(self.app.strings.getString("download_boundary_tooltip")) downloadBoundariesPane.add(downloadBoundariesBtn) self.boundaryPanel.add(boundaryInfo) self.boundaryPanel.add(Box.createRigidArea(Dimension(0, 15))) self.boundaryPanel.add(boundaryTagsPanel) self.boundaryPanel.add(Box.createRigidArea(Dimension(0, 10))) self.boundaryPanel.add(downloadBoundariesPane) self.editingPanels = {"rectangle": self.rectPanel, "polygon": self.polygonPanel, "boundary": self.boundaryPanel} #Main buttons self.okBtn = JButton(self.app.strings.getString("OK"), ImageProvider.get("ok"), actionPerformed=self.on_okBtn_clicked) self.cancelBtn = JButton(self.app.strings.getString("cancel"), ImageProvider.get("cancel"), actionPerformed=self.close_dialog) self.previewBtn = JButton(self.app.strings.getString("Preview_zone"), actionPerformed=self.on_previewBtn_clicked) self.previewBtn.setToolTipText(self.app.strings.getString("preview_zone_tooltip")) okBtnSize = self.okBtn.getPreferredSize() viewBtnSize = self.previewBtn.getPreferredSize() viewBtnSize.height = okBtnSize.height self.previewBtn.setPreferredSize(viewBtnSize) #layout self.add(info) self.add(Box.createRigidArea(Dimension(0, 15))) namePanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(namePanel) self.add(Box.createRigidArea(Dimension(0, 15))) countryPanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(countryPanel) self.add(Box.createRigidArea(Dimension(0, 15))) modeLbl.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(modeLbl) self.add(Box.createRigidArea(Dimension(0, 5))) self.add(self.modesComboBox) self.modesComboBox.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(Box.createRigidArea(Dimension(0, 15))) self.configPanel = JPanel(CardLayout()) self.configPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)) self.configPanel.add(self.rectPanel, RECTPANEL) self.configPanel.add(self.polygonPanel, POLYGONPANEL) self.configPanel.add(self.boundaryPanel, BOUNDARYPANEL) self.configPanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(self.configPanel) buttonsPanel = JPanel() buttonsPanel.add(self.okBtn) buttonsPanel.add(self.cancelBtn) buttonsPanel.add(self.previewBtn) buttonsPanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(buttonsPanel) self.addWindowListener(self) self.pack() def update_gui_from_preferences(self): self.nameTextField.setText(self.app.newZone.name) #Reset rectangle mode bboxStr = ",".join(["%0.4f" % x for x in self.app.newZone.bbox]) self.bboxTextField.setText(bboxStr) self.bboxPreviewTextField.setText(bboxStr) self.bboxFromJosmBtn.setEnabled(True) self.bboxTextField.setEnabled(False) #Reset polygon mode self.polygonAsString = "" #Reset boundary mode self.boundaryAsString = "" self.modesComboBox.setSelectedIndex(0) def actionPerformed(self, e): #Show the panel for configuring the favourite area of the #selected type if e.getSource() == self.modesComboBox: cl = self.configPanel.getLayout() selectedMode = self.modesStrings[self.modesComboBox.selectedIndex] cl.show(self.configPanel, selectedMode) #Activate bbox input for rectangular favourite zone mode elif e.getSource() == self.captureRBtn: self.bboxFromJosmBtn.setEnabled(True) self.bboxTextField.setEnabled(False) else: self.bboxFromJosmBtn.setEnabled(False) self.bboxTextField.setEnabled(True) def on_bboxFromJosmBtn_clicked(self, widget): """Read bbox currently shown in JOSM """ bbox = self.app.get_frame_bounds() self.bboxPreviewTextField.setText(",".join(["%0.4f" % x for x in bbox])) ### Manage layer for creating a new favourite zone from polygon or boundary def create_new_zone_editing_layer(self, e=None): """Open a new dataset where the user can draw a closed way to delimit the favourite area """ layer = self.get_new_zone_editing_layer() if layer is not None: self.app.mv.setActiveLayer(layer) else: Main.main.addLayer(OsmDataLayer(DataSet(), self.FAVAREALAYERNAME, None)) Main.main.parent.toFront() def get_new_zone_editing_layer(self): """Check if the layer for editing the favourite area yet exists """ for layer in self.app.mv.getAllLayers(): if layer.getName() == self.FAVAREALAYERNAME: return layer return None def remove_new_zone_editing_layer(self): layer = self.get_new_zone_editing_layer() if layer is not None: self.app.mv.removeLayer(layer) def on_zone_edited(self): """Read ways that delimit the favourite area and convert them to jts geometry """ if self.modesComboBox.getSelectedIndex() == 0: mode = "rectangle" elif self.modesComboBox.getSelectedIndex() == 1: mode = "polygon" elif self.modesComboBox.getSelectedIndex() == 2: mode = "boundary" if mode in ("polygon", "boundary"): layer = self.get_new_zone_editing_layer() if layer is not None: self.app.mv.setActiveLayer(layer) else: if mode == "polygon": msg = self.app.strings.getString("polygon_fav_layer_missing_msg") else: msg = self.app.strings.getString("boundary_fav_layer_missing_msg") JOptionPane.showMessageDialog(self, msg, self.app.strings.getString("Warning"), JOptionPane.WARNING_MESSAGE) return dataset = self.app.mv.editLayer.data areaWKT = self.read_area_from_osm_ways(mode, dataset) if areaWKT is None: print "I could not read the new favourite area." else: if mode == "polygon": self.polygonAsString = areaWKT else: self.boundaryAsString = areaWKT return mode def read_area_from_osm_ways(self, mode, dataset): """Read way in favourite area editing layer and convert them to WKT """ converter = JTSConverter(False) lines = [converter.convert(way) for way in dataset.ways] polygonizer = Polygonizer() polygonizer.add(lines) polygons = polygonizer.getPolygons() multipolygon = GeometryFactory().createMultiPolygon(list(polygons)) multipolygonWKT = WKTWriter().write(multipolygon) if multipolygonWKT == "MULTIPOLYGON EMPTY": if mode == "polygon": msg = self.app.strings.getString("empty_ways_polygon_msg") else: msg = self.app.strings.getString("empty_ways_boundaries_msg") JOptionPane.showMessageDialog(self, msg, self.app.strings.getString("Warning"), JOptionPane.WARNING_MESSAGE) return return multipolygonWKT def on_downloadBoundariesBtn_clicked(self, e): """Download puter ways of administrative boundaries from Overpass API """ adminLevel = self.adminLevelTagTextField.getText() name = self.nameTagTextField.getText() optional = self.optionalTagTextField.getText() if (adminLevel, name, optional) == ("", "", ""): JOptionPane.showMessageDialog(self, self.app.strings.getString("enter_a_tag_msg"), self.app.strings.getString("Warning"), JOptionPane.WARNING_MESSAGE) return optTag = "" if optional.find("=") != -1: if len(optional.split("=")) == 2: key, value = optional.split("=") optTag = '["%s"="%s"]' % (URLEncoder.encode(key, "UTF-8"), URLEncoder.encode(value.replace(" ", "%20"), "UTF-8")) self.create_new_zone_editing_layer() overpassurl = 'http://127.0.0.1:8111/import?url=' overpassurl += 'http://overpass-api.de/api/interpreter?data=' overpassquery = 'relation["admin_level"="%s"]' % adminLevel overpassquery += '["name"="%s"]' % URLEncoder.encode(name, "UTF-8") overpassquery += '%s;(way(r:"outer");node(w););out meta;' % optTag overpassurl += overpassquery.replace(" ", "%20") print overpassurl self.app.send_to_josm(overpassurl) ### Buttons ############################################################ def create_new_zone(self, mode): """Read data entered on gui and create a new zone """ name = self.nameTextField.getText() country = self.countryTextField.getText().upper() #error: name if name.replace(" ", "") == "": JOptionPane.showMessageDialog(self, self.app.strings.getString("missing_name_warning"), self.app.strings.getString("missing_name_warning_title"), JOptionPane.WARNING_MESSAGE) return False if name in [z.name for z in self.app.tempZones]: JOptionPane.showMessageDialog(self, self.app.strings.getString("duplicate_name_warning"), self.app.strings.getString("duplicate_name_warning_title"), JOptionPane.WARNING_MESSAGE) return False #zone type zType = mode #error: geometry type not defined if zType == "polygon" and self.polygonAsString == ""\ or zType == "boundary" and self.boundaryAsString == "": JOptionPane.showMessageDialog(self, self.app.strings.getString("zone_not_correctly_build_warning"), self.app.strings.getString("zone_not_correctly_build_warning_title"), JOptionPane.WARNING_MESSAGE) return False #geometry string if zType == "rectangle": geomString = self.bboxPreviewTextField.getText() elif zType == "polygon": geomString = self.polygonAsString else: geomString = self.boundaryAsString self.app.newZone = Zone(self.app, name, zType, geomString, country) #self.app.newZone.print_info() return True def on_okBtn_clicked(self, event): """Add new zone to temp zones """ mode = self.on_zone_edited() if self.create_new_zone(mode): self.app.tempZones.append(self.app.newZone) self.app.preferencesFrame.zonesTable.getModel().addRow([self.app.newZone.country, self.app.newZone.icon, self.app.newZone.name]) maxIndex = len(self.app.tempZones) - 1 self.app.preferencesFrame.zonesTable.setRowSelectionInterval(maxIndex, maxIndex) self.close_dialog() self.app.preferencesFrame.check_removeBtn_status() self.app.preferencesFrame.zonesTable.scrollRectToVisible( self.app.preferencesFrame.zonesTable.getCellRect( self.app.preferencesFrame.zonesTable.getRowCount() - 1, 0, True)) def on_previewBtn_clicked(self, e): """Show the favourite area on a map """ mode = self.on_zone_edited() if not self.create_new_zone(mode): return zone = self.app.newZone if zone.zType == "rectangle": wktString = zone.bbox_to_wkt_string() else: wktString = zone.wktGeom script = '/*http://stackoverflow.com/questions/11954401/wkt-and-openlayers*/' script += '\nfunction init() {' script += '\n var map = new OpenLayers.Map({' script += '\n div: "map",' script += '\n projection: new OpenLayers.Projection("EPSG:900913"),' script += '\n displayProjection: new OpenLayers.Projection("EPSG:4326"),' script += '\n layers: [' script += '\n new OpenLayers.Layer.OSM()' script += '\n ]' script += '\n });' script += '\n var wkt = new OpenLayers.Format.WKT();' script += '\n var polygonFeature = wkt.read("%s");' % wktString script += '\n var vectors = new OpenLayers.Layer.Vector("Favourite area");' script += '\n map.addLayer(vectors);' script += '\n polygonFeature.geometry.transform(map.displayProjection, map.getProjectionObject());' script += '\n vectors.addFeatures([polygonFeature]);' script += '\n map.zoomToExtent(vectors.getDataExtent());' script += '\n};' scriptFile = open(File.separator.join([self.app.SCRIPTDIR, "html", "script.js"]), "w") scriptFile.write(script) scriptFile.close() OpenBrowser.displayUrl(File.separator.join([self.app.SCRIPTDIR, "html", "favourite_area.html"])) def windowClosing(self, windowEvent): self.close_dialog() def close_dialog(self, e=None): #delete favourite zone editing layer if present self.remove_new_zone_editing_layer() self.dispose() self.app.preferencesFrame.toFront()
class PluginUI(): def __init__(self, extender): self.extender = extender self.initComponents() def showMessage(self, msg): JOptionPane.showMessageDialog(self.mainPanel, msg) def getProcessorTechName(self): return self.comboProcessorTech.getSelectedItem() def getGeneratorTechsName(self): techList = [] if self.chkGeneral.isSelected(): techList.append('General') if self.chkMAXDB.isSelected(): techList.append('SAP_MaxDB') if self.chkMSSQL.isSelected(): techList.append('MSSQL') if self.chkMSAccess.isSelected(): techList.append('MSAccess') if self.chkPostgres.isSelected(): techList.append('PostgreSQL') if self.chkOracle.isSelected(): techList.append('Oracle') if self.chkSqlite.isSelected(): techList.append('SQLite') if self.chkMysql.isSelected(): techList.append('MySQL') return techList def pastePayloadButtonAction(self, event): clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard() content = clpbrd.getContents(None) if content and content.isDataFlavorSupported(DataFlavor.stringFlavor): items = content.getTransferData(DataFlavor.stringFlavor) items = items.splitlines() for item in items: self.extender.PayloadList.append(item) self.listPayloads.setListData(self.extender.PayloadList) self.writePayloadsListFile() def loadPayloadButtonAction(self, event): fileChooser = JFileChooser() fileChooser.dialogTitle = 'Choose Payload List' fileChooser.fileSelectionMode = JFileChooser.FILES_ONLY if (fileChooser.showOpenDialog( self.mainPanel) == JFileChooser.APPROVE_OPTION): file = fileChooser.getSelectedFile() with open(file.getAbsolutePath(), 'r') as reader: for line in reader.readlines(): self.extender.PayloadList.append(line.strip('\n')) self.listPayloads.setListData(self.extender.PayloadList) self.showMessage('{} payloads loaded'.format( len(self.extender.PayloadList))) self.writePayloadsListFile() def removePayloadButtonAction(self, event): for item in self.listPayloads.getSelectedValuesList(): self.extender.PayloadList.remove(item) self.listPayloads.setListData(self.extender.PayloadList) self.writePayloadsListFile() def clearPayloadButtonAction(self, event): self.extender.PayloadList[:] = [] self.listPayloads.setListData(self.extender.PayloadList) self.writePayloadsListFile() def addPayloadButtonAction(self, event): if str(self.textNewPayload.text).strip(): self.extender.PayloadList.append(self.textNewPayload.text) self.textNewPayload.text = '' self.listPayloads.setListData(self.extender.PayloadList) self.writePayloadsListFile() def toClipboardButtonAction(self, event): self.extender.generatePayloads() result = '\n'.join(self.extender.tamperedPayloads) result = StringSelection(result) clpbrd = Toolkit.getDefaultToolkit().getSystemClipboard() clpbrd.setContents(result, None) self.showMessage('{} url encoded payload copied to clipboard'.format( len(self.extender.tamperedPayloads))) def toFileButtonAction(self, event): fileChooser = JFileChooser() fileChooser.dialogTitle = 'Save Payloads' fileChooser.fileSelectionMode = JFileChooser.FILES_ONLY if (fileChooser.showSaveDialog( self.mainPanel) == JFileChooser.APPROVE_OPTION): file = fileChooser.getSelectedFile() self.extender.generatePayloads() result = '\n' result = result.join(self.extender.tamperedPayloads) with open(file.getAbsolutePath(), 'w') as writer: writer.writelines(result) self.showMessage('{} url encoded payload written to file'.format( len(self.extender.tamperedPayloads))) def tamperPayloadButtonAction(self, event): tamperedPayloads = [] tamperFunction = self.comboProcessorTech.getSelectedItem() payloads = self.textPlainPayload.text payloads = payloads.splitlines() for payload in payloads: tamperedPayloads.append( self.extender.tamperSinglePayload(tamperFunction, payload)) result = '\n'.join(tamperedPayloads) self.textTamperedPayload.text = result def comboProcessorTechAction(self, event): varName = 'SQLiQueryTampering_comboProcessorTech' state = str(self.comboProcessorTech.getSelectedIndex()) self.extender.callbacks.saveExtensionSetting(varName, state) def OnCheck(self, event): chk = event.getSource() varName = 'SQLiQueryTampering_{}'.format(chk.text) state = str(1 if chk.isSelected() else 0) self.extender.callbacks.saveExtensionSetting(varName, state) def writePayloadsListFile(self): payloads = '\n'.join(self.extender.PayloadList) payloads = payloads.encode('utf-8') with open('payloads.lst', 'w') as writer: writer.write(payloads) def readPayloadsListFile(self): result = [] with open('payloads.lst', 'r') as reader: for line in reader.readlines(): result.append(line.strip('\n')) return result def initComponents(self): TabbedPane1 = JTabbedPane() GeneratorScrollPane = JScrollPane() GeneratorPanel = JPanel() jlbl1 = JLabel() jlbl2 = JLabel() spanePayloadList = JScrollPane() self.listPayloads = JList() pastePayloadButton = JButton( actionPerformed=self.pastePayloadButtonAction) loadPayloadButton = JButton( actionPerformed=self.loadPayloadButtonAction) removePayloadButton = JButton( actionPerformed=self.removePayloadButtonAction) clearPayloadButton = JButton( actionPerformed=self.clearPayloadButtonAction) self.textNewPayload = JTextField() addPayloadButton = JButton(actionPerformed=self.addPayloadButtonAction) jSeparator1 = JSeparator() jlbl3 = JLabel() jlbl4 = JLabel() self.chkGeneral = JCheckBox(actionPerformed=self.OnCheck) self.chkMAXDB = JCheckBox(actionPerformed=self.OnCheck) self.chkMSSQL = JCheckBox(actionPerformed=self.OnCheck) self.chkMSAccess = JCheckBox(actionPerformed=self.OnCheck) self.chkPostgres = JCheckBox(actionPerformed=self.OnCheck) self.chkOracle = JCheckBox(actionPerformed=self.OnCheck) self.chkSqlite = JCheckBox(actionPerformed=self.OnCheck) self.chkMysql = JCheckBox(actionPerformed=self.OnCheck) jlbl5 = JLabel() toClipboardButton = JButton( actionPerformed=self.toClipboardButtonAction) toFileButton = JButton(actionPerformed=self.toFileButtonAction) ProcessorScrollPane = JScrollPane() ProcessorPanel = JPanel() jLabel1 = JLabel() self.comboProcessorTech = JComboBox( itemStateChanged=self.comboProcessorTechAction) jSeparator2 = JSeparator() jLabel2 = JLabel() jLabel3 = JLabel() jScrollPane1 = JScrollPane() self.textPlainPayload = JTextArea() jLabel4 = JLabel() jScrollPane2 = JScrollPane() self.textTamperedPayload = JTextArea() tamperPayloadButton = JButton( actionPerformed=self.tamperPayloadButtonAction) jlbl1.setForeground(Color(255, 102, 51)) jlbl1.setFont(Font(jlbl1.getFont().toString(), 1, 14)) jlbl1.setText("User-Defiend Payloads") jlbl2.setText( "This payload type lets you configure a simple list of strings that are used as payloads." ) spanePayloadList.setViewportView(self.listPayloads) self.extender.PayloadList = self.readPayloadsListFile() self.listPayloads.setListData(self.extender.PayloadList) pastePayloadButton.setText("Paste") loadPayloadButton.setText("Load") removePayloadButton.setText("Remove") clearPayloadButton.setText("Clear") self.textNewPayload.setToolTipText("") addPayloadButton.setText("Add") jlbl3.setForeground(Color(255, 102, 51)) jlbl3.setFont(Font(jlbl3.getFont().toString(), 1, 14)) jlbl3.setText("Tamper Techniques") jlbl4.setText( "You can select the techniques that you want to perform processing tasks on each user-defined payload" ) self.chkGeneral.setText("General") varName = 'SQLiQueryTampering_{}'.format(self.chkGeneral.text) state = self.extender.callbacks.loadExtensionSetting(varName) if state: self.chkGeneral.setSelected(int(state)) self.chkMAXDB.setText("SAP MAX DB") varName = 'SQLiQueryTampering_{}'.format(self.chkMAXDB.text) state = self.extender.callbacks.loadExtensionSetting(varName) if state: self.chkMAXDB.setSelected(int(state)) self.chkMSSQL.setText("MS SQL Server") varName = 'SQLiQueryTampering_{}'.format(self.chkMSSQL.text) state = self.extender.callbacks.loadExtensionSetting(varName) if state: self.chkMSSQL.setSelected(int(state)) self.chkMSAccess.setText("MS Access") varName = 'SQLiQueryTampering_{}'.format(self.chkMSAccess.text) state = self.extender.callbacks.loadExtensionSetting(varName) if state: self.chkMSAccess.setSelected(int(state)) self.chkPostgres.setText("Postgres SQL") varName = 'SQLiQueryTampering_{}'.format(self.chkPostgres.text) state = self.extender.callbacks.loadExtensionSetting(varName) if state: self.chkPostgres.setSelected(int(state)) self.chkOracle.setText("Oracle") varName = 'SQLiQueryTampering_{}'.format(self.chkOracle.text) state = self.extender.callbacks.loadExtensionSetting(varName) if state: self.chkOracle.setSelected(int(state)) self.chkSqlite.setText("Sqlite") varName = 'SQLiQueryTampering_{}'.format(self.chkSqlite.text) state = self.extender.callbacks.loadExtensionSetting(varName) if state: self.chkSqlite.setSelected(int(state)) self.chkMysql.setText("MySql") varName = 'SQLiQueryTampering_{}'.format(self.chkMysql.text) state = self.extender.callbacks.loadExtensionSetting(varName) if state: self.chkMysql.setSelected(int(state)) jlbl5.setText("[?] Save the Generated/Tampered Payloads to :") toClipboardButton.setText("Clipboard") toFileButton.setText("File") GeneratorPanelLayout = GroupLayout(GeneratorPanel) GeneratorPanel.setLayout(GeneratorPanelLayout) GeneratorPanelLayout.setHorizontalGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING). addGroup(GeneratorPanelLayout.createSequentialGroup( ).addContainerGap().addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.TRAILING).addComponent( jlbl2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent( jlbl4, GroupLayout.Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent( jSeparator1, GroupLayout.Alignment.LEADING). addGroup(GeneratorPanelLayout.createSequentialGroup().addGap( 6, 6, 6).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( GeneratorPanelLayout.createSequentialGroup( ).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING, False).addComponent( removePayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent( clearPayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent( loadPayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE). addComponent(pastePayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent( addPayloadButton, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)). addGap(21, 21, 21).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING). addComponent( self.textNewPayload).addComponent( spanePayloadList))).addComponent( jlbl1).addComponent(jlbl3). addGroup(GeneratorPanelLayout.createSequentialGroup( ).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( self.chkGeneral).addComponent( self.chkMSSQL) ).addGap(18, 18, 18).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( self.chkPostgres).addComponent( self.chkMAXDB) ).addGap(18, 18, 18).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( self.chkMSAccess).addComponent( self.chkOracle) ).addGap(18, 18, 18).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( self.chkSqlite).addComponent(self.chkMysql) )).addGroup(GeneratorPanelLayout.createSequentialGroup( ).addComponent(jlbl5).addPreferredGap( LayoutStyle.ComponentPlacement. UNRELATED).addComponent(toClipboardButton).addGap( 18, 18, 18).addComponent(toFileButton, GroupLayout.PREFERRED_SIZE, 97, GroupLayout.PREFERRED_SIZE ))))).addContainerGap())) GeneratorPanelLayout.setVerticalGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING). addGroup(GeneratorPanelLayout.createSequentialGroup( ).addContainerGap().addComponent(jlbl1).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED).addComponent( jlbl2, GroupLayout.PREFERRED_SIZE, 21, GroupLayout.PREFERRED_SIZE).addGap(18, 18, 18).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( spanePayloadList, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE). addGroup(GeneratorPanelLayout.createSequentialGroup( ).addComponent(pastePayloadButton).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED ).addComponent(loadPayloadButton).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED ).addComponent(removePayloadButton).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED). addComponent(clearPayloadButton))). addPreferredGap( LayoutStyle.ComponentPlacement.RELATED).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( self.textNewPayload, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE). addComponent(addPayloadButton)).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED). addComponent(jSeparator1, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE).addPreferredGap( LayoutStyle.ComponentPlacement.RELATED). addComponent(jlbl3).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED ).addComponent(jlbl4).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( self.chkGeneral).addComponent( self.chkMAXDB).addComponent( self.chkOracle).addComponent( self.chkSqlite)). addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( self.chkMSSQL).addComponent( self.chkPostgres).addComponent( self.chkMSAccess).addComponent( self.chkMysql) ).addGap(18, 18, 18).addGroup( GeneratorPanelLayout.createParallelGroup( GroupLayout.Alignment.BASELINE).addComponent( jlbl5).addComponent(toClipboardButton). addComponent(toFileButton)).addGap(20, 20, 20))) GeneratorScrollPane.setViewportView(GeneratorPanel) TabbedPane1.addTab("Generator", GeneratorScrollPane) varName = 'SQLiQueryTampering_comboProcessorTech' state = self.extender.callbacks.loadExtensionSetting(varName) for item in self.extender.getTamperFuncsName(): self.comboProcessorTech.addItem(item) if state: self.comboProcessorTech.setSelectedIndex(int(state)) jLabel1.setText("Processor Technique :") jLabel2.setText( "Modify Plain Payloads based on the selected Processor Technique. Write one payload per line." ) jLabel3.setText("Plain Payloads:") self.textPlainPayload.setColumns(20) self.textPlainPayload.setRows(5) jScrollPane1.setViewportView(self.textPlainPayload) jLabel4.setText("Tampered Payloads:") self.textTamperedPayload.setColumns(20) self.textTamperedPayload.setRows(5) jScrollPane2.setViewportView(self.textTamperedPayload) tamperPayloadButton.setText("Tamper Payloads") ProcessorPanelLayout = GroupLayout(ProcessorPanel) ProcessorPanel.setLayout(ProcessorPanelLayout) ProcessorPanelLayout.setHorizontalGroup( ProcessorPanelLayout. createParallelGroup(GroupLayout.Alignment.LEADING).addGroup( GroupLayout.Alignment.TRAILING, ProcessorPanelLayout.createSequentialGroup().addContainerGap( GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE).addComponent( tamperPayloadButton).addContainerGap( GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ).addGroup(ProcessorPanelLayout.createSequentialGroup( ).addContainerGap().addGroup( ProcessorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent(jSeparator2). addComponent(jScrollPane1).addComponent(jScrollPane2).addGroup( ProcessorPanelLayout.createSequentialGroup().addGroup( ProcessorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( jLabel3).addComponent(jLabel4).addGroup( ProcessorPanelLayout.createSequentialGroup( ).addComponent(jLabel1).addPreferredGap( LayoutStyle.ComponentPlacement. UNRELATED).addComponent( self.comboProcessorTech, GroupLayout.PREFERRED_SIZE, 286, GroupLayout.PREFERRED_SIZE)). addComponent(jLabel2)).addGap( 0, 78, Short.MAX_VALUE))).addContainerGap())) ProcessorPanelLayout.setVerticalGroup( ProcessorPanelLayout.createParallelGroup( GroupLayout.Alignment.LEADING).addGroup( ProcessorPanelLayout.createSequentialGroup().addGap( 33, 33, 33).addGroup( ProcessorPanelLayout.createParallelGroup( GroupLayout.Alignment.BASELINE). addComponent(jLabel1).addComponent( self.comboProcessorTech, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)).addGap( 18, 18, 18).addComponent( jSeparator2, GroupLayout.PREFERRED_SIZE, 10, GroupLayout.PREFERRED_SIZE).addGap( 12, 12, 12).addComponent(jLabel2).addGap( 18, 18, 18). addComponent(jLabel3).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED).addComponent( jScrollPane1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED). addComponent(jLabel4).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED).addComponent( jScrollPane2, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE).addPreferredGap( LayoutStyle.ComponentPlacement.UNRELATED). addComponent(tamperPayloadButton).addGap(36, 36, 36))) ProcessorScrollPane.setViewportView(ProcessorPanel) TabbedPane1.addTab("Processor", ProcessorScrollPane) self.mainPanel = JPanel() layout = GroupLayout(self.mainPanel) self.mainPanel.setLayout(layout) layout.setHorizontalGroup( layout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent( TabbedPane1, GroupLayout.DEFAULT_SIZE, 701, Short.MAX_VALUE)) layout.setVerticalGroup( layout.createParallelGroup( GroupLayout.Alignment.LEADING).addComponent(TabbedPane1)) TabbedPane1.getAccessibleContext().setAccessibleName("Generator")
class PreferencesFrame(JFrame, ActionListener, WindowListener, ItemListener, HyperlinkListener): """Dialog with preferences """ def __init__(self, parent, title, app): from javax.swing import JCheckBox, JRadioButton, ButtonGroup self.app = app border = BorderFactory.createEmptyBorder(5, 7, 5, 7) self.getContentPane().setBorder(border) self.getContentPane().setLayout(BorderLayout(0, 5)) self.tabbedPane = JTabbedPane() #1 Tab: general panel1 = JPanel() panel1.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7)) panel1.setLayout(BoxLayout(panel1, BoxLayout.PAGE_AXIS)) #Checkbutton to enable/disable update check when script starts self.updateCBtn = JCheckBox(self.app.strings.getString("updateCBtn")) self.updateCBtn.setToolTipText(self.app.strings.getString("updateCBtn_tooltip")) #Download tools downloadBtn = JButton(self.app.strings.getString("updatesBtn"), ImageProvider.get("dialogs", "refresh"), actionPerformed=self.on_downloadBtn_clicked) downloadBtn.setToolTipText(self.app.strings.getString("updatesBtn_tooltip")) #Checkbuttons for enabling/disabling tools toolsPanel = JPanel(BorderLayout(0, 5)) title = self.app.strings.getString("enable_disable_tools") toolsPanel.setBorder(BorderFactory.createTitledBorder(title)) infoLbl = JLabel(self.app.strings.getString("JOSM_restart_warning")) infoLbl.setFont(infoLbl.getFont().deriveFont(Font.ITALIC)) toolsPanel.add(infoLbl, BorderLayout.PAGE_START) toolsStatusPane = JPanel(GridLayout(len(self.app.realTools), 0)) self.toolsCBtns = [] for tool in self.app.realTools: toolCBtn = JCheckBox() toolCBtn.addItemListener(self) toolLbl = JLabel(tool.title, tool.bigIcon, JLabel.LEFT) self.toolsCBtns.append(toolCBtn) toolPane = JPanel() toolPane.setLayout(BoxLayout(toolPane, BoxLayout.X_AXIS)) toolPane.add(toolCBtn) toolPane.add(toolLbl) toolsStatusPane.add(toolPane) toolsPanel.add(toolsStatusPane, BorderLayout.CENTER) #Radiobuttons for enabling/disabling layers when a new one #is added layersPanel = JPanel(GridLayout(0, 1)) title = self.app.strings.getString("errors_layers_manager") layersPanel.setBorder(BorderFactory.createTitledBorder(title)) errorLayersLbl = JLabel(self.app.strings.getString("errors_layers_info")) errorLayersLbl.setFont(errorLayersLbl.getFont().deriveFont(Font.ITALIC)) layersPanel.add(errorLayersLbl) self.layersRBtns = {} group = ButtonGroup() for mode in self.app.layersModes: layerRBtn = JRadioButton(self.app.strings.getString("%s" % mode)) group.add(layerRBtn) layersPanel.add(layerRBtn) self.layersRBtns[mode] = layerRBtn #Max number of errors text field self.maxErrorsNumberTextField = JTextField() self.maxErrorsNumberTextField.setToolTipText(self.app.strings.getString("maxErrorsNumberTextField_tooltip")) self.maxErrorsNumberTFieldDefaultBorder = self.maxErrorsNumberTextField.getBorder() self.maxErrorsNumberTextField.getDocument().addDocumentListener(ErrNumTextListener(self)) #layout self.updateCBtn.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(self.updateCBtn) panel1.add(Box.createRigidArea(Dimension(0, 15))) downloadBtn.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(downloadBtn) panel1.add(Box.createRigidArea(Dimension(0, 15))) toolsPanel.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(toolsPanel) panel1.add(Box.createRigidArea(Dimension(0, 15))) layersPanel.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(layersPanel) panel1.add(Box.createRigidArea(Dimension(0, 15))) maxErrP = JPanel(BorderLayout(5, 0)) maxErrP.add(JLabel(self.app.strings.getString("max_errors_number")), BorderLayout.LINE_START) maxErrP.add(self.maxErrorsNumberTextField, BorderLayout.CENTER) p = JPanel(BorderLayout()) p.add(maxErrP, BorderLayout.PAGE_START) p.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(p) self.tabbedPane.addTab(self.app.strings.getString("tab_1_title"), None, panel1, None) #2 Tab: favourite zones panel2 = JPanel(BorderLayout(5, 15)) panel2.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7)) #status topPanel = JPanel() topPanel.setLayout(BoxLayout(topPanel, BoxLayout.Y_AXIS)) infoPanel = HtmlPanel(self.app.strings.getString("fav_zones_info")) infoPanel.getEditorPane().addHyperlinkListener(self) infoPanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.favZoneStatusCBtn = JCheckBox(self.app.strings.getString("activate_fav_area"), actionListener=self) self.favZoneStatusCBtn.setToolTipText(self.app.strings.getString("activate_fav_area_tooltip")) self.favZoneStatusCBtn.setAlignmentX(Component.LEFT_ALIGNMENT) topPanel.add(infoPanel) topPanel.add(Box.createRigidArea(Dimension(0, 10))) topPanel.add(self.favZoneStatusCBtn) #table self.zonesTable = JTable() tableSelectionModel = self.zonesTable.getSelectionModel() tableSelectionModel.addListSelectionListener(ZonesTableListener(self)) columns = ["", self.app.strings.getString("Type"), self.app.strings.getString("Name")] tableModel = ZonesTableModel([], columns) self.zonesTable.setModel(tableModel) self.scrollPane = JScrollPane(self.zonesTable) #map self.zonesMap = JMapViewer() self.zonesMap.setZoomContolsVisible(False) self.zonesMap.setMinimumSize(Dimension(100, 200)) #buttons self.removeBtn = JButton(self.app.strings.getString("Remove"), ImageProvider.get("dialogs", "delete"), actionPerformed=self.on_removeBtn_clicked) self.removeBtn.setToolTipText(self.app.strings.getString("remove_tooltip")) newBtn = JButton(self.app.strings.getString("New"), ImageProvider.get("dialogs", "add"), actionPerformed=self.on_newBtn_clicked) newBtn.setToolTipText(self.app.strings.getString("new_tooltip")) #layout panel2.add(topPanel, BorderLayout.PAGE_START) panel2.add(self.scrollPane, BorderLayout.LINE_START) panel2.add(self.zonesMap, BorderLayout.CENTER) self.buttonsPanel = JPanel() self.buttonsPanel.add(self.removeBtn) self.buttonsPanel.add(newBtn) panel2.add(self.buttonsPanel, BorderLayout.PAGE_END) self.tabbedPane.addTab(self.app.strings.getString("tab_2_title"), None, panel2, None) #3 Tab Tools options panel3 = JPanel() panel3.setLayout(BoxLayout(panel3, BoxLayout.Y_AXIS)) panel3.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7)) for tool in self.app.realTools: if hasattr(tool, 'prefs'): p = JPanel(FlowLayout(FlowLayout.LEFT)) p.setBorder(BorderFactory.createTitledBorder(tool.title)) p.add(tool.prefsGui) panel3.add(p) self.tabbedPane.addTab(self.app.strings.getString("tab_3_title"), None, panel3, None) self.add(self.tabbedPane, BorderLayout.CENTER) exitPanel = JPanel() saveBtn = JButton(self.app.strings.getString("OK"), ImageProvider.get("ok"), actionPerformed=self.on_saveBtn_clicked) cancelBtn = JButton(self.app.strings.getString("cancel"), ImageProvider.get("cancel"), actionPerformed=self.on_cancelBtn_clicked) saveBtn.setToolTipText(self.app.strings.getString("save_preferences")) saveBtn.setAlignmentX(0.5) exitPanel.add(saveBtn) exitPanel.add(cancelBtn) self.add(exitPanel, BorderLayout.PAGE_END) self.addWindowListener(self) self.pack() def windowClosing(self, windowEvent): self.on_cancelBtn_clicked() def hyperlinkUpdate(self, e): if e.getEventType() == HyperlinkEvent.EventType.ACTIVATED: OpenBrowser.displayUrl(e.getURL().toString()) def itemStateChanged(self, e): """A ttol has been activated/deactivated. Check if at least one tool is on. """ if all(not button.isSelected() for button in self.toolsCBtns): JOptionPane.showMessageDialog( Main.parent, self.app.strings.getString("tools_disabled_warning"), self.app.strings.getString("tools_disabled_warning_title"), JOptionPane.WARNING_MESSAGE) source = e.getItemSelectable() source.setSelected(True) def actionPerformed(self, e=None): """Enable/disable favourite zones panel """ for container in (self.scrollPane, self.buttonsPanel): self.enableComponents(container, self.favZoneStatusCBtn.isSelected()) if self.favZoneStatusCBtn.isSelected(): self.check_removeBtn_status() def enableComponents(self, container, enable): components = container.getComponents() for component in components: component.setEnabled(enable) if isinstance(component, Container): self.enableComponents(component, enable) def on_downloadBtn_clicked(self, e): update_checker.Updater(self.app, "manual") def clean_map(self): """Remove all rectangles and polygons from the map """ self.zonesMap.removeAllMapRectangles() self.zonesMap.removeAllMapPolygons() def update_gui_from_preferences(self): """Update gui status of preferences frame from config file """ #print "\n- updating Preferences gui" onOff = {"on": True, "off": False} #1 Tab #check for update self.updateCBtn.setSelected(onOff[self.app.checkUpdate]) #tools status, enabled or not for toolIndex, tool in enumerate(self.app.realTools): if "tool.%s" % tool.name in self.app.properties.keys(): configstatus = self.app.properties.getProperty("tool.%s" % tool.name) else: configstatus = "on" # new tool self.toolsCBtns[toolIndex].setSelected(onOff[configstatus]) #layers preferences for mode, button in self.layersRBtns.iteritems(): button.setSelected(mode == self.app.layersMode) #max errors number self.maxErrorsNumberTextField.setText(str(self.app.maxErrorsNumber)) #stats panel self.app.dlg.update_favourite_zone_indicator() #2 Tab #favourite area self.update_favourite_area_gui_from_preferences() self.app.dlg.update_statsPanel_status() #3 Tab #tools preferences for tool in self.app.allTools: if hasattr(tool, 'prefs') and tool.prefsGui is not None: tool.prefsGui.update_gui(tool.prefs) def update_favourite_area_gui_from_preferences(self): #status self.favZoneStatusCBtn.setSelected(self.app.favouriteZoneStatus) #table #store zones to a temporary list, used to store changes #and save them when preferences dialog is closed self.app.tempZones = list(self.app.zones) self.zonesTable.getModel().setNumRows(0) for zone in self.app.tempZones: self.zonesTable.getModel().addRow([zone.country, zone.icon, zone.name]) if self.app.favZone is not None: selectedRow = self.app.tempZones.index(self.app.favZone) self.zonesTable.setRowSelectionInterval(selectedRow, selectedRow) self.zonesTable.getColumnModel().getColumn(0).setMaxWidth(30) self.zonesTable.getColumnModel().getColumn(1).setMaxWidth(50) #enable or disable favourite zone buttons self.actionPerformed() ### fav area editing buttons ########################################### def on_removeBtn_clicked(self, e): rowsNum = self.zonesTable.getSelectedRows() rowsNum.reverse() for rowNum in rowsNum: del self.app.tempZones[rowNum] self.zonesTable.getModel().removeRow(rowNum) if len(self.app.tempZones) != 0: if rowNum == 0: self.zonesTable.setRowSelectionInterval(0, 0) else: self.zonesTable.setRowSelectionInterval(rowNum - 1, rowNum - 1) self.check_removeBtn_status() def check_removeBtn_status(self): if self.app.tempZones != [] and len(self.zonesTable.getSelectedRows()) != 0: self.removeBtn.setEnabled(True) else: self.removeBtn.setEnabled(False) self.clean_map() def on_newBtn_clicked(self, e): try: self.newZoneDialog except AttributeError: self.newZoneDialog = NewZoneDialog(self.app) bbox = self.app.get_frame_bounds() self.app.newZone = Zone(self.app, self.app.strings.getString("New_zone"), "rectangle", ",".join(["%0.4f" % x for x in bbox]), "") self.newZoneDialog.update_gui_from_preferences() self.newZoneDialog.show() ### Exit from preferences ############################################## def on_cancelBtn_clicked(self, event=None): if hasattr(self, "newZoneDialog") and self.newZoneDialog.isVisible(): self.newZoneDialog.close_dialog() self.dispose() def on_saveBtn_clicked(self, event): """Read preferences from gui and save them to config.properties file """ #print "\n- saving preferences to config file" onOff = {True: "on", False: "off"} #1 Tab #check for update self.app.properties.setProperty("check_for_update", onOff[self.updateCBtn.isSelected()]) #tools status for toolIndex, tool in enumerate(self.app.realTools): prop = "tool.%s" % tool.name toolCBtn = self.toolsCBtns[toolIndex] self.app.properties.setProperty(prop, onOff[toolCBtn.isSelected()]) #layers preferences for mode, button in self.layersRBtns.iteritems(): if button.isSelected(): self.app.properties.setProperty("layers_mode", mode) break #max errors number try: num = Integer.parseInt(self.maxErrorsNumberTextField.getText()) except NumberFormatException: num = "" self.app.properties.setProperty("max_errors_number", str(num)) #2 Tab #Favourite zones changes = {"new": [z for z in self.app.tempZones if not z in self.app.zones], "deleted": [z for z in self.app.zones if not z in self.app.tempZones]} #delete files of removed favourite zones for zone in changes["deleted"]: f = File(File.separator.join([self.app.SCRIPTDIR, "configuration", "favourite_zones", "%s.txt" % zone.name])) f.delete() #create files for new favourite zones for zone in changes["new"]: print "\nsave new zone", zone.name fileName = File.separator.join([self.app.SCRIPTDIR, "configuration", "favourite_zones", "%s.txt" % zone.name]) f = open(fileName, "w") zoneData = zone.geomString if zone.country != "": zoneData += "|" + zone.country f.write(zoneData.encode("utf-8")) f.close() self.app.zones = self.app.tempZones if len(self.app.zones) == 0: self.app.favZone = None self.app.properties.setProperty("favourite_area.name", "") self.favZoneStatusCBtn.setSelected(False) else: if len(self.zonesTable.getSelectedRows()) == 0: self.app.favZone = self.app.zones[0] else: self.app.favZone = self.app.zones[self.zonesTable.getSelectedRows()[0]] self.app.properties.setProperty("favourite_area.name", self.app.favZone.name) favZoneStatus = self.favZoneStatusCBtn.isSelected() self.app.properties.setProperty("favourite_area.status", onOff[favZoneStatus]) self.app.favouriteZoneStatus = favZoneStatus #stats panel self.app.dlg.update_favourite_zone_indicator() self.app.dlg.update_statsPanel_status() #3 Tab #tools preferences for tool in self.app.allTools: if hasattr(tool, 'prefs') and tool.prefsGui is not None: for pref, value in tool.prefsGui.read_gui().iteritems(): prefKey = "tool.%s.%s" % (tool.name, pref) self.app.properties.setProperty(prefKey, value) self.app.save_config() self.dispose()
class Config(ITab): """Defines the Configuration tab""" def __init__(self, callbacks, parent): # Initialze self stuff self._callbacks = callbacks self.config = {} self.ext_stats = {} self.url_reqs = [] self.parse_files = False self.tab = JPanel(GridBagLayout()) self.view_port_text = JTextArea("===SpyDir===") self.delim = JTextField(30) self.ext_white_list = JTextField(30) # I'm not sure if these fields are necessary still # why not just use Burp func to handle this? # leaving them in case I need it for the HTTP handler later # self.cookies = JTextField(30) # self.headers = JTextField(30) self.url = JTextField(30) self.parent_window = parent self.plugins = {} self.loaded_p_list = set() self.loaded_plugins = False self.config['Plugin Folder'] = None self.double_click = False self.source_input = "" self.print_stats = True self.curr_conf = JLabel() self.window = JFrame("Select plugins", preferredSize=(200, 250), windowClosing=self.p_close) self.window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE) self.window.setVisible(False) self.path_vars = JTextField(30) # Initialize local stuff tab_constraints = GridBagConstraints() status_field = JScrollPane(self.view_port_text) # Configure view port self.view_port_text.setEditable(False) labels = self.build_ui() # Add things to rows tab_constraints.anchor = GridBagConstraints.FIRST_LINE_END tab_constraints.gridx = 1 tab_constraints.gridy = 0 tab_constraints.fill = GridBagConstraints.HORIZONTAL self.tab.add(JButton( "Resize screen", actionPerformed=self.resize), tab_constraints) tab_constraints.gridx = 0 tab_constraints.gridy = 1 tab_constraints.anchor = GridBagConstraints.FIRST_LINE_START self.tab.add(labels, tab_constraints) tab_constraints.gridx = 1 tab_constraints.gridy = 1 tab_constraints.fill = GridBagConstraints.BOTH tab_constraints.weightx = 1.0 tab_constraints.weighty = 1.0 tab_constraints.anchor = GridBagConstraints.FIRST_LINE_END self.tab.add(status_field, tab_constraints) try: self._callbacks.customizeUiComponent(self.tab) except Exception: pass def build_ui(self): """Builds the configuration screen""" labels = JPanel(GridLayout(21, 1)) checkbox = JCheckBox("Attempt to parse files for URL patterns?", False, actionPerformed=self.set_parse) stats_box = JCheckBox("Show stats?", True, actionPerformed=self.set_show_stats) # The two year old in me is laughing heartily plug_butt = JButton("Specify plugins location", actionPerformed=self.set_plugin_loc) load_plug_butt = JButton("Select plugins", actionPerformed=self.p_build_ui) parse_butt = JButton("Parse directory", actionPerformed=self.parse) clear_butt = JButton("Clear text", actionPerformed=self.clear) spider_butt = JButton("Send to Spider", actionPerformed=self.scan) save_butt = JButton("Save config", actionPerformed=self.save) rest_butt = JButton("Restore config", actionPerformed=self.restore) source_butt = JButton("Input Source File/Directory", actionPerformed=self.get_source_input) # Build grid labels.add(source_butt) labels.add(self.curr_conf) labels.add(JLabel("String Delimiter:")) labels.add(self.delim) labels.add(JLabel("Extension Whitelist:")) labels.add(self.ext_white_list) labels.add(JLabel("URL:")) labels.add(self.url) labels.add(JLabel("Path Variables")) labels.add(self.path_vars) # Leaving these here for now. # labels.add(JLabel("Cookies:")) # labels.add(self.cookies) # labels.add(JLabel("HTTP Headers:")) # labels.add(self.headers) labels.add(checkbox) labels.add(stats_box) labels.add(plug_butt) labels.add(parse_butt) labels.add(JButton("Show all endpoints", actionPerformed=self.print_endpoints)) labels.add(clear_butt) labels.add(spider_butt) labels.add(JLabel("")) labels.add(save_butt) labels.add(rest_butt) labels.add(load_plug_butt) # Tool tips! self.delim.setToolTipText("Use to manipulate the final URL. " "See About tab for example.") self.ext_white_list.setToolTipText("Define a comma delimited list of" " file extensions to parse. Use *" " to parse all files.") self.url.setToolTipText("Enter the target URL") checkbox.setToolTipText("Parse files line by line using plugins" " to enumerate language/framework specific" " endpoints") parse_butt.setToolTipText("Attempt to enumerate application endpoints") clear_butt.setToolTipText("Clear status window and the parse results") spider_butt.setToolTipText("Process discovered endpoints") save_butt.setToolTipText("Saves the current config settings") rest_butt.setToolTipText("<html>Restores previous config settings:" "<br/>-Input Directory<br/>-String Delim" "<br/>-Ext WL<br/>-URL<br/>-Plugins") source_butt.setToolTipText("Select the application's " "source directory or file to parse") self.path_vars.setToolTipText("Supply a JSON object with values" "for dynamically enumerated query" "string variables") return labels def set_url(self, menu_url): """Changes the configuration URL to the one from the menu event""" self.url.setText(menu_url) # Event functions def set_parse(self, event): """ Handles the click event from the UI checkbox to attempt code level parsing """ self.parse_files = not self.parse_files if self.parse_files: if not self.loaded_plugins: self._plugins_missing_warning() def restore(self, event): """Attempts to restore the previously saved configuration.""" jdump = None try: jdump = loads(self._callbacks.loadExtensionSetting("config")) except Exception as exc: # Generic exception thrown directly to user self.update_scroll( "[!!] Error during restore!\n\tException: %s" % str(exc)) if jdump is not None: self.url.setText(jdump.get('URL')) # self.cookies.setText(jdump.get('Cookies')) # self.headers.setText(jdump.get("Headers")) ewl = "" for ext in jdump.get('Extension Whitelist'): ewl += ext + ", " self.ext_white_list.setText(ewl[:-2]) self.delim.setText(jdump.get('String Delimiter')) self.source_input = jdump.get("Input Directory") self.config['Plugin Folder'] = jdump.get("Plugin Folder") if (self.config['Plugin Folder'] is not None and (len(self.plugins.values()) < 1)): self._load_plugins(self.config['Plugin Folder']) self._update() self.update_scroll("[^] Restore complete!") else: self.update_scroll("[!!] Restore failed!") def save(self, event=None): """ Saves the configuration details to a Burp Suite's persistent store. """ self._update() try: if not self._callbacks.isInScope(URL(self.url.getText())): self.update_scroll("[!!] URL provided is NOT in Burp Scope!") except MalformedURLException: # If url field is blank we'll pass # still save the settings. try: self._callbacks.saveExtensionSetting("config", dumps(self.config)) self.update_scroll("[^] Settings saved!") except Exception: self.update_scroll("[!!] Error saving settings to Burp Suite!") def parse(self, event): """ Handles the click event from the UI. Attempts to parse the given directory (and/or source files) for url endpoints Saves the items found within the url_reqs list """ self._update() file_set = set() fcount = 0 other_dirs = set() self.ext_stats = {} if self.loaded_plugins: self.update_scroll("[^] Attempting to parse files" + " for URL patterns. This might take a minute.") if path.isdir(self.source_input): for dirname, _, filenames in walk(self.source_input): for filename in filenames: fcount += 1 ext = path.splitext(filename)[1] count = self.ext_stats.get(ext, 0) + 1 filename = "%s/%s" % (dirname, filename) self.ext_stats.update({ext: count}) if self.parse_files and self._ext_test(ext): # i can haz threading? file_set.update(self._code_as_endpoints(filename, ext)) elif self._ext_test(ext): r_files, oths = self._files_as_endpoints(filename, ext) file_set.update(r_files) other_dirs.update(oths) elif path.isfile(self.source_input): ext = path.splitext(self.source_input)[1] file_set.update(self._code_as_endpoints(self.source_input, ext)) else: self.update_scroll("[!!] Input Directory is not valid!") if len(other_dirs) > 0: self.update_scroll("[*] Found files matching file extension in:\n") for other_dir in other_dirs: self.update_scroll(" " * 4 + "%s\n" % other_dir) self._handle_path_vars(file_set) self._print_parsed_status(fcount) return (other_dirs, self.url_reqs) def _handle_path_vars(self, file_set): proto = 'http://' for item in file_set: if item.startswith("http://") or item.startswith("https://"): proto = item.split("//")[0] + '//' item = item.replace(proto, "") item = self._path_vars(item) self.url_reqs.append(proto + item.replace('//', '/')) def _path_vars(self, item): p_vars = None if self.path_vars.getText(): try: p_vars = loads(str(self.path_vars.getText())) except: self.update_scroll("[!] Error reading supplied Path Variables!") if p_vars is not None: rep_str = "" try: for k in p_vars.keys(): rep_str += "[^] Replacing %s with %s!\n" % (k, str(p_vars.get(k))) self.update_scroll(rep_str) for k in p_vars.keys(): if str(k) in item: item = item.replace(k, str(p_vars.get(k))) except AttributeError: self.update_scroll("[!] Error reading supplied Path Variables! This needs to be a JSON dictionary!") return item def scan(self, event): """ handles the click event from the UI. Adds the given URL to the burp scope and sends the requests to the burp spider """ temp_url = self.url.getText() if not self._callbacks.isInScope(URL(temp_url)): if not self.double_click: self.update_scroll("[!!] URL is not in scope! Press Send to " "Spider again to add to scope and scan!") self.double_click = True return else: self._callbacks.sendToSpider(URL(temp_url)) self.update_scroll( "[^] Sending %d requests to Spider" % len(self.url_reqs)) for req in self.url_reqs: self._callbacks.sendToSpider(URL(req)) def clear(self, event): """Clears the viewport and the current parse exts""" self.view_port_text.setText("===SpyDir===") self.ext_stats = {} def print_endpoints(self, event): """Prints the discovered endpoints to the status window.""" req_str = "" if len(self.url_reqs) > 0: self.update_scroll("[*] Printing all discovered endpoints:") for req in sorted(self.url_reqs): req_str += " %s\n" % req else: req_str = "[!!] No endpoints discovered" self.update_scroll(req_str) def set_show_stats(self, event): """Modifies the show stats setting""" self.print_stats = not self.print_stats def get_source_input(self, event): """Sets the source dir/file for parsing""" source_chooser = JFileChooser() source_chooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES) source_chooser.showDialog(self.tab, "Choose Source Location") chosen_source = source_chooser.getSelectedFile() try: self.source_input = chosen_source.getAbsolutePath() except AttributeError: pass if self.source_input is not None: self.update_scroll("[*] Source location: %s" % self.source_input) self.curr_conf.setText(self.source_input) # Plugin functions def _parse_file(self, filename, file_url): """ Attempts to parse a file with the loaded plugins Returns set of endpoints """ file_set = set() with open(filename, 'r') as plug_in: lines = plug_in.readlines() ext = path.splitext(filename)[1].upper() if ext in self.plugins.keys() and self._ext_test(ext): for plug in self.plugins.get(ext): if plug.enabled: res = plug.run(lines) if len(res) > 0: for i in res: i = file_url + i file_set.add(i) elif ext == '.TXT' and self._ext_test(ext): for i in lines: i = file_url + i file_set.add(i.strip()) return file_set def set_plugin_loc(self, event): """Attempts to load plugins from a specified location""" if self.config['Plugin Folder'] is not None: choose_plugin_location = JFileChooser(self.config['Plugin Folder']) else: choose_plugin_location = JFileChooser() choose_plugin_location.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY) choose_plugin_location.showDialog(self.tab, "Choose Folder") chosen_folder = choose_plugin_location.getSelectedFile() self.config['Plugin Folder'] = chosen_folder.getAbsolutePath() self._load_plugins(self.config['Plugin Folder']) def _load_plugins(self, folder): """ Parses a local directory to get the plugins related to code level scanning """ report = "" if len(self.plugins.keys()) > 0: report = "[^] Plugins reloaded!" for _, _, filenames in walk(folder): for p_name in filenames: n_e = path.splitext(p_name) # n_e = name_extension if n_e[1] == ".py": f_loc = "%s/%s" % (folder, p_name) loaded_plug = self._validate_plugin(n_e[0], f_loc) if loaded_plug: for p in self.loaded_p_list: if p.get_name() == loaded_plug.get_name(): self.loaded_p_list.discard(p) self.loaded_p_list.add(loaded_plug) if not report.startswith("[^]"): report += "%s loaded\n" % loaded_plug.get_name() self._dictify(self.loaded_p_list) if len(self.plugins.keys()) > 0: self.loaded_plugins = True else: report = "[!!] Plugins load failure" self.loaded_plugins = False self.update_scroll(report) return report def _validate_plugin(self, p_name, f_loc): """ Attempts to verify the manditory plugin functions to prevent broken plugins from loading. Generates an error message if plugin does not contain an appropriate function. """ # Load the plugin try: plug = load_source(p_name, f_loc) except Exception as exc: # this needs to be generic. self.update_scroll( "[!!] Error loading: %s\n\tType:%s Error: %s" % (f_loc, type(exc), str(exc))) # Verify the plugin's functions funcs = dir(plug) err = [] if "get_name" not in funcs: err.append("get_name()") if "get_ext" not in funcs: err.append("get_ext()") if "run" not in funcs: err.append("run()") # Report errors & return if len(err) < 1: return Plugin(plug, True) for issue in err: self.update_scroll("[!!] %s is missing: %s func" % (p_name, issue)) return None def _dictify(self, plist): """Converts the list of loaded plugins (plist) into a dictionary""" for p in plist: exts = p.get_ext().upper() for ext in exts.split(","): prev_load = self.plugins.get(ext, []) prev_load.append(p) self.plugins[ext] = prev_load # Status window functions def _print_parsed_status(self, fcount): """Prints the parsed directory status information""" if self.parse_files and not self.loaded_plugins: self._plugins_missing_warning() if len(self.url_reqs) > 0: self.update_scroll("[*] Example URL: %s" % self.url_reqs[0]) if self.print_stats: report = (("[*] Found: %r files to be requested.\n\n" + "[*] Stats: \n " + "Found: %r files.\n") % (len(self.url_reqs), fcount)) if len(self.ext_stats) > 0: report += ("[*] Extensions found: %s" % str(dumps(self.ext_stats, sort_keys=True, indent=4))) else: report = ("[*] Found: %r files to be requested.\n" % len(self.url_reqs)) self.update_scroll(report) return report def _plugins_missing_warning(self): """Prints a warning message""" self.update_scroll("[!!] No plugins loaded!") def update_scroll(self, text): """Updates the view_port_text with the new information""" temp = self.view_port_text.getText().strip() if text not in temp or text[0:4] == "[!!]": self.view_port_text.setText("%s\n%s" % (temp, text)) elif not temp.endswith("[^] Status unchanged"): self.view_port_text.setText("%s\n[^] Status unchanged" % temp) # Internal functions def _code_as_endpoints(self, filename, ext): file_set = set() file_url = self.config.get("URL") if self.loaded_plugins or ext == '.txt': if self._ext_test(ext): file_set.update( self._parse_file(filename, file_url)) else: file_set.update( self._parse_file(filename, file_url)) return file_set def _files_as_endpoints(self, filename, ext): """Generates endpoints via files with the appropriate extension(s)""" file_url = self.config.get("URL") broken_splt = "" other_dirs = set() # directories outside of the String Delim. file_set = set() str_del = self.config.get("String Delimiter") if not str_del: self.update_scroll("[!!] No available String Delimiter!") return spl_str = filename.split(str_del) try: # Fix for index out of bounds exception while parsing # subfolders _not_ included by the split if len(spl_str) > 1: file_url += ((spl_str[1]) .replace('\\', '/')) else: broken_splt = filename.split(self.source_input)[1] other_dirs.add(broken_splt) except Exception as exc: # Generic exception thrown directly to user self.update_scroll("[!!] Error parsing: " + "%s\n\tException: %s" % (filename, str(exc))) if self._ext_test(ext): if file_url != self.config.get("URL"): file_set.add(file_url) else: other_dirs.discard(broken_splt) return file_set, other_dirs def _ext_test(self, ext): """Litmus test for extension whitelist""" val = False if "*" in self.config.get("Extension Whitelist"): val = True else: val = (len(ext) > 0 and (ext.strip().upper() in self.config.get("Extension Whitelist"))) return val def _update(self): """Updates internal data""" self.config["Input Directory"] = self.source_input self.config["String Delimiter"] = self.delim.getText() white_list_text = self.ext_white_list.getText() self.config["Extension Whitelist"] = white_list_text.upper().split(',') file_url = self.url.getText() if not (file_url.startswith('https://') or file_url.startswith('http://')): self.update_scroll("[!] Assuming protocol! Default value: 'http://'") file_url = 'http://' + file_url self.url.setText(file_url) if not file_url.endswith('/') and file_url != "": file_url += '/' self.config["URL"] = file_url # self.config["Cookies"] = self.cookies.getText() # self.config["Headers"] = self.headers.getText() del self.url_reqs[:] self.curr_conf.setText(self.source_input) # Window sizing functions def resize(self, event): """Resizes the window to better fit Burp""" if self.parent_window is not None: par_size = self.parent_window.getSize() par_size.setSize(par_size.getWidth() * .99, par_size.getHeight() * .9) self.tab.setPreferredSize(par_size) self.parent_window.validate() self.parent_window.switch_focus() def p_close(self, event): """ Handles the window close event. """ self.window.setVisible(False) self.window.dispose() def p_build_ui(self, event): """ Adds a list of checkboxes, one for each loaded plugin to the Selct plugins window """ if not self.loaded_p_list: self.update_scroll("[!!] No plugins loaded!") return scroll_pane = JScrollPane() scroll_pane.setPreferredSize(Dimension(200, 250)) check_frame = JPanel(GridBagLayout()) constraints = GridBagConstraints() constraints.fill = GridBagConstraints.HORIZONTAL constraints.gridy = 0 constraints.anchor = GridBagConstraints.FIRST_LINE_START for plug in self.loaded_p_list: check_frame.add(JCheckBox(plug.get_name(), plug.enabled, actionPerformed=self.update_box), constraints) constraints.gridy += 1 vport = JViewport() vport.setView(check_frame) scroll_pane.setViewport(vport) self.window.contentPane.add(scroll_pane) self.window.pack() self.window.setVisible(True) def update_box(self, event): """ Handles the check/uncheck event for the plugin's box. """ for plug in self.loaded_p_list: if plug.get_name() == event.getActionCommand(): plug.enabled = not plug.enabled if plug.enabled: self.update_scroll("[^] Enabled: %s" % event.getActionCommand()) else: self.update_scroll("[^] Disabled: %s" % event.getActionCommand()) # ITab required functions @staticmethod def getTabCaption(): """Returns the name of the Burp Suite Tab""" return "SpyDir" def getUiComponent(self): """Returns the UI component for the Burp Suite tab""" return self.tab
class Config(ITab): """Defines the Configuration tab""" def __init__(self, callbacks, parent): # Initialze self stuff self._callbacks = callbacks self.config = {} self.ext_stats = {} self.url_reqs = [] self.parse_files = False self.tab = JPanel(GridBagLayout()) self.view_port_text = JTextArea("===SpyDir===") self.delim = JTextField(30) self.ext_white_list = JTextField(30) # I'm not sure if these fields are necessary still # why not just use Burp func to handle this? # leaving them in case I need it for the HTTP handler later # self.cookies = JTextField(30) # self.headers = JTextField(30) self.url = JTextField(30) self.parent_window = parent self.plugins = {} self.loaded_p_list = set() self.loaded_plugins = False self.config['Plugin Folder'] = None self.double_click = False self.source_input = "" self.print_stats = True self.curr_conf = JLabel() self.window = JFrame("Select plugins", preferredSize=(200, 250), windowClosing=self.p_close) self.window.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE) self.window.setVisible(False) # Initialize local stuff tab_constraints = GridBagConstraints() status_field = JScrollPane(self.view_port_text) # Configure view port self.view_port_text.setEditable(False) labels = self.build_ui() # Add things to rows tab_constraints.anchor = GridBagConstraints.FIRST_LINE_END tab_constraints.gridx = 1 tab_constraints.gridy = 0 tab_constraints.fill = GridBagConstraints.HORIZONTAL self.tab.add(JButton( "Resize screen", actionPerformed=self.resize), tab_constraints) tab_constraints.gridx = 0 tab_constraints.gridy = 1 tab_constraints.anchor = GridBagConstraints.FIRST_LINE_START self.tab.add(labels, tab_constraints) tab_constraints.gridx = 1 tab_constraints.gridy = 1 tab_constraints.fill = GridBagConstraints.BOTH tab_constraints.weightx = 1.0 tab_constraints.weighty = 1.0 tab_constraints.anchor = GridBagConstraints.FIRST_LINE_END self.tab.add(status_field, tab_constraints) try: self._callbacks.customizeUiComponent(self.tab) except Exception: pass def build_ui(self): """Builds the configuration screen""" labels = JPanel(GridLayout(21, 1)) checkbox = JCheckBox("Attempt to parse files for URL patterns?", False, actionPerformed=self.set_parse) stats_box = JCheckBox("Show stats?", True, actionPerformed=self.set_show_stats) # The two year old in me is laughing heartily plug_butt = JButton("Specify plugins location", actionPerformed=self.set_plugin_loc) load_plug_butt = JButton("Select plugins", actionPerformed=self.p_build_ui) parse_butt = JButton("Parse directory", actionPerformed=self.parse) clear_butt = JButton("Clear text", actionPerformed=self.clear) spider_butt = JButton("Send to Spider", actionPerformed=self.scan) save_butt = JButton("Save config", actionPerformed=self.save) rest_butt = JButton("Restore config", actionPerformed=self.restore) source_butt = JButton("Input Source File/Directory", actionPerformed=self.get_source_input) # Build grid labels.add(source_butt) labels.add(self.curr_conf) labels.add(JLabel("String Delimiter:")) labels.add(self.delim) labels.add(JLabel("Extension Whitelist:")) labels.add(self.ext_white_list) labels.add(JLabel("URL:")) labels.add(self.url) # Leaving these here for now. # labels.add(JLabel("Cookies:")) # labels.add(self.cookies) # labels.add(JLabel("HTTP Headers:")) # labels.add(self.headers) labels.add(checkbox) labels.add(stats_box) labels.add(plug_butt) labels.add(parse_butt) labels.add(JButton("Show all endpoints", actionPerformed=self.print_endpoints)) labels.add(clear_butt) labels.add(spider_butt) labels.add(JLabel("")) labels.add(save_butt) labels.add(rest_butt) labels.add(load_plug_butt) # Tool tips! self.delim.setToolTipText("Use to manipulate the final URL. " "See About tab for example.") self.ext_white_list.setToolTipText("Define a comma delimited list of" " file extensions to parse. Use *" " to parse all files.") self.url.setToolTipText("Enter the target URL") checkbox.setToolTipText("Parse files line by line using plugins" " to enumerate language/framework specific" " endpoints") parse_butt.setToolTipText("Attempt to enumerate application endpoints") clear_butt.setToolTipText("Clear status window and the parse results") spider_butt.setToolTipText("Process discovered endpoints") save_butt.setToolTipText("Saves the current config settings") rest_butt.setToolTipText("<html>Restores previous config settings:" "<br/>-Input Directory<br/>-String Delim" "<br/>-Ext WL<br/>-URL<br/>-Plugins") source_butt.setToolTipText("Select the application's " "source directory or file to parse") return labels def set_url(self, menu_url): """Changes the configuration URL to the one from the menu event""" self.url.setText(menu_url) # Event functions def set_parse(self, event): """ Handles the click event from the UI checkbox to attempt code level parsing """ self.parse_files = not self.parse_files if self.parse_files: if not self.loaded_plugins: self._plugins_missing_warning() def restore(self, event): """Attempts to restore the previously saved configuration.""" jdump = None try: jdump = loads(self._callbacks.loadExtensionSetting("config")) except Exception as exc: # Generic exception thrown directly to user self.update_scroll( "[!!] Error during restore!\n\tException: %s" % str(exc)) if jdump is not None: self.url.setText(jdump.get('URL')) # self.cookies.setText(jdump.get('Cookies')) # self.headers.setText(jdump.get("Headers")) ewl = "" for ext in jdump.get('Extension Whitelist'): ewl += ext + ", " self.ext_white_list.setText(ewl[:-2]) self.delim.setText(jdump.get('String Delimiter')) self.source_input = jdump.get("Input Directory") self.config['Plugin Folder'] = jdump.get("Plugin Folder") if (self.config['Plugin Folder'] is not None and (len(self.plugins.values()) < 1)): self._load_plugins(self.config['Plugin Folder']) self._update() self.update_scroll("[^] Restore complete!") else: self.update_scroll("[!!] Restore failed!") def save(self, event=None): """ Saves the configuration details to a Burp Suite's persistent store. """ self._update() try: if not self._callbacks.isInScope(URL(self.url.getText())): self.update_scroll("[!!] URL provided is NOT in Burp Scope!") except MalformedURLException: # If url field is blank we'll pass # still save the settings. try: self._callbacks.saveExtensionSetting("config", dumps(self.config)) self.update_scroll("[^] Settings saved!") except Exception: self.update_scroll("[!!] Error saving settings to Burp Suite!") def parse(self, event): """ Handles the click event from the UI. Attempts to parse the given directory (and/or source files) for url endpoints Saves the items found within the url_reqs list """ self._update() file_set = set() fcount = 0 other_dirs = set() self.ext_stats = {} if self.loaded_plugins: self.update_scroll("[^] Attempting to parse files" + " for URL patterns. This might take a minute.") if path.isdir(self.source_input): for dirname, _, filenames in walk(self.source_input): for filename in filenames: fcount += 1 ext = path.splitext(filename)[1] count = self.ext_stats.get(ext, 0) + 1 filename = "%s/%s" % (dirname, filename) self.ext_stats.update({ext: count}) if self.parse_files: # i can haz threading? file_set.update(self._code_as_endpoints(filename, ext)) elif self._ext_test(ext): r_files, oths = self._files_as_endpoints(filename, ext) file_set.update(r_files) other_dirs.update(oths) elif path.isfile(self.source_input): ext = path.splitext(self.source_input)[1] file_set.update(self._code_as_endpoints(self.source_input, ext)) else: self.update_scroll("[!!] Input Directory is not valid!") if len(other_dirs) > 0: self.update_scroll("[*] Found files matching file extension in:\n") for other_dir in other_dirs: self.update_scroll(" " * 4 + "%s\n" % other_dir) for item in file_set: if item.startswith("http://") or item.startswith("https://"): proto = item.split("//")[0] + '//' item = item.replace(proto, "") self.url_reqs.append(proto + item.replace('//', '/')) self._print_parsed_status(fcount) return (other_dirs, self.url_reqs) def scan(self, event): """ handles the click event from the UI. Adds the given URL to the burp scope and sends the requests to the burp spider """ temp_url = self.url.getText() if not self._callbacks.isInScope(URL(temp_url)): if not self.double_click: self.update_scroll("[!!] URL is not in scope! Press Send to " "Spider again to add to scope and scan!") self.double_click = True return else: self._callbacks.sendToSpider(URL(temp_url)) self.update_scroll( "[^] Sending %d requests to Spider" % len(self.url_reqs)) for req in self.url_reqs: self._callbacks.sendToSpider(URL(req)) def clear(self, event): """Clears the viewport and the current parse exts""" self.view_port_text.setText("===SpyDir===") self.ext_stats = {} def print_endpoints(self, event): """Prints the discovered endpoints to the status window.""" req_str = "" if len(self.url_reqs) > 0: self.update_scroll("[*] Printing all discovered endpoints:") for req in self.url_reqs: req_str += " %s\n" % req else: req_str = "[!!] No endpoints discovered" self.update_scroll(req_str) def set_show_stats(self, event): """Modifies the show stats setting""" self.print_stats = not self.print_stats def get_source_input(self, event): """Sets the source dir/file for parsing""" source_chooser = JFileChooser() source_chooser.setFileSelectionMode( JFileChooser.FILES_AND_DIRECTORIES) source_chooser.showDialog(self.tab, "Choose Source Location") chosen_source = source_chooser.getSelectedFile() try: self.source_input = chosen_source.getAbsolutePath() except AttributeError: pass if self.source_input is not None: self.update_scroll("[*] Source location: %s" % self.source_input) self.curr_conf.setText(self.source_input) # Plugin functions def _parse_file(self, filename, file_url): """ Attempts to parse a file with the loaded plugins Returns set of endpoints """ file_set = set() with open(filename, 'r') as plug_in: lines = plug_in.readlines() ext = path.splitext(filename)[1].upper() if ext in self.plugins.keys(): for plug in self.plugins.get(ext): if plug.enabled: res = plug.run(lines) if len(res) > 0: for i in res: i = file_url + i file_set.add(i) elif ext == '.TXT' and self._ext_test(ext): for i in lines: i = file_url + i file_set.add(i.strip()) return file_set def set_plugin_loc(self, event): """Attempts to load plugins from a specified location""" if self.config['Plugin Folder'] is not None: choose_plugin_location = JFileChooser(self.config['Plugin Folder']) else: choose_plugin_location = JFileChooser() choose_plugin_location.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY) choose_plugin_location.showDialog(self.tab, "Choose Folder") chosen_folder = choose_plugin_location.getSelectedFile() self.config['Plugin Folder'] = chosen_folder.getAbsolutePath() self._load_plugins(self.config['Plugin Folder']) def _load_plugins(self, folder): """ Parses a local directory to get the plugins related to code level scanning """ report = "" if len(self.plugins.keys()) > 0: report = "[^] Plugins reloaded!" for _, _, filenames in walk(folder): for p_name in filenames: n_e = path.splitext(p_name) # n_e = name_extension if n_e[1] == ".py": f_loc = "%s/%s" % (folder, p_name) loaded_plug = self._validate_plugin(n_e[0], f_loc) if loaded_plug: self.loaded_p_list.add(loaded_plug) if not report.startswith("[^]"): report += "%s loaded\n" % loaded_plug.get_name() self._dictify(self.loaded_p_list) if len(self.plugins.keys()) > 0: self.loaded_plugins = True else: report = "[!!] Plugins load failure" self.loaded_plugins = False self.update_scroll(report) return report def _validate_plugin(self, p_name, f_loc): """ Attempts to verify the manditory plugin functions to prevent broken plugins from loading. Generates an error message if plugin does not contain an appropriate function. """ # Load the plugin try: plug = load_source(p_name, f_loc) except Exception as exc: # this needs to be generic. self.update_scroll( "[!!] Error loading: %s\n\tType:%s Error: %s" % (f_loc, type(exc), str(exc))) # Verify the plugin's functions funcs = dir(plug) err = [] if "get_name" not in funcs: err.append("get_name()") if "get_ext" not in funcs: err.append("get_ext()") if "run" not in funcs: err.append("run()") # Report errors & return if len(err) < 1: return Plugin(plug, True) else: for issue in err: self.update_scroll("[!!] %s is missing: %s func" % (p_name, issue)) return None def _dictify(self, plist): """Converts the list of loaded plugins (plist) into a dictionary""" for p in plist: exts = p.get_ext().upper() for ext in exts.split(","): prev_load = self.plugins.get(ext, []) prev_load.append(p) self.plugins[ext] = prev_load # Status window functions def _print_parsed_status(self, fcount): """Prints the parsed directory status information""" if self.parse_files and not self.loaded_plugins: self._plugins_missing_warning() if len(self.url_reqs) > 0: self.update_scroll("[*] Example URL: %s" % self.url_reqs[0]) if self.print_stats: report = (("[*] Found: %r files to be requested.\n\n" + "[*] Stats: \n " + "Found: %r files.\n") % (len(self.url_reqs), fcount)) if len(self.ext_stats) > 0: report += ("[*] Extensions found: %s" % str(dumps(self.ext_stats, sort_keys=True, indent=4))) else: report = ("[*] Found: %r files to be requested.\n" % len(self.url_reqs)) self.update_scroll(report) return report def _plugins_missing_warning(self): """Prints a warning message""" self.update_scroll("[!!] No plugins loaded!") def update_scroll(self, text): """Updates the view_port_text with the new information""" temp = self.view_port_text.getText().strip() if text not in temp or text[0:4] == "[!!]": self.view_port_text.setText("%s\n%s" % (temp, text)) elif not temp.endswith("[^] Status unchanged"): self.view_port_text.setText("%s\n[^] Status unchanged" % temp) # Internal functions def _code_as_endpoints(self, filename, ext): file_set = set() file_url = self.config.get("URL") if self.loaded_plugins: if self._ext_test(ext): file_set.update( self._parse_file(filename, file_url)) else: file_set.update( self._parse_file(filename, file_url)) return file_set def _files_as_endpoints(self, filename, ext): """Generates endpoints via files with the appropriate extension(s)""" file_url = self.config.get("URL") broken_splt = "" other_dirs = set() # directories outside of the String Delim. file_set = set() str_del = self.config.get("String Delimiter") if not str_del: self.update_scroll("[!!] No available String Delimiter!") return spl_str = filename.split(str_del) try: # Fix for index out of bounds exception while parsing # subfolders _not_ included by the split if len(spl_str) > 1: file_url += ((spl_str[1]) .replace('\\', '/')) else: broken_splt = filename.split(self.source_input)[1] other_dirs.add(broken_splt) except Exception as exc: # Generic exception thrown directly to user self.update_scroll("[!!] Error parsing: " + "%s\n\tException: %s" % (filename, str(exc))) if self._ext_test(ext): if file_url != self.config.get("URL"): file_set.add(file_url) else: other_dirs.discard(broken_splt) return file_set, other_dirs def _ext_test(self, ext): """Litmus test for extension whitelist""" val = False if len(self.config.get("Extension Whitelist")) > 0: val = (len(ext) > 0 and (ext.strip().upper() in self.config.get("Extension Whitelist"))) elif "*" in self.config.get("Extension Whitelist"): val = True return val def _update(self): """Updates internal data""" self.config["Input Directory"] = self.source_input self.config["String Delimiter"] = self.delim.getText() white_list_text = self.ext_white_list.getText() self.config["Extension Whitelist"] = white_list_text.upper().split(',') file_url = self.url.getText() if not file_url.endswith('/') and file_url != "": file_url += '/' self.config["URL"] = file_url # self.config["Cookies"] = self.cookies.getText() # self.config["Headers"] = self.headers.getText() del self.url_reqs[:] self.curr_conf.setText(self.source_input) # Window sizing functions def resize(self, event): """Resizes the window to better fit Burp""" if self.parent_window is not None: par_size = self.parent_window.getSize() par_size.setSize(par_size.getWidth() * .99, par_size.getHeight() * .9) self.tab.setPreferredSize(par_size) self.parent_window.validate() self.parent_window.switch_focus() def p_close(self, event): """ Handles the window close event. """ self.window.setVisible(False) self.window.dispose() def p_build_ui(self, event): """ Adds a list of checkboxes, one for each loaded plugin to the Selct plugins window """ if not self.loaded_p_list: self.update_scroll("[!!] No plugins loaded!") return scroll_pane = JScrollPane() scroll_pane.setPreferredSize(Dimension(200, 250)) check_frame = JPanel(GridBagLayout()) constraints = GridBagConstraints() constraints.fill = GridBagConstraints.HORIZONTAL constraints.gridy = 0 constraints.anchor = GridBagConstraints.FIRST_LINE_START for plug in self.loaded_p_list: check_frame.add(JCheckBox(plug.get_name(), plug.enabled, actionPerformed=self.update_box), constraints) constraints.gridy += 1 vport = JViewport() vport.setView(check_frame) scroll_pane.setViewport(vport) self.window.contentPane.add(scroll_pane) self.window.pack() self.window.setVisible(True) def update_box(self, event): """ Handles the check/uncheck event for the plugin's box. """ for plug in self.loaded_p_list: if plug.get_name() == event.getActionCommand(): plug.enabled = not plug.enabled if plug.enabled: self.update_scroll("[^] Enabled: %s" % event.getActionCommand()) else: self.update_scroll("[^] Disabled: %s" % event.getActionCommand()) # ITab required functions @staticmethod def getTabCaption(): """Returns the name of the Burp Suite Tab""" return "SpyDir" def getUiComponent(self): """Returns the UI component for the Burp Suite tab""" return self.tab
class WorkHelper(JFrame): def __init__(self): super(WorkHelper, self).__init__() self.clipboard = Toolkit.getDefaultToolkit().getSystemClipboard() #self.initUI() #def initUI(self): #panel = JPanel() #self.getContentPane().add(panel) ############################################################# # Layout layout = GroupLayout(self.getContentPane()) self.getContentPane().setLayout(layout) layout.setAutoCreateGaps(True) layout.setAutoCreateContainerGaps(True) ############################################################# ############################################################# # Scroll Area Input + Output Larea1 = JLabel("InputArea:") Larea2 = JLabel("OutputArea:") Sarea1 = JScrollPane() Sarea2 = JScrollPane() self.area1 = JTextArea() self.area1.setToolTipText("Input Area") self.area1.setEditable(True) self.area1.setBorder(BorderFactory.createLineBorder(Color.gray)) Sarea1.setPreferredSize(Dimension(300,100)) Sarea1.getViewport().setView((self.area1)) self.area2 = JTextArea() self.area2.setToolTipText("Output Area") self.area2.setEditable(False) self.area2.setBorder(BorderFactory.createLineBorder(Color.gray)) Sarea2.setPreferredSize(Dimension(300,100)) Sarea2.getViewport().setView((self.area2)) ############################################################# ############################################################# # Buttons self.cCurly = JCheckBox("Curly"); self.cCurly.setToolTipText("When 'Checked' Curly Brackets will surround the Categories") self.cCurly.setSelected(1) self.cCtClipB = JCheckBox("Auto-Copy"); self.cCtClipB.setToolTipText("When 'Checked' after the Categories are created they will added to the clipboard") self.cCtClipB.setSelected(1) self.cSemiC = JCheckBox("SemiColumn"); self.cSemiC.setToolTipText("When 'Checked' after the Categories are created at the end will be a semicolomn") self.cSemiC.setSelected(1) bRemoveNBSP_L = JButton("Clean LText", actionPerformed=self.bRemoveNBSP_L) bRemoveNBSP_L.setToolTipText("Removes Spaces, Tabs from the start of every text line from the input Area") bRemoveNBSP_R = JButton("Clean RText", actionPerformed=self.bRemoveNBSP_R) bRemoveNBSP_R.setToolTipText("Removes Spaces, Tabs from the end of every text line from the input Area") bCopyToInput = JButton("Copy to Input", actionPerformed=self.bCopyToInput) bCopyToInput.setToolTipText("Copy the text from the Output Area to the Input Area for further Operations") bClear = JButton("Clear", actionPerformed=self.bClear) bClear.setToolTipText("Clears the text form both Input and Output text Areas") self.iStart = JTextField(maximumSize=Dimension(40,25)) self.iStart.setToolTipText("The Start Index for the Making of the Categories") self.RThis = JTextField() self.RThis = JTextField(maximumSize=Dimension(120,25)) self.RThis.setToolTipText("Text to be replaced or The Starting C_Index") self.RThat = JTextField() self.RThat = JTextField(maximumSize=Dimension(120,25)) self.RThat.setToolTipText("Text to be placed or The Finish C_Index") bSandReplace = JButton("Replace Text", actionPerformed=self.bSandReplace) bSandReplace.setToolTipText("Replace the text from This with Thext from That in the Text from the Input Area and displays it in the Output Area") bcCat = JButton("CreatCateg", actionPerformed=self.bcCat) bcCat.setToolTipText("Create a categorical form starting C_Index to finish C_Index; Use the above text boxes to define the indexes") bC_S = JButton("Create _Series", actionPerformed=self.bC_S) bC_S.setToolTipText("Create a series form starting C_Index to finish C_Index; Use the above text boxes to define the indexes; It will create a series for every row in the Input Area") bM_Categories = JButton("Categories", actionPerformed=self.mCategories) bM_Categories.setToolTipText("Make Categories using the lines from the Input Area") #bM_Categories = JButton(maximumSize=Dimension(40,25)) # de incercat daca merge cu ; sa grupezi in [dsa] elementele ############################################################# ############################################################# # Aplication Layout 2 groups one Horizontal and one Vertical layout.setHorizontalGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(Larea1) .addComponent(Sarea1) .addComponent(Sarea2) .addComponent(bCopyToInput) .addComponent(Larea2)) .addGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(bM_Categories) .addComponent(self.iStart)) .addGroup(layout.createSequentialGroup() .addComponent(self.cCurly) .addComponent(self.cSemiC) .addComponent(self.cCtClipB)) .addGroup(layout.createSequentialGroup() .addComponent(bRemoveNBSP_L) .addComponent(bRemoveNBSP_R)) .addGroup(layout.createSequentialGroup() .addComponent(self.RThis) .addComponent(self.RThat)) .addGroup(layout.createSequentialGroup() .addComponent(bSandReplace) .addComponent(bcCat)) .addGroup(layout.createSequentialGroup() .addComponent(bC_S)) .addComponent(bClear)) ) layout.setVerticalGroup(layout.createSequentialGroup() .addComponent(Larea1) .addGroup(layout.createParallelGroup() .addComponent(Sarea1) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(bM_Categories) .addComponent(self.iStart)) .addGroup(layout.createParallelGroup() .addComponent(self.cCurly) .addComponent(self.cSemiC) .addComponent(self.cCtClipB)) .addGroup(layout.createParallelGroup() .addComponent(bRemoveNBSP_L) .addComponent(bRemoveNBSP_R)) .addGroup(layout.createParallelGroup() .addComponent(self.RThis) .addComponent(self.RThat)) .addGroup(layout.createParallelGroup() .addComponent(bSandReplace) .addComponent(bcCat)) .addGroup(layout.createParallelGroup() .addComponent(bC_S)) ) ) .addGroup(layout.createParallelGroup() .addComponent(bCopyToInput) .addComponent(bClear)) .addComponent(Larea2) .addGroup(layout.createParallelGroup() .addComponent(Sarea2)) ) #layout.linkSize(SwingConstants.HORIZONTAL, [ok, bCopyToInput, close, bM_Categories]) layout.linkSize(SwingConstants.HORIZONTAL, [self.RThis,self.RThat,bRemoveNBSP_L,bRemoveNBSP_R,bCopyToInput,bM_Categories,bSandReplace,bcCat,bC_S]) #layout.linkSize(SwingConstants.HORIZONTAL, [self.cCurly,bM_Categories]) ############################################################# ############################################################# # Aplication Settings self.pack() #self.setPreferredSize(Dimension(1000, 1000)) self.setTitle("Workhelper") self.setSize(800, 500) self.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) self.setLocationRelativeTo(None) self.setVisible(True) ############################################################# ############################################################# # WorkHelper class methods: def onQuit(self, e): "@sig public void setExpression(java.lang.String e)" System.exit(0) # def addToClipBoard(self, text): # "@sig public void setExpression(java.lang.String text)" # command = 'echo ' + text.strip() + '| clip' # os.system(command) # brute method for pasting into clipboard on windows def mCategories(self, e): "@sig public void setExpression(java.lang.String e)" """ Takes every line of text form the Input Area and by using a string composotion it creates the output in the SPSS dimension categories format. """ try: StartIndex = int(self.iStart.getText()) except ValueError: StartIndex=1 text=self.area1.getText().rstrip() counter=StartIndex lastindex=0 textO="" for i in range(0,len(text)): if text[i]=='\n': textO=textO+("_"+str(counter)+' "'+text[lastindex:i]+'",\n') lastindex=i+1 counter=counter+1 if len(text[lastindex:len(text)])>0: textO=textO+("_"+str(counter)+' "'+text[lastindex:len(text)]+'"') if len(textO)>0: if self.cCurly.isSelected(): textO = "{\n"+ textO + "\n}" if self.cSemiC.isSelected(): textO = textO + ";" self.copyToClipboard(textO) self.area2.setText(textO) def copyToClipboard(self, text): if self.cCtClipB.isSelected(): stringSelection = StringSelection(text) self.clipboard.setContents(stringSelection, None) def bCopyToInput(self, e): "@sig public void setExpression(java.lang.String e)" """Copy the Text from the Output Area to the input Area for further operations""" self.area1.setText(self.area2.getText()) def bRemoveNBSP_L(self, e): "@sig public void setExpression(java.lang.String e)" text=self.area1.getText().rstrip() textO="" lastindex=0 for i in range(0,len(text)): if text[i] == '\n': textO = textO+text[lastindex:i].lstrip()+"\n" lastindex=i+1 #print(text[0:i].lstrip()+'\n') if len(text[lastindex:len(text)])>0: textO=textO+text[lastindex:len(text)].lstrip() self.area2.setText(textO) def bRemoveNBSP_R(self, e): "@sig public void setExpression(java.lang.String e)" text=self.area1.getText().rstrip() textO="" lastindex=0 for i in range(0,len(text)): if text[i] == '\n': textO = textO+text[lastindex:i].rstrip()+"\n" lastindex=i+1 #print(text[0:i].lstrip()+'\n') if len(text[lastindex:len(text)])>0: textO=textO+text[lastindex:len(text)].rstrip() self.area2.setText(textO) def bClear(self, e): "@sig public void setExpression(java.lang.String e)" self.area1.setText("") self.area2.setText("") def bcCat(self, e): "@sig public void setExpression(java.lang.String e)" try: StartIndex = int(self.RThis.getText()) except ValueError: StartIndex=1 try: FinishIndex = int(self.RThat.getText()) except ValueError: FinishIndex=1 cCats="" for i in range(StartIndex,FinishIndex+1): if i<>FinishIndex: cCats=cCats+"_"+str(i)+"," else: cCats=cCats+"_"+str(i) if StartIndex<FinishIndex: cCats="{"+cCats+"}" self.copyToClipboard(cCats) self.area2.setText(cCats) def bSandReplace(self, e): self.area2.setText(self.area1.getText().replace(self.RThis.getText(),self.RThat.getText())) def bC_S(self, e): "@sig public void setExpression(java.lang.String e)" try: StartIndex = int(self.RThis.getText()) except ValueError: StartIndex=1 try: FinishIndex = int(self.RThat.getText()) except ValueError: FinishIndex=1 if StartIndex<FinishIndex: text=self.area1.getText().rstrip() lastindex=0 textO="" for i in range(0,len(text)): if text[i]=='\n': counter=StartIndex for j in range(StartIndex,FinishIndex+1): textO=textO+(text[lastindex:i]+"_"+str(counter)+" ") counter=counter+1 lastindex=i+1 textO=textO+'\n' #if len(text[lastindex:len(text)])>0: # textO=textO+("_"+str(counter)+' "'+text[lastindex:len(text)]+'"') if lastindex==0 and len(text)>0: counter=StartIndex for j in range(StartIndex,FinishIndex+1): textO=textO+(text[lastindex:i]+"_"+str(counter)+" ") counter=counter+1 if len(textO)>0: self.copyToClipboard(textO) self.area2.setText(textO)
class BurpExtender(IBurpExtender, ITab, IScannerCheck, IContextMenuFactory, IParameter, IIntruderPayloadGeneratorFactory): def registerExtenderCallbacks(self, callbacks): self.callbacks = callbacks self.helpers = callbacks.getHelpers() callbacks.setExtensionName("Session Authentication Tool") self.out = callbacks.getStdout() # definition of suite tab self.tab = JPanel(GridBagLayout()) self.tabledata = MappingTableModel(callbacks) self.table = JTable(self.tabledata) #self.table.getColumnModel().getColumn(0).setPreferredWidth(50); #self.table.getColumnModel().getColumn(1).setPreferredWidth(100); self.tablecont = JScrollPane(self.table) c = GridBagConstraints() c.fill = GridBagConstraints.HORIZONTAL c.anchor = GridBagConstraints.FIRST_LINE_START c.gridx = 0 c.gridy = 0 c.gridheight = 6 c.weightx = 0.3 c.weighty = 0.5 self.tab.add(self.tablecont, c) c = GridBagConstraints() c.weightx = 0.1 c.anchor = GridBagConstraints.FIRST_LINE_START c.gridx = 1 c.gridy = 0 label_id = JLabel("Identifier:") self.tab.add(label_id, c) self.input_id = JTextField(20) self.input_id.setToolTipText( "Enter the identifier which is used by the application to identifiy a particular test user account, e.g. a numerical user id or a user name." ) c.gridy = 1 self.tab.add(self.input_id, c) c.gridy = 2 label_content = JLabel("Content:") self.tab.add(label_content, c) self.input_content = JTextField(20, actionPerformed=self.btn_add_id) self.input_content.setToolTipText( "Enter some content which is displayed in responses of the application and shows that the current session belongs to a particular user, e.g. the full name of the user." ) c.gridy = 3 self.tab.add(self.input_content, c) self.btn_add = JButton("Add/Edit Identity", actionPerformed=self.btn_add_id) c.gridy = 4 self.tab.add(self.btn_add, c) self.btn_del = JButton("Delete Identity", actionPerformed=self.btn_del_id) c.gridy = 5 self.tab.add(self.btn_del, c) callbacks.customizeUiComponent(self.tab) callbacks.customizeUiComponent(self.table) callbacks.customizeUiComponent(self.tablecont) callbacks.customizeUiComponent(self.btn_add) callbacks.customizeUiComponent(self.btn_del) callbacks.customizeUiComponent(label_id) callbacks.customizeUiComponent(self.input_id) callbacks.addSuiteTab(self) callbacks.registerScannerCheck(self) callbacks.registerIntruderPayloadGeneratorFactory(self) callbacks.registerContextMenuFactory(self) def btn_add_id(self, e): ident = self.input_id.text self.input_id.text = "" content = self.input_content.text self.input_content.text = "" self.tabledata.add_mapping(ident, content) self.input_id.requestFocusInWindow() def btn_del_id(self, e): rows = self.table.getSelectedRows().tolist() self.tabledata.del_rows(rows) ### ITab ### def getTabCaption(self): return ("SessionAuth") def getUiComponent(self): return self.tab ### IContextMenuFactory ### def createMenuItems(self, invocation): menuitems = list() msgs = invocation.getSelectedMessages() if msgs != None: if len( msgs ) == 1: # "add as object id/as content to last id" context menu items bounds = invocation.getSelectionBounds() if bounds != None and bounds[0] != bounds[1]: msg = None if invocation.getInvocationContext( ) == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST or invocation.getInvocationContext( ) == IContextMenuInvocation.CONTEXT_MESSAGE_VIEWER_REQUEST: msg = msgs[0].getRequest().tostring() if invocation.getInvocationContext( ) == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_RESPONSE or invocation.getInvocationContext( ) == IContextMenuInvocation.CONTEXT_MESSAGE_VIEWER_RESPONSE: msg = msgs[0].getResponse().tostring() if msg != None: selection = msg[bounds[0]:bounds[1]] shortSelection = selection[:20] if len(selection) > len(shortSelection): shortSelection += "..." menuitems.append( JMenuItem("Add '" + shortSelection + "' as object id", actionPerformed=self.gen_menu_add_id( selection))) if self.tabledata.lastadded != None: menuitems.append( JMenuItem( "Add '" + shortSelection + "' as content to last added id", actionPerformed=self.gen_menu_add_content( selection))) if len(msgs) > 0: # "Send to Intruder" context menu items requestsWithIds = list() for msg in msgs: if isinstance(msg.getRequest(), array) and self.tabledata.containsId( msg.getRequest().tostring()): requestsWithIds.append(msg) if len(requestsWithIds) > 0: menuitems.append( JMenuItem( "Send to Intruder and preconfigure id injection points", actionPerformed=self.gen_menu_send_intruder( requestsWithIds))) return menuitems def gen_menu_add_id(self, ident): def menu_add_id(e): self.tabledata.add_mapping(ident, "") return menu_add_id def gen_menu_add_content(self, content): def menu_add_content(e): self.tabledata.set_lastadded_content(content) return menu_add_content def gen_menu_send_intruder(self, requestResponses): def menu_send_intruder(e): for requestResponse in requestResponses: httpService = requestResponse.getHttpService() request = requestResponse.getRequest() injectionPoints = list() for ident in self.tabledata.getIds(): newInjectionPoints = findAll(request.tostring(), ident) if newInjectionPoints != None: injectionPoints += newInjectionPoints if len(injectionPoints) > 0: self.callbacks.sendToIntruder( httpService.getHost(), httpService.getPort(), httpService.getProtocol() == "https", request, injectionPoints) return menu_send_intruder ### IIntruderPayloadGeneratorFactory ### def getGeneratorName(self): return "SessionAuth Identifiers" def createNewInstance(self, attack): return IdentifiersPayloadGenerator(self.tabledata) ### IScannerCheck ### def doPassiveScan(self, baseRequestResponse): analyzedRequest = self.helpers.analyzeRequest(baseRequestResponse) params = analyzedRequest.getParameters() ids = self.tabledata.getIds() issues = list() for param in params: value = param.getValue() for ident in ids: if value == ident: issues.append( SessionAuthPassiveScanIssue( analyzedRequest.getUrl(), baseRequestResponse, param, ident, self.tabledata.getValue(ident), SessionAuthPassiveScanIssue.foundEqual, self.callbacks)) elif value.find(ident) >= 0: issues.append( SessionAuthPassiveScanIssue( analyzedRequest.getUrl(), baseRequestResponse, param, ident, self.tabledata.getValue(ident), SessionAuthPassiveScanIssue.foundInside, self.callbacks)) if len(issues) > 0: return issues else: return None def doActiveScan(self, baseRequestResponse, insertionPoint): ids = self.tabledata.getIds() if len(ids ) <= 1: # active check only possible if multiple ids were given return None baseVal = insertionPoint.getBaseValue() url = baseRequestResponse.getUrl() idFound = list() for ident in ids: # find all identifiers in base value if baseVal.find(ident) >= 0: idFound.append(ident) if len(idFound) == 0: # no given identifier found, nothing to do return None baseResponse = baseRequestResponse.getResponse().tostring() baseResponseBody = baseResponse[ self.helpers.analyzeResponse(baseResponse).getBodyOffset():] issues = list() scannedCombos = list() for replaceId in idFound: # scanner checks: replace found id by other given ids for scanId in ids: if replaceId == scanId or set([replaceId, scanId ]) in scannedCombos: continue scannedCombos.append(set([replaceId, scanId])) scanPayload = baseVal.replace(replaceId, scanId) scanRequest = insertionPoint.buildRequest(scanPayload) scanRequestResponse = self.callbacks.makeHttpRequest( baseRequestResponse.getHttpService(), scanRequest) scanResponse = scanRequestResponse.getResponse().tostring() scanResponseBody = scanResponse[self.helpers.analyzeResponse( scanResponse).getBodyOffset():] if baseResponseBody == scanResponseBody: # response hasn't changed - no issue continue # Analyze responses replaceValue = self.tabledata.getValue(replaceId) scanValue = self.tabledata.getValue(scanId) # naming convention: # first word: base || scan (response) # second word: Replace || Scan (value) if replaceValue != "": baseReplaceValueCount = len( baseResponseBody.split(replaceValue)) - 1 scanReplaceValueCount = len( scanResponseBody.split(replaceValue)) - 1 else: baseReplaceValueCount = 0 scanReplaceValueCount = 0 if scanValue != "": baseScanValueCount = len( baseResponseBody.split(scanValue)) - 1 scanScanValueCount = len( scanResponseBody.split(scanValue)) - 1 else: baseScanValueCount = 0 scanScanValueCount = 0 if scanScanValueCount == 0: # Scan identifier content value doesn't appears, but responses differ issueCase = SessionAuthActiveScanIssue.caseScanValueNotFound elif baseReplaceValueCount > 0 and baseScanValueCount == 0 and scanReplaceValueCount == 0 and scanScanValueCount == baseReplaceValueCount: # Scan identifier replaces all occurrences of the original identifier in the response issueCase = SessionAuthActiveScanIssue.caseScanValueAppearsExactly elif baseReplaceValueCount > 0 and baseScanValueCount == 0 and scanReplaceValueCount == 0 and scanScanValueCount > 0: # Scan identfiers value appears, replaced ids value disappears issueCase = SessionAuthActiveScanIssue.caseScanValueAppearsFuzzy elif baseReplaceValueCount > scanReplaceValueCount and baseScanValueCount < scanScanValueCount: # Occurence count of replaced id value decreases, scan id value increases issueCase = SessionAuthActiveScanIssue.caseDecreaseIncrease elif baseScanValueCount < scanScanValueCount: # Occurence count of scan id value increases issueCase = SessionAuthActiveScanIssue.caseScanValueIncrease else: # Remainingg cases issueCase = SessionAuthActiveScanIssue.caseOther issues.append( SessionAuthActiveScanIssue(url, baseRequestResponse, insertionPoint, scanPayload, scanRequestResponse, replaceId, replaceValue, scanId, scanValue, issueCase, self.callbacks)) if len(issues) > 0: return issues else: return None def consolidateDuplicateIssues(self, existingIssue, newIssue): if existingIssue.getIssueDetail() == newIssue.getIssueDetail(): return 1 else: return 0
class PreferencesFrame(JFrame, ActionListener, WindowListener, ItemListener, HyperlinkListener): """Dialog with preferences """ def __init__(self, parent, title, app): from javax.swing import JCheckBox, JRadioButton, ButtonGroup self.app = app border = BorderFactory.createEmptyBorder(5, 7, 5, 7) self.getContentPane().setBorder(border) self.getContentPane().setLayout(BorderLayout(0, 5)) self.tabbedPane = JTabbedPane() #1 Tab: general panel1 = JPanel() panel1.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7)) panel1.setLayout(BoxLayout(panel1, BoxLayout.PAGE_AXIS)) #Checkbutton to enable/disable update check when script starts self.updateCBtn = JCheckBox(self.app.strings.getString("updateCBtn")) self.updateCBtn.setToolTipText( self.app.strings.getString("updateCBtn_tooltip")) #Download tools downloadBtn = JButton(self.app.strings.getString("updatesBtn"), ImageProvider.get("dialogs", "refresh"), actionPerformed=self.on_downloadBtn_clicked) downloadBtn.setToolTipText( self.app.strings.getString("updatesBtn_tooltip")) #Checkbuttons for enabling/disabling tools toolsPanel = JPanel(BorderLayout(0, 5)) title = self.app.strings.getString("enable_disable_tools") toolsPanel.setBorder(BorderFactory.createTitledBorder(title)) infoLbl = JLabel(self.app.strings.getString("JOSM_restart_warning")) infoLbl.setFont(infoLbl.getFont().deriveFont(Font.ITALIC)) toolsPanel.add(infoLbl, BorderLayout.PAGE_START) toolsStatusPane = JPanel(GridLayout(len(self.app.realTools), 0)) self.toolsCBtns = [] for tool in self.app.realTools: toolCBtn = JCheckBox() toolCBtn.addItemListener(self) toolLbl = JLabel(tool.title, tool.bigIcon, JLabel.LEFT) self.toolsCBtns.append(toolCBtn) toolPane = JPanel() toolPane.setLayout(BoxLayout(toolPane, BoxLayout.X_AXIS)) toolPane.add(toolCBtn) toolPane.add(toolLbl) toolsStatusPane.add(toolPane) toolsPanel.add(toolsStatusPane, BorderLayout.CENTER) #Radiobuttons for enabling/disabling layers when a new one #is added layersPanel = JPanel(GridLayout(0, 1)) title = self.app.strings.getString("errors_layers_manager") layersPanel.setBorder(BorderFactory.createTitledBorder(title)) errorLayersLbl = JLabel( self.app.strings.getString("errors_layers_info")) errorLayersLbl.setFont(errorLayersLbl.getFont().deriveFont( Font.ITALIC)) layersPanel.add(errorLayersLbl) self.layersRBtns = {} group = ButtonGroup() for mode in self.app.layersModes: layerRBtn = JRadioButton(self.app.strings.getString("%s" % mode)) group.add(layerRBtn) layersPanel.add(layerRBtn) self.layersRBtns[mode] = layerRBtn #Max number of errors text field self.maxErrorsNumberTextField = JTextField() self.maxErrorsNumberTextField.setToolTipText( self.app.strings.getString("maxErrorsNumberTextField_tooltip")) self.maxErrorsNumberTFieldDefaultBorder = self.maxErrorsNumberTextField.getBorder( ) self.maxErrorsNumberTextField.getDocument().addDocumentListener( ErrNumTextListener(self)) #layout self.updateCBtn.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(self.updateCBtn) panel1.add(Box.createRigidArea(Dimension(0, 15))) downloadBtn.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(downloadBtn) panel1.add(Box.createRigidArea(Dimension(0, 15))) toolsPanel.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(toolsPanel) panel1.add(Box.createRigidArea(Dimension(0, 15))) layersPanel.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(layersPanel) panel1.add(Box.createRigidArea(Dimension(0, 15))) maxErrP = JPanel(BorderLayout(5, 0)) maxErrP.add(JLabel(self.app.strings.getString("max_errors_number")), BorderLayout.LINE_START) maxErrP.add(self.maxErrorsNumberTextField, BorderLayout.CENTER) p = JPanel(BorderLayout()) p.add(maxErrP, BorderLayout.PAGE_START) p.setAlignmentX(Component.LEFT_ALIGNMENT) panel1.add(p) self.tabbedPane.addTab(self.app.strings.getString("tab_1_title"), None, panel1, None) #2 Tab: favourite zones panel2 = JPanel(BorderLayout(5, 15)) panel2.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7)) #status topPanel = JPanel() topPanel.setLayout(BoxLayout(topPanel, BoxLayout.Y_AXIS)) infoPanel = HtmlPanel(self.app.strings.getString("fav_zones_info")) infoPanel.getEditorPane().addHyperlinkListener(self) infoPanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.favZoneStatusCBtn = JCheckBox( self.app.strings.getString("activate_fav_area"), actionListener=self) self.favZoneStatusCBtn.setToolTipText( self.app.strings.getString("activate_fav_area_tooltip")) self.favZoneStatusCBtn.setAlignmentX(Component.LEFT_ALIGNMENT) topPanel.add(infoPanel) topPanel.add(Box.createRigidArea(Dimension(0, 10))) topPanel.add(self.favZoneStatusCBtn) #table self.zonesTable = JTable() tableSelectionModel = self.zonesTable.getSelectionModel() tableSelectionModel.addListSelectionListener(ZonesTableListener(self)) columns = [ "", self.app.strings.getString("Type"), self.app.strings.getString("Name") ] tableModel = ZonesTableModel([], columns) self.zonesTable.setModel(tableModel) self.scrollPane = JScrollPane(self.zonesTable) #map self.zonesMap = JMapViewer() self.zonesMap.setZoomContolsVisible(False) self.zonesMap.setMinimumSize(Dimension(100, 200)) #buttons self.removeBtn = JButton(self.app.strings.getString("Remove"), ImageProvider.get("dialogs", "delete"), actionPerformed=self.on_removeBtn_clicked) self.removeBtn.setToolTipText( self.app.strings.getString("remove_tooltip")) newBtn = JButton(self.app.strings.getString("New"), ImageProvider.get("dialogs", "add"), actionPerformed=self.on_newBtn_clicked) newBtn.setToolTipText(self.app.strings.getString("new_tooltip")) #layout panel2.add(topPanel, BorderLayout.PAGE_START) panel2.add(self.scrollPane, BorderLayout.LINE_START) panel2.add(self.zonesMap, BorderLayout.CENTER) self.buttonsPanel = JPanel() self.buttonsPanel.add(self.removeBtn) self.buttonsPanel.add(newBtn) panel2.add(self.buttonsPanel, BorderLayout.PAGE_END) self.tabbedPane.addTab(self.app.strings.getString("tab_2_title"), None, panel2, None) #3 Tab Tools options panel3 = JPanel() panel3.setLayout(BoxLayout(panel3, BoxLayout.Y_AXIS)) panel3.setBorder(BorderFactory.createEmptyBorder(7, 7, 7, 7)) for tool in self.app.realTools: if hasattr(tool, 'prefs'): p = JPanel(FlowLayout(FlowLayout.LEFT)) p.setBorder(BorderFactory.createTitledBorder(tool.title)) p.add(tool.prefsGui) panel3.add(p) self.tabbedPane.addTab(self.app.strings.getString("tab_3_title"), None, panel3, None) self.add(self.tabbedPane, BorderLayout.CENTER) exitPanel = JPanel() saveBtn = JButton(self.app.strings.getString("OK"), ImageProvider.get("ok"), actionPerformed=self.on_saveBtn_clicked) cancelBtn = JButton(self.app.strings.getString("cancel"), ImageProvider.get("cancel"), actionPerformed=self.on_cancelBtn_clicked) saveBtn.setToolTipText(self.app.strings.getString("save_preferences")) saveBtn.setAlignmentX(0.5) exitPanel.add(saveBtn) exitPanel.add(cancelBtn) self.add(exitPanel, BorderLayout.PAGE_END) self.addWindowListener(self) self.pack() def windowClosing(self, windowEvent): self.on_cancelBtn_clicked() def hyperlinkUpdate(self, e): if e.getEventType() == HyperlinkEvent.EventType.ACTIVATED: OpenBrowser.displayUrl(e.getURL().toString()) def itemStateChanged(self, e): """A ttol has been activated/deactivated. Check if at least one tool is on. """ if all(not button.isSelected() for button in self.toolsCBtns): JOptionPane.showMessageDialog( Main.parent, self.app.strings.getString("tools_disabled_warning"), self.app.strings.getString("tools_disabled_warning_title"), JOptionPane.WARNING_MESSAGE) source = e.getItemSelectable() source.setSelected(True) def actionPerformed(self, e=None): """Enable/disable favourite zones panel """ for container in (self.scrollPane, self.buttonsPanel): self.enableComponents(container, self.favZoneStatusCBtn.isSelected()) if self.favZoneStatusCBtn.isSelected(): self.check_removeBtn_status() def enableComponents(self, container, enable): components = container.getComponents() for component in components: component.setEnabled(enable) if isinstance(component, Container): self.enableComponents(component, enable) def on_downloadBtn_clicked(self, e): update_checker.Updater(self.app, "manual") def clean_map(self): """Remove all rectangles and polygons from the map """ self.zonesMap.removeAllMapRectangles() self.zonesMap.removeAllMapPolygons() def update_gui_from_preferences(self): """Update gui status of preferences frame from config file """ #print "\n- updating Preferences gui" onOff = {"on": True, "off": False} #1 Tab #check for update self.updateCBtn.setSelected(onOff[self.app.checkUpdate]) #tools status, enabled or not for toolIndex, tool in enumerate(self.app.realTools): if "tool.%s" % tool.name in self.app.properties.keys(): configstatus = self.app.properties.getProperty("tool.%s" % tool.name) else: configstatus = "on" # new tool self.toolsCBtns[toolIndex].setSelected(onOff[configstatus]) #layers preferences for mode, button in self.layersRBtns.iteritems(): button.setSelected(mode == self.app.layersMode) #max errors number self.maxErrorsNumberTextField.setText(str(self.app.maxErrorsNumber)) #stats panel self.app.dlg.update_favourite_zone_indicator() #2 Tab #favourite area self.update_favourite_area_gui_from_preferences() self.app.dlg.update_statsPanel_status() #3 Tab #tools preferences for tool in self.app.allTools: if hasattr(tool, 'prefs') and tool.prefsGui is not None: tool.prefsGui.update_gui(tool.prefs) def update_favourite_area_gui_from_preferences(self): #status self.favZoneStatusCBtn.setSelected(self.app.favouriteZoneStatus) #table #store zones to a temporary list, used to store changes #and save them when preferences dialog is closed self.app.tempZones = list(self.app.zones) self.zonesTable.getModel().setNumRows(0) for zone in self.app.tempZones: self.zonesTable.getModel().addRow( [zone.country, zone.icon, zone.name]) if self.app.favZone is not None: selectedRow = self.app.tempZones.index(self.app.favZone) self.zonesTable.setRowSelectionInterval(selectedRow, selectedRow) self.zonesTable.getColumnModel().getColumn(0).setMaxWidth(30) self.zonesTable.getColumnModel().getColumn(1).setMaxWidth(50) #enable or disable favourite zone buttons self.actionPerformed() ### fav area editing buttons ########################################### def on_removeBtn_clicked(self, e): rowsNum = self.zonesTable.getSelectedRows() rowsNum.reverse() for rowNum in rowsNum: del self.app.tempZones[rowNum] self.zonesTable.getModel().removeRow(rowNum) if len(self.app.tempZones) != 0: if rowNum == 0: self.zonesTable.setRowSelectionInterval(0, 0) else: self.zonesTable.setRowSelectionInterval(rowNum - 1, rowNum - 1) self.check_removeBtn_status() def check_removeBtn_status(self): if self.app.tempZones != [] and len( self.zonesTable.getSelectedRows()) != 0: self.removeBtn.setEnabled(True) else: self.removeBtn.setEnabled(False) self.clean_map() def on_newBtn_clicked(self, e): try: self.newZoneDialog except AttributeError: self.newZoneDialog = NewZoneDialog(self.app) bbox = self.app.get_frame_bounds() self.app.newZone = Zone(self.app, self.app.strings.getString("New_zone"), "rectangle", ",".join(["%0.4f" % x for x in bbox]), "") self.newZoneDialog.update_gui_from_preferences() self.newZoneDialog.show() ### Exit from preferences ############################################## def on_cancelBtn_clicked(self, event=None): if hasattr(self, "newZoneDialog") and self.newZoneDialog.isVisible(): self.newZoneDialog.close_dialog() self.dispose() def on_saveBtn_clicked(self, event): """Read preferences from gui and save them to config.properties file """ #print "\n- saving preferences to config file" onOff = {True: "on", False: "off"} #1 Tab #check for update self.app.properties.setProperty("check_for_update", onOff[self.updateCBtn.isSelected()]) #tools status for toolIndex, tool in enumerate(self.app.realTools): prop = "tool.%s" % tool.name toolCBtn = self.toolsCBtns[toolIndex] self.app.properties.setProperty(prop, onOff[toolCBtn.isSelected()]) #layers preferences for mode, button in self.layersRBtns.iteritems(): if button.isSelected(): self.app.properties.setProperty("layers_mode", mode) break #max errors number try: num = Integer.parseInt(self.maxErrorsNumberTextField.getText()) except NumberFormatException: num = "" self.app.properties.setProperty("max_errors_number", str(num)) #2 Tab #Favourite zones changes = { "new": [z for z in self.app.tempZones if not z in self.app.zones], "deleted": [z for z in self.app.zones if not z in self.app.tempZones] } #delete files of removed favourite zones for zone in changes["deleted"]: f = File( File.separator.join([ self.app.SCRIPTDIR, "configuration", "favourite_zones", "%s.txt" % zone.name ])) f.delete() #create files for new favourite zones for zone in changes["new"]: print "\nsave new zone", zone.name fileName = File.separator.join([ self.app.SCRIPTDIR, "configuration", "favourite_zones", "%s.txt" % zone.name ]) f = open(fileName, "w") zoneData = zone.geomString if zone.country != "": zoneData += "|" + zone.country f.write(zoneData.encode("utf-8")) f.close() self.app.zones = self.app.tempZones if len(self.app.zones) == 0: self.app.favZone = None self.app.properties.setProperty("favourite_area.name", "") self.favZoneStatusCBtn.setSelected(False) else: if len(self.zonesTable.getSelectedRows()) == 0: self.app.favZone = self.app.zones[0] else: self.app.favZone = self.app.zones[ self.zonesTable.getSelectedRows()[0]] self.app.properties.setProperty("favourite_area.name", self.app.favZone.name) favZoneStatus = self.favZoneStatusCBtn.isSelected() self.app.properties.setProperty("favourite_area.status", onOff[favZoneStatus]) self.app.favouriteZoneStatus = favZoneStatus #stats panel self.app.dlg.update_favourite_zone_indicator() self.app.dlg.update_statsPanel_status() #3 Tab #tools preferences for tool in self.app.allTools: if hasattr(tool, 'prefs') and tool.prefsGui is not None: for pref, value in tool.prefsGui.read_gui().iteritems(): prefKey = "tool.%s.%s" % (tool.name, pref) self.app.properties.setProperty(prefKey, value) self.app.save_config() self.dispose()
class NewZoneDialog(JDialog, ActionListener, WindowListener): """Dialog for favourite zone editing """ def __init__(self, parent, title, modal, app): from java.awt import CardLayout self.app = app border = BorderFactory.createEmptyBorder(5, 7, 7, 7) self.getContentPane().setBorder(border) self.setLayout(BoxLayout(self.getContentPane(), BoxLayout.Y_AXIS)) self.FAVAREALAYERNAME = "Favourite zone editing" info = JLabel(self.app.strings.getString("Create_a_new_favourite_zone")) info.setAlignmentX(Component.LEFT_ALIGNMENT) #Name nameLbl = JLabel(self.app.strings.getString("fav_zone_name")) self.nameTextField = JTextField(20) self.nameTextField.setMaximumSize(self.nameTextField.getPreferredSize()) self.nameTextField.setToolTipText(self.app.strings.getString("fav_zone_name_tooltip")) namePanel = JPanel() namePanel.setLayout(BoxLayout(namePanel, BoxLayout.X_AXIS)) namePanel.add(nameLbl) namePanel.add(Box.createHorizontalGlue()) namePanel.add(self.nameTextField) #Country countryLbl = JLabel(self.app.strings.getString("fav_zone_country")) self.countryTextField = JTextField(20) self.countryTextField.setMaximumSize(self.countryTextField.getPreferredSize()) self.countryTextField.setToolTipText(self.app.strings.getString("fav_zone_country_tooltip")) countryPanel = JPanel() countryPanel.setLayout(BoxLayout(countryPanel, BoxLayout.X_AXIS)) countryPanel.add(countryLbl) countryPanel.add(Box.createHorizontalGlue()) countryPanel.add(self.countryTextField) #Type modeLbl = JLabel(self.app.strings.getString("fav_zone_type")) RECTPANEL = "rectangle" POLYGONPANEL = "polygon" BOUNDARYPANEL = "boundary" self.modesStrings = [RECTPANEL, POLYGONPANEL, BOUNDARYPANEL] modesComboModel = DefaultComboBoxModel() for i in (self.app.strings.getString("rectangle"), self.app.strings.getString("delimited_by_a_closed_way"), self.app.strings.getString("delimited_by_an_administrative_boundary")): modesComboModel.addElement(i) self.modesComboBox = JComboBox(modesComboModel, actionListener=self, editable=False) #- Rectangle self.rectPanel = JPanel() self.rectPanel.setLayout(BoxLayout(self.rectPanel, BoxLayout.Y_AXIS)) capturePane = JPanel() capturePane.setLayout(BoxLayout(capturePane, BoxLayout.X_AXIS)) capturePane.setAlignmentX(Component.LEFT_ALIGNMENT) josmP = JPanel() self.captureRBtn = JRadioButton(self.app.strings.getString("capture_area")) self.captureRBtn.addActionListener(self) self.captureRBtn.setSelected(True) self.bboxFromJosmBtn = JButton(self.app.strings.getString("get_current_area"), actionPerformed=self.on_bboxFromJosmBtn_clicked) self.bboxFromJosmBtn.setToolTipText(self.app.strings.getString("get_capture_area_tooltip")) josmP.add(self.bboxFromJosmBtn) capturePane.add(self.captureRBtn) capturePane.add(Box.createHorizontalGlue()) capturePane.add(self.bboxFromJosmBtn) manualPane = JPanel() manualPane.setLayout(BoxLayout(manualPane, BoxLayout.X_AXIS)) manualPane.setAlignmentX(Component.LEFT_ALIGNMENT) self.manualRBtn = JRadioButton(self.app.strings.getString("use_this_bbox")) self.manualRBtn.addActionListener(self) self.bboxTextField = JTextField(20) self.bboxTextField.setMaximumSize(self.bboxTextField.getPreferredSize()) self.bboxTextField.setToolTipText(self.app.strings.getString("fav_bbox_tooltip")) self.bboxTextFieldDefaultBorder = self.bboxTextField.getBorder() self.bboxTextField.getDocument().addDocumentListener(TextListener(self)) manualPane.add(self.manualRBtn) manualPane.add(Box.createHorizontalGlue()) manualPane.add(self.bboxTextField) group = ButtonGroup() group.add(self.captureRBtn) group.add(self.manualRBtn) previewPane = JPanel() previewPane.setLayout(BoxLayout(previewPane, BoxLayout.X_AXIS)) previewPane.setAlignmentX(Component.LEFT_ALIGNMENT) bboxPreviewInfo = JTextField(self.app.strings.getString("coordinates"), editable=0, border=None) bboxPreviewInfo.setMaximumSize(bboxPreviewInfo.getPreferredSize()) self.bboxPreviewTextField = JTextField(20, editable=0, border=None) self.bboxPreviewTextField.setMaximumSize(self.bboxPreviewTextField.getPreferredSize()) previewPane.add(bboxPreviewInfo) previewPane.add(Box.createHorizontalGlue()) previewPane.add(self.bboxPreviewTextField) self.rectPanel.add(capturePane) self.rectPanel.add(Box.createRigidArea(Dimension(0, 10))) self.rectPanel.add(manualPane) self.rectPanel.add(Box.createRigidArea(Dimension(0, 20))) self.rectPanel.add(previewPane) #- Polygon (closed way) drawn by hand self.polygonPanel = JPanel(BorderLayout()) self.polygonPanel.setLayout(BoxLayout(self.polygonPanel, BoxLayout.Y_AXIS)) polyInfo = JLabel("<html>%s</html>" % self.app.strings.getString("polygon_info")) polyInfo.setFont(polyInfo.getFont().deriveFont(Font.ITALIC)) polyInfo.setAlignmentX(Component.LEFT_ALIGNMENT) editPolyPane = JPanel() editPolyPane.setAlignmentX(Component.LEFT_ALIGNMENT) editPolyBtn = JButton(self.app.strings.getString("create_fav_layer"), actionPerformed=self.create_new_zone_editing_layer) editPolyBtn.setToolTipText(self.app.strings.getString("create_fav_layer_tooltip")) editPolyPane.add(editPolyBtn) self.polygonPanel.add(polyInfo) self.polygonPanel.add(Box.createRigidArea(Dimension(0, 15))) self.polygonPanel.add(editPolyPane) self.polygonPanel.add(Box.createRigidArea(Dimension(0, 15))) #- Administrative Boundary self.boundaryPanel = JPanel() self.boundaryPanel.setLayout(BoxLayout(self.boundaryPanel, BoxLayout.Y_AXIS)) boundaryInfo = JLabel("<html>%s</html>" % app.strings.getString("boundary_info")) boundaryInfo.setFont(boundaryInfo.getFont().deriveFont(Font.ITALIC)) boundaryInfo.setAlignmentX(Component.LEFT_ALIGNMENT) boundaryTagsPanel = JPanel(GridLayout(3, 3, 5, 5)) boundaryTagsPanel.setAlignmentX(Component.LEFT_ALIGNMENT) boundaryTagsPanel.add(JLabel("name =")) self.nameTagTextField = JTextField(20) boundaryTagsPanel.add(self.nameTagTextField) boundaryTagsPanel.add(JLabel("admin_level =")) self.adminLevelTagTextField = JTextField(20) self.adminLevelTagTextField.setToolTipText(self.app.strings.getString("adminLevel_tooltip")) boundaryTagsPanel.add(self.adminLevelTagTextField) boundaryTagsPanel.add(JLabel(self.app.strings.getString("other_tag"))) self.optionalTagTextField = JTextField(20) self.optionalTagTextField.setToolTipText("key=value") boundaryTagsPanel.add(self.optionalTagTextField) downloadBoundariesPane = JPanel() downloadBoundariesPane.setAlignmentX(Component.LEFT_ALIGNMENT) downloadBoundariesBtn = JButton(self.app.strings.getString("download_boundary"), actionPerformed=self.on_downloadBoundariesBtn_clicked) downloadBoundariesBtn.setToolTipText(self.app.strings.getString("download_boundary_tooltip")) downloadBoundariesPane.add(downloadBoundariesBtn) self.boundaryPanel.add(boundaryInfo) self.boundaryPanel.add(Box.createRigidArea(Dimension(0, 15))) self.boundaryPanel.add(boundaryTagsPanel) self.boundaryPanel.add(Box.createRigidArea(Dimension(0, 10))) self.boundaryPanel.add(downloadBoundariesPane) self.editingPanels = {"rectangle": self.rectPanel, "polygon": self.polygonPanel, "boundary": self.boundaryPanel} #Main buttons self.okBtn = JButton(self.app.strings.getString("OK"), ImageProvider.get("ok"), actionPerformed=self.on_okBtn_clicked) self.cancelBtn = JButton(self.app.strings.getString("cancel"), ImageProvider.get("cancel"), actionPerformed=self.close_dialog) self.previewBtn = JButton(self.app.strings.getString("Preview_zone"), actionPerformed=self.on_previewBtn_clicked) self.previewBtn.setToolTipText(self.app.strings.getString("preview_zone_tooltip")) okBtnSize = self.okBtn.getPreferredSize() viewBtnSize = self.previewBtn.getPreferredSize() viewBtnSize.height = okBtnSize.height self.previewBtn.setPreferredSize(viewBtnSize) #layout self.add(info) self.add(Box.createRigidArea(Dimension(0, 15))) namePanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(namePanel) self.add(Box.createRigidArea(Dimension(0, 15))) countryPanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(countryPanel) self.add(Box.createRigidArea(Dimension(0, 15))) modeLbl.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(modeLbl) self.add(Box.createRigidArea(Dimension(0, 5))) self.add(self.modesComboBox) self.modesComboBox.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(Box.createRigidArea(Dimension(0, 15))) self.configPanel = JPanel(CardLayout()) self.configPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)) self.configPanel.add(self.rectPanel, RECTPANEL) self.configPanel.add(self.polygonPanel, POLYGONPANEL) self.configPanel.add(self.boundaryPanel, BOUNDARYPANEL) self.configPanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(self.configPanel) buttonsPanel = JPanel() buttonsPanel.add(self.okBtn) buttonsPanel.add(self.cancelBtn) buttonsPanel.add(self.previewBtn) buttonsPanel.setAlignmentX(Component.LEFT_ALIGNMENT) self.add(buttonsPanel) self.addWindowListener(self) self.pack() def update_gui_from_preferences(self): self.nameTextField.setText(self.app.newZone.name) #Reset rectangle mode bboxStr = ",".join(["%0.4f" % x for x in self.app.newZone.bbox]) self.bboxTextField.setText(bboxStr) self.bboxPreviewTextField.setText(bboxStr) self.bboxFromJosmBtn.setEnabled(True) self.bboxTextField.setEnabled(False) #Reset polygon mode self.polygonAsString = "" #Reset boundary mode self.boundaryAsString = "" self.modesComboBox.setSelectedIndex(0) def actionPerformed(self, e): #Show the panel for configuring the favourite area of the #selected type if e.getSource() == self.modesComboBox: cl = self.configPanel.getLayout() selectedMode = self.modesStrings[self.modesComboBox.selectedIndex] cl.show(self.configPanel, selectedMode) #Activate bbox input for rectangular favourite zone mode elif e.getSource() == self.captureRBtn: self.bboxFromJosmBtn.setEnabled(True) self.bboxTextField.setEnabled(False) else: self.bboxFromJosmBtn.setEnabled(False) self.bboxTextField.setEnabled(True) def on_bboxFromJosmBtn_clicked(self, widget): """Read bbox currently shown in JOSM """ bbox = self.app.get_frame_bounds() self.bboxPreviewTextField.setText(",".join(["%0.4f" % x for x in bbox])) ### Manage layer for creating a new favourite zone from polygon or boundary def create_new_zone_editing_layer(self, e=None): """Open a new dataset where the user can draw a closed way to delimit the favourite area """ layer = self.get_new_zone_editing_layer() if layer is not None: self.app.mv.setActiveLayer(layer) else: Main.main.addLayer(OsmDataLayer(DataSet(), self.FAVAREALAYERNAME, None)) Main.main.parent.toFront() def get_new_zone_editing_layer(self): """Check if the layer for editing the favourite area yet exists """ for layer in self.app.mv.getAllLayers(): if layer.getName() == self.FAVAREALAYERNAME: return layer return None def remove_new_zone_editing_layer(self): layer = self.get_new_zone_editing_layer() if layer is not None: self.app.mv.removeLayer(layer) def on_zone_edited(self): """Read ways that delimit the favourite area and convert them to jts geometry """ if self.modesComboBox.getSelectedIndex() == 0: mode = "rectangle" elif self.modesComboBox.getSelectedIndex() == 1: mode = "polygon" elif self.modesComboBox.getSelectedIndex() == 2: mode = "boundary" if mode in ("polygon", "boundary"): layer = self.get_new_zone_editing_layer() if layer is not None: self.app.mv.setActiveLayer(layer) else: if mode == "polygon": msg = self.app.strings.getString("polygon_fav_layer_missing_msg") else: msg = self.app.strings.getString("boundary_fav_layer_missing_msg") JOptionPane.showMessageDialog(self, msg, self.app.strings.getString("Warning"), JOptionPane.WARNING_MESSAGE) return dataset = self.app.mv.editLayer.data areaWKT = self.read_area_from_osm_ways(mode, dataset) if areaWKT is None: print "I could not read the new favourite area." else: if mode == "polygon": self.polygonAsString = areaWKT else: self.boundaryAsString = areaWKT return mode def read_area_from_osm_ways(self, mode, dataset): """Read way in favourite area editing layer and convert them to WKT """ converter = JTSConverter(False) lines = [converter.convert(way) for way in dataset.ways] polygonizer = Polygonizer() polygonizer.add(lines) polygons = polygonizer.getPolygons() multipolygon = GeometryFactory().createMultiPolygon(list(polygons)) multipolygonWKT = WKTWriter().write(multipolygon) if multipolygonWKT == "MULTIPOLYGON EMPTY": if mode == "polygon": msg = self.app.strings.getString("empty_ways_polygon_msg") else: msg = self.app.strings.getString("empty_ways_boundaries_msg") JOptionPane.showMessageDialog(self, msg, self.app.strings.getString("Warning"), JOptionPane.WARNING_MESSAGE) return return multipolygonWKT def on_downloadBoundariesBtn_clicked(self, e): """Download puter ways of administrative boundaries from Overpass API """ adminLevel = self.adminLevelTagTextField.getText() name = self.nameTagTextField.getText() optional = self.optionalTagTextField.getText() if (adminLevel, name, optional) == ("", "", ""): JOptionPane.showMessageDialog(self, self.app.strings.getString("enter_a_tag_msg"), self.app.strings.getString("Warning"), JOptionPane.WARNING_MESSAGE) return optTag = "" if optional.find("=") != -1: if len(optional.split("=")) == 2: key, value = optional.split("=") optTag = '["%s"="%s"]' % (URLEncoder.encode(key, "UTF-8"), URLEncoder.encode(value.replace(" ", "%20"), "UTF-8")) self.create_new_zone_editing_layer() overpassurl = 'http://127.0.0.1:8111/import?url=' overpassurl += 'http://overpass-api.de/api/interpreter?data=' overpassquery = 'relation["admin_level"="%s"]' % adminLevel overpassquery += '["name"="%s"]' % URLEncoder.encode(name, "UTF-8") overpassquery += '%s;(way(r:"outer");node(w););out meta;' % optTag overpassurl += overpassquery.replace(" ", "%20") print overpassurl self.app.send_to_josm(overpassurl) ### Buttons ############################################################ def create_new_zone(self, mode): """Read data entered on gui and create a new zone """ name = self.nameTextField.getText() country = self.countryTextField.getText().upper() #error: name if name.replace(" ", "") == "": JOptionPane.showMessageDialog(self, self.app.strings.getString("missing_name_warning"), self.app.strings.getString("missing_name_warning_title"), JOptionPane.WARNING_MESSAGE) return False if name in [z.name for z in self.app.tempZones]: JOptionPane.showMessageDialog(self, self.app.strings.getString("duplicate_name_warning"), self.app.strings.getString("duplicate_name_warning_title"), JOptionPane.WARNING_MESSAGE) return False #zone type zType = mode #error: geometry type not defined if zType == "polygon" and self.polygonAsString == ""\ or zType == "boundary" and self.boundaryAsString == "": JOptionPane.showMessageDialog(self, self.app.strings.getString("zone_not_correctly_build_warning"), self.app.strings.getString("zone_not_correctly_build_warning_title"), JOptionPane.WARNING_MESSAGE) return False #geometry string if zType == "rectangle": geomString = self.bboxPreviewTextField.getText() elif zType == "polygon": geomString = self.polygonAsString else: geomString = self.boundaryAsString self.app.newZone = Zone(self.app, name, zType, geomString, country) #self.app.newZone.print_info() return True def on_okBtn_clicked(self, event): """Add new zone to temp zones """ mode = self.on_zone_edited() if self.create_new_zone(mode): self.app.tempZones.append(self.app.newZone) self.app.preferencesFrame.zonesTable.getModel().addRow([self.app.newZone.country, self.app.newZone.icon, self.app.newZone.name]) maxIndex = len(self.app.tempZones) - 1 self.app.preferencesFrame.zonesTable.setRowSelectionInterval(maxIndex, maxIndex) self.close_dialog() self.app.preferencesFrame.check_removeBtn_status() self.app.preferencesFrame.zonesTable.scrollRectToVisible( self.app.preferencesFrame.zonesTable.getCellRect( self.app.preferencesFrame.zonesTable.getRowCount() - 1, 0, True)) def on_previewBtn_clicked(self, e): """Show the favourite area on a map """ mode = self.on_zone_edited() if not self.create_new_zone(mode): return zone = self.app.newZone if zone.zType == "rectangle": wktString = zone.bbox_to_wkt_string() else: wktString = zone.wktGeom script = '/*http://stackoverflow.com/questions/11954401/wkt-and-openlayers*/' script += '\nfunction init() {' script += '\n var map = new OpenLayers.Map({' script += '\n div: "map",' script += '\n projection: new OpenLayers.Projection("EPSG:900913"),' script += '\n displayProjection: new OpenLayers.Projection("EPSG:4326"),' script += '\n layers: [' script += '\n new OpenLayers.Layer.OSM()' script += '\n ]' script += '\n });' script += '\n var wkt = new OpenLayers.Format.WKT();' script += '\n var polygonFeature = wkt.read("%s");' % wktString script += '\n var vectors = new OpenLayers.Layer.Vector("Favourite area");' script += '\n map.addLayer(vectors);' script += '\n polygonFeature.geometry.transform(map.displayProjection, map.getProjectionObject());' script += '\n vectors.addFeatures([polygonFeature]);' script += '\n map.zoomToExtent(vectors.getDataExtent());' script += '\n};' scriptFile = open(File.separator.join([self.app.SCRIPTDIR, "html", "script.js"]), "w") scriptFile.write(script) scriptFile.close() OpenBrowser.displayUrl(File.separator.join([self.app.SCRIPTDIR, "html", "favourite_area.html"])) def windowClosing(self, windowEvent): self.close_dialog() def close_dialog(self, e=None): #delete favourite zone editing layer if present self.remove_new_zone_editing_layer() self.dispose() self.app.preferencesFrame.setEnabled(True) self.app.preferencesFrame.toFront()
class BurpExtender(IBurpExtender, ITab): socket_time_out = 3 def registerExtenderCallbacks(self, callbacks): self.out = callbacks.getStdout() self.callbacks = callbacks self.helpers = callbacks.getHelpers() callbacks.setExtensionName("WhatsApp Decoder") self.banner = JLabel("WHATSAPP DECRYPTION AND ENCRYPTION EXTENSION BY DIKLA BARDA, ROMAN ZAIKIN", SwingConstants.CENTER) self.banner.setFont(Font("Serif", Font.PLAIN, 17)) self.banner.setBorder(BorderFactory.createLineBorder(Color.BLACK)) self.statusConn = JLabel("CONNECTION STATUS: ") self.statusConnField = JLabel("NOT CONNECTED") self.statusAct = JLabel("ACTION STATUS: ") self.statusActField = JLabel("OK") self.ref = JLabel("Ref object: ") self.refField = JTextField("123", 80) self.refField.setToolTipText("Copy the Ref from burpsuit WebSocket, make sure that the parameter 'secret' is there and you copy only the 'ref' without the connection and other data, if not logout from your whatsapp web and login again.") self.privateKey = JLabel("Private Key:") self.privateKeyField = JTextField("123", 80) self.privateKeyField.setToolTipText("Copy the private key list from your whatsapp web according to our blog post ") self.publicKey = JLabel("Public Key: ") self.publicKeyField = JTextField("123", 80) self.publicKeyField.setToolTipText("Copy the public key list from your whatsapp web according to our blog post") self.statusPanel1 = JPanel() self.statusPanel1.add(self.statusConn) self.statusPanel1.add(self.statusConnField) self.statusPanel2 = JPanel() self.statusPanel2.add(self.statusAct) self.statusPanel2.add(self.statusActField) self.privateKeyPanel = JPanel() self.privateKeyPanel.add(self.privateKey) self.privateKeyPanel.add(self.privateKeyField) self.publicKeyPanel = JPanel() self.publicKeyPanel.add(self.publicKey) self.publicKeyPanel.add(self.publicKeyField) self.refPanel = JPanel() self.refPanel.add(self.ref) self.refPanel.add(self.refField) self.messageField = JTextArea("", 5, 90) self.messageField.setLineWrap(True) self.messageField.setToolTipText("If you putting in the incoming traffic you can copy it from burp suit, the outgoing is the list from aesCbcEncrypt") self.whatsAppMessagesPanel = JPanel() self.whatsAppMessagesPanel.add(self.messageField) self.btnSave = JButton("Connect", actionPerformed=self.saveConfig) self.btnRestore = JButton("Clear", actionPerformed=self.clearConfig) self.grpConfig = JPanel() self.grpConfig.add(self.btnSave) self.grpConfig.add(self.btnRestore) self.btnIncoming = JButton("Incoming", actionPerformed=self.performAction) self.btnOutgoing = JButton("Outgoing", actionPerformed=self.performAction) self.btnEncrypt = JButton("Encrypt", actionPerformed=self.performAction) self.btnEncrypt.setEnabled(False) # Can't send data without a direction self.btnDecrypt = JButton("Decrypt", actionPerformed=self.performAction) self.btnDecrypt.setEnabled(False) # Can't send data without a direction self.btnCrypt = JPanel() self.btnCrypt.add(self.btnIncoming) self.btnCrypt.add(self.btnEncrypt) self.btnCrypt.add(self.btnDecrypt) self.btnCrypt.add(self.btnOutgoing) self.tab = JPanel() layout = GridBagLayout() self.tab.setLayout(layout) c = GridBagConstraints() c.ipadx = 0 c.ipady = 0 c.fill = GridBagConstraints.BOTH #c.weightx = 0 # gap between the x items #c.weighty = 0 # gap between the y items c.anchor = GridBagConstraints.NORTHWEST c.gridx = 0 c.gridy = 0 self.tab.add(self.banner, c) c.gridx = 0 c.gridy = 1 self.tab.add(self.refPanel, c) c.gridx = 0 c.gridy = 2 self.tab.add(self.privateKeyPanel, c) c.gridx = 0 c.gridy = 3 self.tab.add(self.publicKeyPanel, c) c.gridx = 0 c.gridy = 4 c.anchor = GridBagConstraints.CENTER self.tab.add(self.grpConfig, c) c.gridx = 0 c.gridy = 5 self.tab.add(self.whatsAppMessagesPanel, c) c.gridx = 0 c.gridy = 6 self.tab.add(self.btnCrypt, c) c.gridx = 0 c.gridy = 7 self.tab.add(self.statusPanel1, c) c.gridx = 0 c.gridy = 8 self.tab.add(self.statusPanel2, c) # restore config self.restoreConfig() callbacks.addSuiteTab(self) def performAction(self, e=None): self.client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.client.settimeout(self.socket_time_out) self.data = self.messageField.getText() eventSource = e.getSource() eventSource.setEnabled(False) # Incoming data if eventSource == self.btnIncoming: self.direction = "in" self.btnOutgoing.setEnabled(True) self.btnEncrypt.setEnabled(True) self.btnDecrypt.setEnabled(True) # Outgoing data elif eventSource == self.btnOutgoing: self.direction = "out" self.btnIncoming.setEnabled(True) self.btnEncrypt.setEnabled(True) self.btnDecrypt.setEnabled(True) # Send elif eventSource == self.btnDecrypt: self.btnDecrypt.setEnabled(True) clientData = json.dumps({"action": "decrypt", "data": { "direction": self.direction, "msg": self.messageField.getText() } }) self.client.sendto(clientData, ("127.0.0.1",2912)) try: serverData, addr = self.client.recvfrom(2048) serverData = json.loads(serverData) if serverData["status"] == 0: print serverData self.messageField.setText(json.dumps(serverData["data"])) self.statusActField.setForeground(Color.GREEN) self.statusActField.setText("OK") else: self.statusActField.setForeground(Color.RED) self.statusActField.setText("Error: {}".format(json.dumps(serverData["data"]))) except socket.timeout: pass elif eventSource == self.btnEncrypt: self.btnEncrypt.setEnabled(True) clientData = json.dumps({"action": "encrypt", "data": { "direction": self.direction, "msg": self.messageField.getText() } }) self.client.sendto(clientData, ("127.0.0.1", 2912)) try: serverData, addr = self.client.recvfrom(2048) serverData = json.loads(serverData) if serverData["status"] == 0: if isinstance(serverData["data"], list): self.messageField.setText(json.dumps(serverData["data"])) else: self.messageField.setText(serverData["data"]) self.statusActField.setForeground(Color.GREEN) self.statusActField.setText("OK") else: self.statusActField.setForeground(Color.RED) self.statusActField.setText("Error: {}".format(json.dumps(serverData["data"]))) except socket.timeout: pass self.client.close() def saveConfig(self, e=None): self.client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.client.settimeout(self.socket_time_out) config = { 'ref': self.refField.getText(), 'private': self.privateKeyField.getText(), 'public': self.publicKeyField.getText(), } self.callbacks.saveExtensionSetting("config", pickle.dumps(config)) try: clientData = json.dumps({"action":"init", "data":{ "ref":json.loads(self.refField.getText()), "private":self.privateKeyField.getText(), "public":self.publicKeyField.getText() } }) self.client.sendto(clientData, ("127.0.0.1", 2912)) serverData, addr = self.client.recvfrom(2048) print (serverData) self.statusConnField.setText("CONNECTED") self.statusActField.setForeground(Color.GREEN) self.statusActField.setText("OK") except socket.timeout: self.statusActField.setForeground(Color.RED) self.statusActField.setText("Error: Can't connect to the local server make sure parser.py is running!") pass except Exception as e: self.statusActField.setForeground(Color.RED) self.statusActField.setText("Error: make Sure the ref is a correct json!") self.client.close() def clearConfig(self, e=None): self.refField.setText("") self.privateKeyField.setText("") self.publicKeyField.setText("") self.statusConnField.setText("NOT CONNECTED") self.statusActField.setText("OK") self.messageField.setText("") def restoreConfig(self, e=None): storedConfig = self.callbacks.loadExtensionSetting("config") if storedConfig != None: config = pickle.loads(storedConfig) self.refField.setText(config["ref"]) self.privateKeyField.setText(config["private"]) self.publicKeyField.setText(config["public"]) def getTabCaption(self): return ("WhatsApp Decoder") def getUiComponent(self): return self.tab
class BurpExtender(IBurpExtender, IScannerCheck, IScanIssue, ITab): def registerExtenderCallbacks(self, callbacks): self.callbacks = callbacks self.helpers = callbacks.getHelpers() callbacks.setExtensionName("Missing Scanner Checks") self.out = callbacks.getStdout() # define all checkboxes self.cbPassiveChecks = self.defineCheckBox("Passive Scanner Checks") self.cbDOMXSS = self.defineCheckBox("DOM XSS", False) self.cbDOMXSSSources = self.defineCheckBox("Sources", False) self.cbDOMXSSSinks = self.defineCheckBox("Sinks") self.cbDOMXSSjQuerySinks = self.defineCheckBox("jQuery Sinks", False) self.grpDOMXSSSettings = JPanel() self.grpDOMXSSSettings.add(self.cbDOMXSSSources) self.grpDOMXSSSettings.add(self.cbDOMXSSSinks) self.grpDOMXSSSettings.add(self.cbDOMXSSjQuerySinks) self.cbSTS = self.defineCheckBox("Strict Transport Security") self.lblSTSMin = JLabel("Minimum acceptable max-age") self.inSTSMin = JTextField( str(STSMinimum), 9, actionPerformed=self.setSTSMinimum ) # TODO: actionPerformed only fires on enter key - focus lost would be better self.inSTSMin.setToolTipText( "Enter the minimum max-age value which is considered as acceptable. Press return to change setting!" ) self.grpSTSSettings = JPanel() self.grpSTSSettings.add(self.lblSTSMin) self.grpSTSSettings.add(self.inSTSMin) self.cbXCTO = self.defineCheckBox("Content Sniffing") self.cbXXP = self.defineCheckBox( "Client-side XSS Filter Configuration") self.cbRedirToHTTPS = self.defineCheckBox( "Redirection from HTTP to HTTPS") self.btnSave = JButton("Set as default", actionPerformed=self.saveConfig) self.btnRestore = JButton("Restore", actionPerformed=self.restoreConfig) self.grpConfig = JPanel() self.grpConfig.add(self.btnSave) self.grpConfig.add(self.btnRestore) self.restoreConfig() # definition of config tab self.tab = JPanel() layout = GroupLayout(self.tab) self.tab.setLayout(layout) layout.setAutoCreateGaps(True) layout.setAutoCreateContainerGaps(True) layout.setHorizontalGroup(layout.createSequentialGroup().addGroup( layout.createParallelGroup().addComponent(self.cbPassiveChecks) ).addGroup(layout.createParallelGroup().addComponent( self.cbDOMXSS).addComponent(self.cbSTS).addComponent( self.cbXCTO).addComponent(self.cbXXP).addComponent( self.cbRedirToHTTPS)).addGroup( layout.createParallelGroup().addComponent( self.grpDOMXSSSettings, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE).addComponent( self.grpSTSSettings, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE).addComponent( self.grpConfig, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE))) layout.setVerticalGroup(layout.createSequentialGroup().addGroup( layout.createParallelGroup().addComponent( self.cbPassiveChecks).addComponent(self.cbDOMXSS).addComponent( self.grpDOMXSSSettings, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)).addGroup( layout.createParallelGroup().addComponent( self.cbSTS).addComponent( self.grpSTSSettings, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)).addComponent( self.cbXCTO).addComponent( self.cbXXP).addComponent( self.cbRedirToHTTPS).addComponent( self.grpConfig, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE, GroupLayout.PREFERRED_SIZE)) self.domXSSSourcesRE = re.compile( "(location\s*[\[.])|([.\[]\s*[\"']?\s*(arguments|dialogArguments|innerHTML|write(ln)?|open(Dialog)?|showModalDialog|cookie|URL|documentURI|baseURI|referrer|name|opener|parent|top|content|self|frames)\W)|(localStorage|sessionStorage|Database)" ) # NOTE: done some optimizations here, original RE caused too much noise # - added leading dot in the first part - original recognized "<a href=..." etc. # - removed "value" in first part self.domXSSSinksRE = re.compile( "(\.(src|href|data|location|code|action)\s*[\"'\]]*\s*\+?\s*=)|((replace|assign|navigate|getResponseHeader|open(Dialog)?|showModalDialog|eval|evaluate|execCommand|execScript|setTimeout|setInterval)\s*[\"'\]]*\s*\()" ) self.domXSSjQuerySinksRE = re.compile( "after\(|\.append\(|\.before\(|\.html\(|\.prepend\(|\.replaceWith\(|\.wrap\(|\.wrapAll\(|\$\(|\.globalEval\(|\.add\(|jQUery\(|\$\(|\.parseHTML\(" ) self.headerSTSRE = re.compile( "^Strict-Transport-Security:.*?max-age=\"?(\d+)\"?", re.I) # TODO: multiple max-age directives cause confusion! self.headerXCTORE = re.compile( "^X-Content-Type-Options:\s*nosniff\s*$", re.I) self.headerXXP = re.compile( "^X-XSS-Protection:\s*(\d)(?:\s*;\s*mode\s*=\s*\"?(block)\"?)?", re.I) self.headerLocationHTTPS = re.compile( "^(?:Content-)?Location:\s*(https://.*)$", re.I) callbacks.registerScannerCheck(self) callbacks.addSuiteTab(self) def defineCheckBox(self, caption, selected=True, enabled=True): checkBox = JCheckBox(caption) checkBox.setSelected(selected) checkBox.setEnabled(enabled) return checkBox def setSTSMinimum(self, e=None): val = self.inSTSMin.text if re.match("^\d+$", val): STSMinimum = int(val) else: self.inSTSMin.setText( str(STSMinimum)) # TODO: doesn't works as desired def saveConfig(self, e=None): config = { 'passiveChecks': self.cbPassiveChecks.isSelected(), 'DOMXSS': self.cbDOMXSS.isSelected(), 'DOMXSSSources': self.cbDOMXSSSources.isSelected(), 'DOMXSSSinks': self.cbDOMXSSSinks.isSelected(), 'DOMXSSjQuerySinks': self.cbDOMXSSjQuerySinks.isSelected(), 'STS': self.cbSTS.isSelected(), 'STSMin': self.inSTSMin.text, 'XCTO': self.cbXCTO.isSelected(), 'XXP': self.cbXXP.isSelected(), 'RedirToHTTPS': self.cbRedirToHTTPS.isSelected(), } self.callbacks.saveExtensionSetting("config", pickle.dumps(config)) def restoreConfig(self, e=None): storedConfig = self.callbacks.loadExtensionSetting("config") if storedConfig != None: try: config = pickle.loads(storedConfig) self.cbPassiveChecks.setSelected(config['passiveChecks']) self.cbDOMXSS.setSelected(config['DOMXSS']) self.cbDOMXSSSources.setSelected(config['DOMXSSSources']) self.cbDOMXSSSinks.setSelected(config['DOMXSSSinks']) self.cbDOMXSSjQuerySinks.setSelected( config['DOMXSSjQuerySinks']) self.cbSTS.setSelected(config['STS']) self.inSTSMin.text = config['STSMin'] self.cbXCTO.setSelected(config['XCTO']) self.cbXXP.setSelected(config['XXP']) self.cbRedirToHTTPS.setSelected(config['RedirToHTTPS']) self.setSTSMinimum() except: print( "Classical case of \"shouldn't happen\": something went wrong with config restore. Submit a bug or patch and keep your eyes open for Zombies. Something is really strange here.\nConfig contained: " + storedConfig) ### ITab ### def getTabCaption(self): return ("Additional Scanner Checks") def getUiComponent(self): return self.tab def doActiveScan(self, baseRequestResponse, insertionPoint): pass ### IScannerCheck ### def doPassiveScan(self, baseRequestResponse): if not self.cbPassiveChecks.isSelected(): return None scanIssues = list() requestProtocol = baseRequestResponse.getHttpService().getProtocol() analyzedResponse = self.helpers.analyzeResponse( baseRequestResponse.getResponse()) responseHeaders = analyzedResponse.getHeaders() bodyOffset = analyzedResponse.getBodyOffset() responseBody = baseRequestResponse.getResponse( )[analyzedResponse.getBodyOffset():].tostring() # Identify DOMXSS sources and sinks domXSSSources = list() domXSSSinks = list() domXSSjQuerySinks = list() if self.cbDOMXSS.isSelected(): if self.cbDOMXSSSources.isSelected(): domXSSSources = self.domXSSSourcesRE.finditer(responseBody) if self.cbDOMXSSSinks.isSelected(): domXSSSinks = self.domXSSSinksRE.finditer(responseBody) if self.cbDOMXSSjQuerySinks.isSelected(): domXSSjQuerySinks = self.domXSSjQuerySinksRE.finditer( responseBody) domXSSSourcesPos = extractMatchPositions(domXSSSources, bodyOffset) domXSSSinksPos = extractMatchPositions(domXSSSinks, bodyOffset) domXSSjQuerySinksPos = extractMatchPositions( domXSSjQuerySinks, bodyOffset) if len(domXSSSourcesPos) + len(domXSSSinksPos) + len( domXSSjQuerySinksPos) > 0: # One of the DOMXSS REs matched scanIssues.append( DOMXSSScanIssue(baseRequestResponse, domXSSSourcesPos, domXSSSinksPos, domXSSjQuerySinksPos, self.helpers, self.callbacks)) # Identify missing, wrong or multiple occurring HTTP headers headersSTS = list() headersXCTO = list() headersXXP = list() headersLocationHTTPS = list() offset = 0 for header in responseHeaders: if self.cbSTS.isSelected(): match = self.headerSTSRE.match(header) if match: headersSTS.append((match, offset)) if self.cbXCTO.isSelected(): match = self.headerXCTORE.match(header) if match: headersXCTO.append(match) if self.cbXXP.isSelected(): match = self.headerXXP.match(header) if match: headersXXP.append((match, offset)) if self.cbRedirToHTTPS.isSelected() and requestProtocol == 'http': match = self.headerLocationHTTPS.match(header) if match: headersLocationHTTPS.append((match, offset)) offset += len( header ) + 2 # TODO: assumption that CRLF is always used. The world is ugly, make a real check. if requestProtocol != "https": pass # HSTS only valid in HTTPS responses. elif self.cbSTS.isSelected(): if len(headersSTS) == 0: # No HSTS header scanIssues.append( STSScanIssue(baseRequestResponse, STSScanIssue.caseNoHeader, None, self.helpers, self.callbacks)) elif len(headersSTS) == 1 and int( headersSTS[0][0].group(1) ) < STSMinimum: # HSTS header present, but time frame too short scanIssues.append( STSScanIssue(baseRequestResponse, STSScanIssue.caseTooLow, (int(headersSTS[0][0].group(1)), headersSTS[0][1] + headersSTS[0][0].start(1), headersSTS[0][1] + headersSTS[0][0].end(1)), self.helpers, self.callbacks)) elif len(headersSTS) > 1: # multiple HSTS headers scanIssues.append( STSScanIssue(baseRequestResponse, STSScanIssue.caseMultipleHeaders, headersSTS, self.helpers, self.callbacks)) # Redirection from HTTP to HTTPS if self.cbRedirToHTTPS.isSelected() and len(headersLocationHTTPS) > 0: scanIssues.append( RedirectFromHTTP2HTTPSScanIssue(baseRequestResponse, headersLocationHTTPS, self.helpers, self.callbacks)) if self.cbXXP.isSelected(): if len(headersXXP) == 0: # No XSS protection header scanIssues.append( XXPScanIssue(baseRequestResponse, XXPScanIssue.caseNoHeader, None, self.helpers, self.callbacks)) elif len(headersXXP) == 1 and int( headersXXP[0][0].group(1)) == 1 and headersXXP[0][0].group( 2) != "block": # Activated but not in block mode scanIssues.append( XXPScanIssue(baseRequestResponse, XXPScanIssue.caseNoBlockMode, headersXXP, self.helpers, self.callbacks)) elif len(headersXXP) > 1: # Multiple XXP headers scanIssues.append( XXPScanIssue(baseRequestResponse, XXPScanIssue.caseMultipleHeaders, headersXXP, self.helpers, self.callbacks)) # "X-XSS-Protection: 0" already catched by Burp # X-Content-Type-Options missing # NOTE: it is assumed that multiple "X-Content-Type-Options: nosniff" headers can't cause confusion at browser side because they all have the same meaning. if self.cbXCTO.isSelected() and len(headersXCTO) == 0: scanIssues.append( XCTOScanIssue(baseRequestResponse, self.helpers, self.callbacks)) return scanIssues def consolidateDuplicateIssues(self, existingIssue, newIssue): if existingIssue.getIssueName() == newIssue.getIssueName(): if newIssue.getIssueName( ) == issueNameDOMXSS: # DOMXSS issues are different if response content is different. responseExisting = existingIssue.getHttpMessages( )[0].getResponse() analyzedResponseExisting = self.helpers.analyzeResponse( responseExisting) bodyOffsetExisting = analyzedResponseExisting.getBodyOffset() responseBodyExisting = responseExisting.getResponse( )[analyzedResponseExisting.getBodyOffset():].tostring() responseNew = newIssue.getHttpMessages()[0].getResponse() analyzedResponseNew = self.helpers.analyzeResponse(responseNew) bodyOffsetNew = analyzedResponseNew.getBodyOffset() responseBodyNew = responseNew.getResponse( )[analyzedResponseNew.getBodyOffset():].tostring() if responseBodyExisting == responseBodyNew: return -1 else: return 0 elif newIssue.getIssueName( ) == issueNameRedirectFromHTTP2HTTPS: # Redirection issues are different if target URLs differ if existingIssue.getIssueDetail() == newIssue.getIssueDetail(): return -1 else: return 0 else: # In all other cases: keep existing issue return -1 return 0
class WorkHelper(JFrame): def __init__(self): super(WorkHelper, self).__init__() self.clipboard = Toolkit.getDefaultToolkit().getSystemClipboard() ############################################################# # Layout: layout = GroupLayout(self.getContentPane()) self.getContentPane().setLayout(layout) layout.setAutoCreateGaps(True) layout.setAutoCreateContainerGaps(True) ############################################################# ############################################################# # Frame Area: Larea1 = JLabel("InputArea:") Sarea1 = JScrollPane() self.area1 = JTextArea() self.area1.setToolTipText("Input Area") self.area1.setEditable(True) self.area1.setBorder(BorderFactory.createLineBorder(Color.gray)) Sarea1.setPreferredSize(Dimension(300,100)) Sarea1.getViewport().setView((self.area1)) bClear = JButton("Clear", actionPerformed=self.bClear) bClear.setToolTipText("Clears the text form both Input and Output text Areas") bCopyToInput = JButton("Copy to Input", actionPerformed=self.bCopyToInput) bCopyToInput.setToolTipText("Copy the text from the Output Area to the Input Area for further Operations") self.cCtClipB = JCheckBox("Auto-Copy"); self.cCtClipB.setToolTipText("When 'Checked' after the Categories are created they will added to the clipboard") self.cCtClipB.setSelected(1) Larea2 = JLabel("OutputArea:") Sarea2 = JScrollPane() self.area2 = JTextArea() self.area2.setToolTipText("Output Area") self.area2.setEditable(False) self.area2.setBorder(BorderFactory.createLineBorder(Color.gray)) Sarea2.setPreferredSize(Dimension(300,100)) Sarea2.getViewport().setView((self.area2)) ############################################################# # Tabbed Area: tabPane = JTabbedPane(JTabbedPane.TOP) self.getContentPane().add(tabPane) ##################################################### # Text Edit pane panel_TEdit = JPanel() layout2 = GroupLayout(panel_TEdit) layout2.setAutoCreateGaps(True) layout2.setAutoCreateContainerGaps(True) panel_TEdit.setLayout(layout2) bRemoveNBSP_L = JButton("Clean LText", actionPerformed=self.bRemoveNBSP_L) bRemoveNBSP_L.setToolTipText("Removes Spaces, Tabs from the start of every text line from the input Area") bRemoveNBSP_R = JButton("Clean RText", actionPerformed=self.bRemoveNBSP_R) bRemoveNBSP_R.setToolTipText("Removes Spaces, Tabs from the end of every text line from the input Area") self.ReplaceThis = JTextField() self.ReplaceThis = JTextField(maximumSize=Dimension(120,25)) self.ReplaceThis.setToolTipText("Text to be replaced") self.ReplaceThat = JTextField() self.ReplaceThat = JTextField(maximumSize=Dimension(120,25)) self.ReplaceThat.setToolTipText("Text to be placed") bSandReplace = JButton("Replace Text", actionPerformed=self.bSandReplace) bSandReplace.setToolTipText("Replace the text from This with Text from That in the Text from the Input Area and displays it in the Output Area") bRemNumbers = JButton("Rem Numbers", actionPerformed=self.RemNumbers) bRemNumbers.setToolTipText("Removes numbers from the start of every line") ##################################################### # Dimension pane panel_Dimensions = JPanel() layout3 = GroupLayout(panel_Dimensions) layout3.setAutoCreateGaps(True) layout3.setAutoCreateContainerGaps(True) panel_Dimensions.setLayout(layout3) self.cCurly = JCheckBox("Curly"); self.cCurly.setToolTipText("When 'Checked' Curly Brackets will surround the Categories") self.cCurly.setSelected(1) self.cSemiC = JCheckBox("SemiColumn"); self.cSemiC.setToolTipText("When 'Checked' after the Categories are created at the end will be a semicolomn") self.cSemiC.setSelected(1) self.iStart = JTextField(maximumSize=Dimension(40,25)) self.iStart.setToolTipText("The Start Index for the Making of the Categories") self.RThis = JTextField() self.RThis = JTextField(maximumSize=Dimension(120,25)) self.RThis.setToolTipText("The Starting Index used in creating the Categorical") self.RThat = JTextField() self.RThat = JTextField(maximumSize=Dimension(120,25)) self.RThat.setToolTipText("The Finish Index used in creating the Categorical") optioncCategories = JLabel("Options:") bcCat = JButton("CreatCateg", actionPerformed=self.bcCat) bcCat.setToolTipText("Create a categorical form starting C_Index to finish C_Index; Use the text boxes to define the indexes") bM_Categories = JButton("Categories", actionPerformed=self.mCategories) bM_Categories.setToolTipText("Make Categories using the lines from the Input Area. Use it to define Categorical questions.") ##################################################### # ConfirmIt pane panel_ConfirmIt = JPanel() layout4 = GroupLayout(panel_ConfirmIt) layout4.setAutoCreateGaps(True) layout4.setAutoCreateContainerGaps(True) panel_ConfirmIt.setLayout(layout4) self.PID = JTextField() self.PID = JTextField(maximumSize=Dimension(120,25)) self.PID.setToolTipText("The PID number used for creating links with PID and ids from every line of the Input Area") bClinks = JButton("Create Links", actionPerformed=self.bClinks) bClinks.setToolTipText("Create links for a project using PID and ID, ID`s are read from every line of the Input Area") bClinksNA = JButton("Create Links NA ", actionPerformed=self.bClinksNA) bClinksNA.setToolTipText("Create links for a project using PID and ID`s from the standard sample test for US") bClinksCA = JButton("Create Links CA", actionPerformed=self.bClinksCA) bClinksCA.setToolTipText("Create links for a project using PID and ID`s from the standard sample test for CA") self.Width = JTextField() self.Width = JTextField(maximumSize=Dimension(120,25)) self.Width.setToolTipText("The Width used in creating the DIV html tag, note the dimension used is in px") baddDIVt = JButton("Add DIV tag", actionPerformed=self.baddDIVt) baddDIVt.setToolTipText("Create a DIV tag for every line in the Input Area") ##################################################### # Statistics pane panel_Statistics = JPanel() layout5 = GroupLayout(panel_Statistics) layout5.setAutoCreateGaps(True) layout5.setAutoCreateContainerGaps(True) panel_Statistics.setLayout(layout5) ##################################################### # TimeTraking pane panel_TimeTraking = JPanel() layout6 = GroupLayout(panel_TimeTraking) layout6.setAutoCreateGaps(True) layout6.setAutoCreateContainerGaps(True) panel_TimeTraking.setLayout(layout6) ##################################################### # Tabbed Area Tabs tabPane.addTab("Text Edit", panel_TEdit) tabPane.addTab("Dimensions", panel_Dimensions) tabPane.addTab("ConfirmIt", panel_ConfirmIt) tabPane.addTab("Statistics", panel_Statistics) tabPane.addTab("TimeTraking", panel_TimeTraking) ############################################################# ############################################################# # Aplication Layouts: 2 groups one Horizontal and one Vertical ############################################################# # Frame Layout: 2 groups one Horizontal and one Vertical layout.setHorizontalGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addComponent(Larea1) .addComponent(Sarea1) .addComponent(Sarea2) .addGroup(layout.createSequentialGroup() .addComponent(bCopyToInput) .addComponent(bClear) .addComponent(self.cCtClipB)) .addComponent(Larea2)) .addGroup(layout.createParallelGroup() .addComponent(tabPane)) ) layout.setVerticalGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup() .addGroup(layout.createSequentialGroup() .addComponent(Larea1) .addComponent(Sarea1) .addGroup(layout.createParallelGroup() .addComponent(bCopyToInput) .addComponent(bClear) .addComponent(self.cCtClipB) ) .addComponent(Larea2) .addComponent(Sarea2)) .addGroup(layout.createSequentialGroup() .addComponent(tabPane)) ) ) ############################################################# # TEdit Layout: 2 groups one Horizontal and one Vertical layout2.setHorizontalGroup(layout2.createSequentialGroup() .addGroup(layout2.createParallelGroup() .addGroup(layout2.createSequentialGroup() .addComponent(bRemNumbers) .addComponent(bRemoveNBSP_L) .addComponent(bRemoveNBSP_R)) .addGroup(layout2.createSequentialGroup() .addComponent(bSandReplace) .addComponent(self.ReplaceThis) .addComponent(self.ReplaceThat)) )) layout2.setVerticalGroup(layout2.createSequentialGroup() .addGroup(layout2.createParallelGroup() .addComponent(bRemNumbers) .addComponent(bRemoveNBSP_L) .addComponent(bRemoveNBSP_R)) .addGroup(layout2.createParallelGroup() .addComponent(bSandReplace) .addComponent(self.ReplaceThis) .addComponent(self.ReplaceThat)) ) ############################################################# # Dimensions Layout: 2 groups one Horizontal and one Vertical layout3.setHorizontalGroup(layout3.createSequentialGroup() .addGroup(layout3.createParallelGroup() .addGroup(layout3.createSequentialGroup() .addComponent(bM_Categories) .addComponent(self.iStart)) .addGroup(layout3.createSequentialGroup() .addComponent(optioncCategories) .addComponent(self.cCurly) .addComponent(self.cSemiC) ) .addGroup(layout3.createSequentialGroup() .addComponent(bcCat) .addComponent(self.RThis) .addComponent(self.RThat)) .addGroup(layout3.createSequentialGroup() ) ) ) layout3.setVerticalGroup(layout3.createSequentialGroup() .addGroup(layout3.createSequentialGroup() .addGroup(layout3.createParallelGroup() .addComponent(bM_Categories) .addComponent(self.iStart)) .addGroup(layout3.createParallelGroup() .addComponent(bcCat) .addComponent(self.RThis) .addComponent(self.RThat)) .addGroup(layout3.createParallelGroup() .addGroup(layout3.createParallelGroup() .addComponent(optioncCategories) .addComponent(self.cCurly) .addComponent(self.cSemiC) ) ) ) ) ############################################################# # ConfimIT Layout: 2 groups one Horizontal and one Vertical layout4.setHorizontalGroup(layout4.createSequentialGroup() .addGroup(layout4.createParallelGroup() .addGroup(layout4.createSequentialGroup() .addComponent(bClinks) .addComponent(self.PID) ) .addGroup(layout4.createSequentialGroup() .addComponent(bClinksNA) .addComponent(bClinksCA) ) .addGroup(layout4.createSequentialGroup() .addComponent(baddDIVt) .addComponent(self.Width) ) )) layout4.setVerticalGroup(layout4.createSequentialGroup() .addGroup(layout4.createSequentialGroup() .addGroup(layout4.createParallelGroup() .addComponent(bClinks) .addComponent(self.PID)) .addGroup(layout4.createParallelGroup() .addComponent(bClinksNA) .addComponent(bClinksCA) ) .addGroup(layout4.createParallelGroup() .addComponent(baddDIVt) .addComponent(self.Width) ) )) #layout2.linkSize(SwingConstants.HORIZONTAL, [self.cCurly,bM_Categories]) #layout.linkSize(SwingConstants.HORIZONTAL, [ok, bCopyToInput, close, bM_Categories]) #layout3.linkSize(SwingConstants.HORIZONTAL, [self.RThis,self.RThat,bRemoveNBSP_L,bRemoveNBSP_R,bM_Categories,bSandReplace,bcCat]) ############################################################# ############################################################# # Aplication Settings self.pack() #self.setPreferredSize(Dimension(1000, 1000)) self.setTitle("Workhelper") self.setSize(800, 500) self.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE) self.setLocationRelativeTo(None) self.setVisible(True) ############################################################# ############################################################# # WorkHelper class methods: def onQuit(self, e): "@sig public void setExpression(java.lang.String e)" os.system.exit(0) # def addToClipBoard(self, text): # "@sig public void setExpression(java.lang.String text)" # command = 'echo ' + text.strip() + '| clip' # os.system(command) # brute method for pasting into clipboard on windows def mCategories(self, e): "@sig public void setExpression(java.lang.String e)" """ Takes every line of text form the Input Area and by using a string composition it creates the output in the SPSS dimension categories format. """ try: StartIndex = int(self.iStart.getText()) except ValueError: StartIndex=1 text=self.area1.getText().rstrip() counter=StartIndex lastindex=0 textO="" for i in range(0,len(text)): if text[i]=='\n': textO=textO+("_"+str(counter)+' "'+text[lastindex:i]+'",\n') lastindex=i+1 counter=counter+1 if len(text[lastindex:len(text)])>0: textO=textO+("_"+str(counter)+' "'+text[lastindex:len(text)]+'"') if len(textO)>0: if self.cCurly.isSelected(): textO = "{\n"+ textO + "\n}" if self.cSemiC.isSelected(): textO = textO + ";" self.copyToClipboard(textO) self.area2.setText(textO) def copyToClipboard(self, text): if self.cCtClipB.isSelected(): stringSelection = StringSelection(text) self.clipboard.setContents(stringSelection, None) def bCopyToInput(self, e): "@sig public void setExpression(java.lang.String e)" """Copy the Text from the Output Area to the input Area for further operations""" self.area1.setText(self.area2.getText()) def bRemoveNBSP_L(self, e): "@sig public void setExpression(java.lang.String e)" text=self.area1.getText().rstrip() textO="" lastindex=0 for i in range(0,len(text)): if text[i] == '\n': textO = textO+text[lastindex:i].lstrip()+"\n" lastindex=i+1 #print(text[0:i].lstrip()+'\n') if len(text[lastindex:len(text)])>0: textO=textO+text[lastindex:len(text)].lstrip() self.area2.setText(textO) def bRemoveNBSP_R(self, e): "@sig public void setExpression(java.lang.String e)" text=self.area1.getText().rstrip() textO="" lastindex=0 for i in range(0,len(text)): if text[i] == '\n': textO = textO+text[lastindex:i].rstrip()+"\n" lastindex=i+1 #print(text[0:i].lstrip()+'\n') if len(text[lastindex:len(text)])>0: textO=textO+text[lastindex:len(text)].rstrip() self.area2.setText(textO) def bClear(self, e): "@sig public void setExpression(java.lang.String e)" self.area1.setText("") self.area2.setText("") def bcCat(self, e): "@sig public void setExpression(java.lang.String e)" try: StartIndex = int(self.RThis.getText()) except ValueError: StartIndex=1 try: FinishIndex = int(self.RThat.getText()) except ValueError: FinishIndex=1 cCats="" for i in range(StartIndex,FinishIndex+1): if i<>FinishIndex: cCats=cCats+"_"+str(i)+"," else: cCats=cCats+"_"+str(i) if StartIndex<FinishIndex: cCats="{"+cCats+"}" self.copyToClipboard(cCats) self.area2.setText(cCats) def bSandReplace(self, e): self.area2.setText(self.area1.getText().replace(self.ReplaceThis.getText(),self.ReplaceThat.getText())) self.copyToClipboard(self.area2.getText()) ############################################################# # Confirmit def bClinks(self, e): text=self.area1.getText().rstrip() lastindex=0 textO="" for i in range(0,len(text)): if text[i]=='\n': textO=textO+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+text[lastindex:i]+'\n' lastindex=i+1 if len(text[lastindex:len(text)])>0: textO=textO+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+text[lastindex:len(text)] self.copyToClipboard(textO) self.area2.setText(textO) def bClinksNA(self, e): output="" for i in range (1,201): if i<10: output=output+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+'US9900'+str(i)+'\n' else: if i<100: output=output+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+'US990'+str(i)+'\n' else: if i==200: output=output+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+'US99'+str(i) else: output=output+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+'US99'+str(i)+'\n' self.area2.setText(output) self.copyToClipboard(self.area2.getText()) def bClinksCA(self, e): output="" for i in range (1,201): if i<10: output=output+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+'CA9900'+str(i)+'\n' else: if i<100: output=output+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+'CA990'+str(i)+'\n' else: if i==200: output=output+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+'CA99'+str(i) else: output=output+'http://surveys.ipsosinteractive.com/surveys2/?pid='+self.PID.getText()+'&id='+'CA99'+str(i)+'\n' self.area2.setText(output) self.copyToClipboard(self.area2.getText()) def baddDIVt(self, e): try: Width = int(self.Width.getText()) except ValueError: Width=1 text=self.area1.getText().rstrip() lastindex=0 textO="" for i in range(0,len(text)): if text[i]=='\n': textO=textO+'<div style="width:'+str(Width)+'px">'+text[lastindex:i]+'</div>'+'\n' lastindex=i+1 if len(text[lastindex:len(text)])>0: textO=textO+'<div style="width:'+str(Width)+'px">'+text[lastindex:len(text)]+'</div>' self.copyToClipboard(textO) self.area2.setText(textO) def RemNumbers(self, e): text=self.area1.getText().rstrip() lastindex=0 textO="" for i in range(0,len(text)): if text[i]=='\n': textO=textO+text[lastindex:i].lstrip('1234567890')+'\n' lastindex=i+1 if len(text[lastindex:len(text)])>0: textO=textO+text[lastindex:len(text)].lstrip('1234567890') self.copyToClipboard(textO) self.area2.setText(textO)