├── chrome.manifest ├── content ├── AttackHttpResponseObserver.js ├── AttackRunner.js ├── ErrorStringContainer.js ├── FieldResult.js ├── PrefObserver.js ├── Results.js ├── ResultsManager.js ├── StreamListener.js ├── TestManager.js ├── TestRunnerContainer.js ├── about.xul ├── addAttack.js ├── addAttack.xul ├── addError.js ├── addError.xul ├── attackStringContainer.js ├── htmlStringEncoder.js ├── io.js ├── json.js ├── overlay.js ├── overlay.xul ├── preferenceStringContainer.js ├── preferences.fx2.js ├── preferences.fx3.js ├── preferences.xul ├── progressListener.js ├── results.html ├── sidebarBuilder.js ├── sqlime.js ├── sqlime_sidebar.js ├── sqlime_sidebar.xul ├── sqlimeevaluators.js ├── tabbrowsermanager.js ├── util.js ├── whiletestruns.js └── whiletestruns.xul ├── defaults └── preferences │ └── sqlime.js ├── gpl-3.0.txt ├── install.rdf ├── locale └── en-US │ ├── overlay.dtd │ ├── prefwindow.dtd │ ├── sqlime.dtd │ └── sqlime.properties ├── readme.txt ├── skin ├── logo_sc.png ├── overlay.css ├── preferences.css ├── results.css ├── small_logo_sc.png ├── sqlime_sidebar.css ├── tiny_logo.png ├── toolbar-button.png └── whiletestruns.css └── update.rdf /chrome.manifest: -------------------------------------------------------------------------------- 1 | content sqlime content/ 2 | locale sqlime en-US locale/en-US/ 3 | skin sqlime classic/1.0 skin/ 4 | overlay chrome://browser/content/browser.xul chrome://sqlime/content/overlay.xul 5 | style chrome://global/content/customizeToolbar.xul chrome://sqlime/skin/overlay.css 6 | # Firefox 2 & Firefox 3 differences 7 | override chrome://sqlime/content/preferences.js chrome://sqlime/content/preferences.fx2.js appversion<3.0 8 | override chrome://sqlime/content/preferences.js chrome://sqlime/content/preferences.fx3.js appversion>=3.0 -------------------------------------------------------------------------------- /content/AttackHttpResponseObserver.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * AttackHttpResponseObserver.js 25 | */ 26 | const AttackHttpResponseObserver_topic = 'http-on-examine-response'; 27 | 28 | function AttackHttpResponseObserver(attackRunner, resultsManager){ 29 | 30 | this.attackRunner = attackRunner; 31 | this.resultsManager = resultsManager; 32 | 33 | } 34 | 35 | AttackHttpResponseObserver.prototype = { 36 | className: 'AttackHttpResponseObserver' 37 | , 38 | QueryInterface: function(iid) { 39 | if (iid.equals(Components.interfaces.nsIObserver) || 40 | iid.equals(Components.interfaces.nsISupports)) 41 | { 42 | return this; 43 | } 44 | 45 | throw Components.results.NS_ERROR_NO_INTERFACE; 46 | }, 47 | 48 | observe: function(subject, topic, data) { 49 | 50 | if (topic == AttackHttpResponseObserver_topic){ 51 | try { 52 | var channel = subject. 53 | QueryInterface(Components.interfaces.nsIHttpChannel) 54 | if (channel.responseStatus < 300 || 55 | channel.responseStatus >= 400) 56 | { 57 | this.resultsManager.gotChannelForAttackRunner(channel, 58 | this); 59 | } 60 | } 61 | catch(err) { 62 | dump('AttackHttpResponseObserver::observe: ' + err + '\n'); 63 | for(var k in err) 64 | dump('AttackHttpResponseObserver::observe: err['+k+'] ==' + err[k] + '\n') 65 | } 66 | } 67 | 68 | } 69 | 70 | }; -------------------------------------------------------------------------------- /content/AttackRunner.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * AttackRunner.js 25 | * @requires ResultsManager 26 | * @requires TabManager 27 | * @requires AttackHttpResponseObserver 28 | */ 29 | 30 | /** 31 | * @class AttackRunner 32 | */ 33 | function AttackRunner(){ 34 | 35 | this.className = "AttackRunner"; 36 | 37 | /** 38 | * uniqueID is important for heuristic tests which need a random string in 39 | * order to find the char they sent 40 | */ 41 | this.uniqueID = Math.floor(Date.now() * Math.random()); 42 | 43 | this.tabWrapper = null; 44 | 45 | this.resultsWrappers = new Array(); 46 | 47 | } 48 | 49 | AttackRunner.prototype = { 50 | testData: null 51 | , 52 | submitForm: function(browser, formIndex){ 53 | var forms = browser.webNavigation.document.forms; 54 | var formFound = false; 55 | for (var i = 0; i < forms.length && !formFound; i++){ 56 | if (i == formIndex){ 57 | dump('submitting form ... ' + i + ' ' + (i == formIndex) + '\n'); 58 | if (forms[i].target) forms[i].target = null; 59 | forms[i].submit(); 60 | formFound = true; 61 | } 62 | //debug code.. 63 | else { 64 | dump('this form is not it... ' + i + ' ' + (i == formIndex) + '\n'); 65 | } 66 | } 67 | return formFound; 68 | } 69 | , 70 | /** 71 | * Begin an individual test. 72 | * @param formPanel currently unused 73 | * @param formIndex index, in the list of forms, of the one being tested 74 | * @param field the field to inject 75 | * @param testValue the input containing the injection 76 | * @param resultsManager evaluates the results of the test 77 | * @param tabWrapper contains the tab to run the test in 78 | * @param tabManager provides information about the target page 79 | */ 80 | do_test: function(formPanel, formIndex, field, testData, resultsManager, 81 | tabWrapper, tabManager) 82 | { 83 | var wroteTabData = false; 84 | var self = this; 85 | var formData = null; 86 | 87 | this.formIndex = formIndex; 88 | this.fieldIndex = field.index; 89 | this.field = field; 90 | this.tabWrapper = tabWrapper 91 | 92 | 93 | if (field) { 94 | formData = tabManager.getFormDataForURL(formIndex, field.index, 95 | testData.string); 96 | } 97 | else { 98 | formData = tabManager.getFormDataForURL(formIndex, null, testData.string); 99 | } 100 | this.testData = tabManager.getTabData(formIndex, field.index, testData.string); 101 | dump('\ndoing source test...'); 102 | this.do_source_test(formIndex, formIndex, field, testData, 103 | resultsManager, formData, tabManager); 104 | 105 | } 106 | , 107 | do_source_test:function(formPanel, formIndex, field, testData, 108 | resultsManager, formData, tabManager) { 109 | var streamListener = new StreamListener(this, resultsManager); 110 | resultsManager.addSourceListener(streamListener); 111 | 112 | // the IO service 113 | var ioService = Components.classes['@mozilla.org/network/io-service;1'] 114 | .getService(Components.interfaces.nsIIOService); 115 | 116 | 117 | var form = tabManager.tabForms[formIndex]; 118 | var formAction = form.action; 119 | var formURL = (form.action.indexOf("?") == -1) ? formAction : formAction.split("?")[0]; 120 | 121 | dump('AttackRunner::do_source_test formAction=== '+formAction+'\n'); 122 | if (form.method.toLowerCase() != 'post'){ 123 | formAction += formAction.indexOf('?') === -1 ? '?' : '&'; 124 | formAction += formData; 125 | formURL = formAction; 126 | } 127 | 128 | dump('attackrunner::do_source_test::formAction == ' + formAction + '\n'); 129 | dump('attackrunner::do_source_test::formData == ' + formData + '\n'); 130 | 131 | var uri = ioService.newURI(formURL, null, null); 132 | Components.utils.reportError("got a " + uri.toString() + " from a " + formURL) 133 | 134 | this.channel = ioService.newChannelFromURI(uri); 135 | 136 | 137 | if (form.method.toLowerCase() == 'post'){ 138 | var inputStream = Components. 139 | classes['@mozilla.org/io/string-input-stream;1']. 140 | createInstance(Components.interfaces.nsIStringInputStream); 141 | inputStream.setData(formData, formData.length); 142 | this.channel.QueryInterface(Components.interfaces.nsIUploadChannel). 143 | setUploadStream(inputStream, 144 | 'application/x-www-form-urlencoded', -1); 145 | this.channel.QueryInterface(Components.interfaces.nsIHttpChannel). 146 | requestMethod = 'POST'; 147 | } 148 | 149 | streamListener.testData = this.testData; 150 | this.channel.asyncOpen(streamListener, null); 151 | resultsManager.extensionManager.finishedTest(); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /content/ErrorStringContainer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * ErrorStringContainer.js 25 | * @requires PreferenceStringContainer.js 26 | */ 27 | function ErrorStringContainer(){ 28 | this.init(); 29 | } 30 | ErrorStringContainer.prototype = new PreferenceStringContainer(); 31 | dump('creating... ErrorStringContainer object\n'); 32 | ErrorStringContainer.prototype.init = function (){ 33 | 34 | var attackStrings; 35 | 36 | this.prefBranch = this.prefService.getBranch('extensions.sqlime.'); 37 | attackStrings = this.prefBranch.getCharPref('errorstrings'); 38 | this.strings = sqlime.JSON.fromString(attackStrings); 39 | }; 40 | 41 | ErrorStringContainer.prototype.save = function() { 42 | dump('ErrorStringContainer::save this.strings ' +this.strings + '\n'); 43 | dump('ErrorStringContainer::save typeof(this.strings) ' +typeof( this.strings )+ '\n'); 44 | this.prefBranch.setCharPref('errorstrings', sqlime.JSON.toString(this.strings)); 45 | } 46 | 47 | 48 | function getErrorStringContainer(){ 49 | 50 | if (typeof(errorStringContainer) === 'undefined' || !errorStringContainer) { 51 | errorStringContainer = new ErrorStringContainer(); 52 | } 53 | 54 | return errorStringContainer; 55 | } 56 | -------------------------------------------------------------------------------- /content/FieldResult.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * FieldResult.js 25 | * A FieldResult represents the resulting "value" of a form's field after all 26 | * testing has been performed. 27 | * It holds all the results generated for a field. 28 | * This object is used for sorting. 29 | * @requires result.js 30 | */ 31 | function FieldResult(formIndex, fieldIndex){ 32 | this.fieldIndex = fieldIndex; 33 | this.formIndex = formIndex; 34 | this.results = new Array(); 35 | this.maxValue = 0; 36 | this.maxValueType = 0; 37 | this.state = 0; 38 | } 39 | 40 | /** 41 | * These consts are used to check what kind of rsults does this fieldresult 42 | * have. 43 | */ 44 | const fieldresult_has_pass = 0x0001; 45 | const fieldresult_has_warn = 0x0002; 46 | const fieldresult_has_error = 0x0004; 47 | 48 | FieldResult.prototype = { 49 | addResults: function (resultsToAdd) { 50 | 51 | for each(var result in resultsToAdd) { 52 | if (this.maxValueType < result.type){ 53 | this.maxValue = result.value; 54 | this.maxValueType = result.type; 55 | } 56 | else if (this.maxValueType === result.type ) { 57 | if (this.maxValue < result.value) { 58 | this.maxValue = result.value; 59 | } 60 | } 61 | this.state = this.state | result.type; 62 | this.results.push(result); 63 | } 64 | } 65 | , 66 | getLength: function(){ 67 | var numTestsRun = 0; 68 | var numPasses = 0; 69 | var numWarnings = 0; 70 | var numFailes = 0; 71 | for each(var r in this.results) { 72 | numTestsRun++; 73 | switch(r.type){ 74 | case RESULT_TYPE_ERROR: 75 | numFailes++; 76 | break; 77 | case RESULT_TYPE_WARNING: 78 | numWarnings++; 79 | break; 80 | case RESULT_TYPE_PASS: 81 | numPasses++; 82 | break; 83 | } 84 | } 85 | return [numTestsRun, numFailes, numWarnings, numPasses]; 86 | } 87 | , 88 | getSubmitState: function(){ 89 | return this.results[0].testData; 90 | } 91 | , 92 | sort: function(){ 93 | var errors = new Array(); 94 | var warnings = new Array(); 95 | var passes = new Array(); 96 | 97 | for each(var result in this.results) { 98 | switch(result.type){ 99 | case RESULT_TYPE_ERROR: 100 | errors.push(result); 101 | break; 102 | case RESULT_TYPE_WARNING: 103 | warnings.push(result); 104 | break; 105 | case RESULT_TYPE_PASS: 106 | passes.push(result); 107 | break; 108 | } 109 | } 110 | 111 | return this.results = errors.concat(warnings, passes); 112 | } 113 | } -------------------------------------------------------------------------------- /content/PrefObserver.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * PrefObserver.js 25 | * This provides a class that can be used to watch arbitrary preferences and do 26 | * artibrary things based on them. 27 | * This assumes will act on all preferences being watched (that is all children 28 | * of this preference as well as the preference itself). 29 | */ 30 | 31 | function Xss_PrefObserver(functionToCall){ 32 | this.funcToCall = functionToCall; 33 | 34 | } 35 | 36 | Xss_PrefObserver.prototype = { 37 | observe: function(subject, topic, data) { 38 | dump('Xss_PrefObserver::Observe topic == ' + topic + '\n'); 39 | if (topic == "nsPref:changed") { 40 | this.funcToCall(subject, topic, data); 41 | } 42 | } 43 | , 44 | QueryInterface : function(aIID) { 45 | if (aIID.equals(Components.interfaces.nsIObserver)) { 46 | return this; 47 | } 48 | 49 | throw Components.results.NS_NOINTERFACE; 50 | } 51 | }; -------------------------------------------------------------------------------- /content/Results.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * Result.js 25 | */ 26 | 27 | const RESULT_TYPE_ERROR = 0x0004; 28 | const RESULT_TYPE_WARNING =0x0002; 29 | const RESULT_TYPE_PASS = 0x0001; 30 | 31 | /** 32 | * The Result object is returned by evalutors. 33 | * The type defines whether the test resulted in an error, warning, or pass. 34 | * The value is used for sorting errors, warnings, and passes (usually doesn't 35 | * matter for passes) 36 | * The message is what is to be displayed to the user. 37 | */ 38 | function Result(type, value, message){ 39 | this.value = value; 40 | this.type = type; 41 | this.message = message; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /content/StreamListener.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * StreamListener 25 | */ 26 | function StreamListener(attackRunner, resultsManager) { 27 | this.attackRunner = attackRunner; 28 | this.resultsManager = resultsManager; 29 | this.done = false; 30 | this.data = ""; 31 | } 32 | 33 | StreamListener.prototype = { 34 | // nsIStreamListener 35 | onStartRequest: function (aRequest, aContext) { 36 | //do nothing... 37 | } 38 | , 39 | onDataAvailable: function (aRequest, aContext, aStream, aSourceOffset, aLength) { 40 | var scriptableInputStream = 41 | Components.classes["@mozilla.org/scriptableinputstream;1"] 42 | .createInstance(Components.interfaces.nsIScriptableInputStream); 43 | scriptableInputStream.init(aStream); 44 | 45 | this.data += scriptableInputStream.read(aLength); 46 | } 47 | , 48 | onStopRequest: function (aRequest, aContext, aStatus) { 49 | if (this.done === false) { 50 | this.done = true; 51 | 52 | dump('\n---- Here is the raw source of the result:----\n') 53 | dump(this.data); 54 | dump('\n--- end of raw source ---'); 55 | 56 | this.resultsManager.evaluateSource(this); 57 | } 58 | } 59 | , 60 | // nsIChannelEventSink 61 | onChannelRedirect: function (aOldChannel, aNewChannel, aFlags) { 62 | }, 63 | // nsIInterfaceRequestor 64 | getInterface: function (aIID) { 65 | try { 66 | return this.QueryInterface(aIID); 67 | } catch (e) { 68 | throw Components.results.NS_NOINTERFACE; 69 | } 70 | } 71 | , 72 | // nsIProgressEventSink (not implementing will cause annoying exceptions) 73 | onProgress : function (aRequest, aContext, aProgress, aProgressMax) { 74 | } 75 | , 76 | onStatus : function (aRequest, aContext, aStatus, aStatusArg) { 77 | } 78 | , 79 | // nsIHttpEventSink (not implementing will cause annoying exceptions) 80 | onRedirect : function (aOldChannel, aNewChannel) { 81 | } 82 | , 83 | // we are faking an XPCOM interface, so we need to implement QI 84 | QueryInterface : function(aIID) { 85 | if (aIID.equals(Components.interfaces.nsISupports) || 86 | aIID.equals(Components.interfaces.nsIInterfaceRequestor) || 87 | aIID.equals(Components.interfaces.nsIChannelEventSink) || 88 | aIID.equals(Components.interfaces.nsIProgressEventSink) || 89 | aIID.equals(Components.interfaces.nsIHttpEventSink) || 90 | aIID.equals(Components.interfaces.nsIStreamListener)) 91 | { 92 | return this; 93 | } 94 | 95 | throw Components.results.NS_NOINTERFACE; 96 | } 97 | }; 98 | -------------------------------------------------------------------------------- /content/TestManager.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2008 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * TestManager 25 | * The TestManager is responsible for making sure that tests are run properly. 26 | * It does not actually run the tests, just preps them. The TestRunnerContainer 27 | * is responsible for running the tests. 28 | */ 29 | 30 | /** 31 | * TestManager ctor 32 | */ 33 | function TestManager(){ 34 | 35 | /** 36 | * an array of vulnerable fields, used in heuristic testing 37 | */ 38 | this.vulnerableFields = new Array(); 39 | this.controller = null; 40 | this.resultsManager = null; 41 | this.waitingForHeuristicTests = false; 42 | this.testType = null; 43 | this.resultsStillExpected = 0; 44 | 45 | } 46 | 47 | TestManager.prototype = { 48 | /** 49 | * Runs a test on the passed fields. 50 | * @param testType whether to test with all the strings or just with the top strings 51 | * @param fieldsToTest the fields to test with this battery 52 | * @param tabManager information about the target page 53 | */ 54 | runTest: function (testType, fieldsToTest, tabManager) { 55 | 56 | this.testType = testType; 57 | 58 | this.clear(); 59 | 60 | this.fieldsToTest = fieldsToTest; 61 | 62 | this.tabManager = tabManager; 63 | 64 | this.runThoroughTest(testType, fieldsToTest); 65 | } 66 | , 67 | /** 68 | * This is a function that AttackRunner requires its resultsmanager to have 69 | */ 70 | addSourceListener: function(sourceListener, attackRunner) { 71 | 72 | } 73 | , 74 | /** 75 | * called by testRunners to report their results 76 | * @param browser a browser instance with the results 77 | * @param 78 | */ 79 | evaluate: function(browser, attackRunner) { 80 | 81 | } 82 | , 83 | /** 84 | * called by a streamlistener to report the results of a source test 85 | * @param streamListener the streamListener that is reporting the results 86 | */ 87 | evaluateSource: function(streamListener) { 88 | 89 | var resultData = streamListener.data; 90 | var testData = streamListener.attackRunner.testData; 91 | 92 | if (resultData.indexOf(testData.string) !== -1) { 93 | var vulnerableField = streamListener.attackRunner.field; 94 | var isVulnerablFieldAlreadyLogged = false; 95 | if (this.vulnerableFields.length > 0) { 96 | for each (var value in this.vulnerableFields) { 97 | var areFormIndexsSame = value.formIndex === vulnerableField.formIndex; 98 | if (areFormIndexsSame) { 99 | var areFieldsSame = value.index === vulnerableField.index; 100 | if (areFieldsSame) { 101 | value.vulnerableChars += testData.string[testData.string.length-1]; 102 | isVulnerablFieldAlreadyLogged = true; 103 | break; 104 | } 105 | } 106 | } 107 | } 108 | 109 | if (isVulnerablFieldAlreadyLogged === false) { 110 | streamListener.attackRunner.field.vulnerableChars = testData.string[testData.string.length-1]; 111 | this.vulnerableFields.push(streamListener.attackRunner.field); 112 | } 113 | 114 | } 115 | 116 | this.resultsStillExpected--; 117 | } 118 | , 119 | /** 120 | * runs non-heuristic tests on the fields. 121 | * @param testType with all strings or just the top strings. 122 | */ 123 | runThoroughTest: function(testType, vulnerableFields) { 124 | 125 | this.resultsManager = new ResultsManager(this.controller); 126 | 127 | this.resultsManager.addSourceEvaluator(checkSrcForErrorString); 128 | this.resultsManager.addSourceEvaluator(checkForServerResponseCode); 129 | 130 | getTestRunnerContainer().clear(); 131 | var testStrings = getAttackStringContainer().getStrings(); 132 | var numberOfTests; 133 | if (testType.allTests) 134 | numberOfTests = testStrings.length; 135 | else { 136 | numberOfTests = this.controller.getPreferredNumberOfAttacks(); 137 | } 138 | 139 | for each (var field in vulnerableFields) { 140 | 141 | for (var n = 0; n < numberOfTests && testStrings[n]; n++) { 142 | 143 | var testRunner = new AttackRunner(); 144 | this.resultsManager.registerAttack(testRunner); 145 | 146 | getTestRunnerContainer().addTestRunner(testRunner, null, 147 | field.formIndex, field, testStrings[n], 148 | this.resultsManager); 149 | 150 | } 151 | 152 | } 153 | 154 | var self = this; 155 | 156 | var testRunnerContainer = getTestRunnerContainer(self); 157 | 158 | if (testRunnerContainer.keepChecking === false) { 159 | testRunnerContainer.keepChecking = true; 160 | } 161 | testRunnerContainer.start(this.tabManager); 162 | 163 | } 164 | , 165 | /** 166 | * this is called by the testRunnerContainer when all tests are definitely 167 | * complete. 168 | */ 169 | doneTesting: function() { 170 | var self = this; 171 | function checkAgain() { 172 | self.doneTesting(); 173 | } 174 | if (this.controller) { 175 | if (this.resultsManager.allResultsLogged === false){ 176 | dump('\nnot done yet...'); 177 | window.setTimeout(checkAgain, 100); 178 | //Components.utils.reportError('results not all logged yet'); 179 | return 180 | } 181 | dump('\ndone now.') 182 | getTestRunnerContainer().clearWorkTabs(); 183 | this.controller.generatingReport(); 184 | this.resultsManager.showResults(this); 185 | 186 | } 187 | 188 | } 189 | , 190 | /** 191 | * postReport is called after the report is generated 192 | */ 193 | postReport: function() { 194 | this.controller.postTest(); 195 | } 196 | , 197 | /** 198 | * clears the object and makes it ready for use for a new set of tests. 199 | */ 200 | clear: function() { 201 | this.resultsManager = null; 202 | 203 | this.vulnerableFields.splice(0,this.vulnerableFields.length); 204 | 205 | } 206 | , 207 | /** 208 | * Called when an AttackRunner cannot test because it is in an error state. 209 | */ 210 | cannotRunTests: function() { 211 | getTestRunnerContainer().stop(); 212 | getTestRunnerContainer().clearWorkTabs(); 213 | 214 | var resultsManager = null; 215 | if (this.resultsManager) { 216 | resultsManager = this.resultsManager; 217 | } 218 | else { 219 | resultsManager = new ResultsManager(this.controller); 220 | } 221 | resultsManager.showResults(this, "There was an error while testing this site. This was likely due to Mozilla bug 420025 which only affects Fx2. We're working on making SQL Inject Me work with FireFox 3. Please help us track this bug by either emailing us the url to this site or commenting on the bug. We apologize for the inconvenience."); 222 | this.controller.postTest(); 223 | 224 | Components.utils.reportError( 225 | 'The loading of this page in a work tab as not successful: ' + 226 | getMainHTMLDoc().documentURI); 227 | } 228 | } 229 | 230 | /** 231 | * The getInstance method for the TestManager singleton 232 | */ 233 | function getTestManager(controller) { 234 | if (typeof(xssme__testmanager__) == 'undefined' || 235 | !xssme__testmanager__) 236 | { 237 | xssme__testmanager__ = new TestManager(); 238 | } 239 | // @todo: there has to be a better way... 240 | if (controller) { 241 | xssme__testmanager__.controller = controller; 242 | } 243 | 244 | return xssme__testmanager__; 245 | } 246 | 247 | -------------------------------------------------------------------------------- /content/TestRunnerContainer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * TestRunnerContainer.js 25 | */ 26 | 27 | /** 28 | * Based around a poor man's semaphore concept. 29 | */ 30 | function TestRunnerContainer(){ 31 | this.testRunners = new Array(); //All these arrays are parallell 32 | this.formPanels = new Array(); 33 | this.formIndexes = new Array(); 34 | this.fields = new Array(); 35 | this.testValues = new Array(); 36 | this.resultsManagers = new Array(); 37 | this.testManager = null; 38 | this.keepChecking = true; 39 | } 40 | 41 | TestRunnerContainer.prototype = { 42 | addTestRunner: function(testRunner, formPanel, formIndex, field, 43 | testValue, resultsManager) 44 | { 45 | this.testRunners.push(testRunner); 46 | this.formPanels.push(formPanel); 47 | this.formIndexes.push(formIndex); 48 | this.fields.push(field); 49 | this.testValues.push(testValue); 50 | this.resultsManagers.push(resultsManager); 51 | } 52 | , 53 | /* Called to begin a new test battery in this container. 54 | * @param tabManager information about the target of this battery 55 | */ 56 | start: function (tabManager) { 57 | // Has another part of the program halted the testing? 58 | if (!this.keepChecking) return; 59 | dump("check for more attacks: " + this.testRunners.length); 60 | // Do we have any more tests to run? 61 | if (this.testRunners.length == 0) { 62 | Components.utils.reportError("so done checking? kthxbye"); 63 | this.keepChecking = false; 64 | this.testManager.doneTesting(); 65 | return; 66 | } 67 | 68 | // Begin the next test in the first available tab and move that tab to the back of the queue. 69 | for (var i = 0; i < this.tabWrappers.length; i++) { 70 | if (!this.tabWrappers[i].inUse) { 71 | this.tabWrappers[i].inUse = true; 72 | this.testRunners.pop().do_test(this.formPanels.pop(), 73 | this.formIndexes.pop(), 74 | this.fields.pop(), 75 | this.testValues.pop(), 76 | this.resultsManagers.pop(), 77 | this.tabWrappers[i], 78 | tabManager); 79 | this.tabWrappers.push(this.tabWrappers.splice(i, 1)[0]); 80 | Components.utils.reportError("Running a test"); 81 | break; 82 | } 83 | } 84 | 85 | var self = this; 86 | setTimeout(function() { self.start(tabManager); }, 1); 87 | } 88 | , 89 | numWorkTabs: 6 90 | , 91 | getNumWorkTabs: function(){ 92 | var prefService = Components.classes['@mozilla.org/preferences-service;1']. 93 | getService(Components.interfaces.nsIPrefService); 94 | var branch = prefService.getBranch('extensions.sqlime.'); 95 | if (branch.prefHasUserValue('numtabstouse') ){ 96 | return branch.getIntPref('numtabstouse'); 97 | } 98 | else { 99 | return this.numWorkTabs; 100 | } 101 | } 102 | , 103 | clear: function (){ 104 | this.testRunners.splice(0, this.testRunners.length); 105 | this.formPanels.splice(0, this.formPanels.length); 106 | this.formIndexes.splice(0, this.formPanels.length); 107 | this.fields.splice(0, this.formPanels.length); 108 | this.testValues.splice(0, this.formPanels.length); 109 | this.resultsManagers.splice(0, this.formPanels.length); 110 | } 111 | , 112 | /** 113 | * Creates the tabs whose browsers will be used to run individual tests. 114 | * @param testManager will be reported to when test battery is complete. 115 | */ 116 | setup: function(testManager) { 117 | this.testManager = testManager; 118 | this.tabWrappers = new Array(); 119 | for (var i = 0; i < this.getNumWorkTabs(); i++) { 120 | this.tabWrappers[i] = { 121 | inUse: false, 122 | tab: null 123 | }; 124 | } 125 | } 126 | , 127 | clearWorkTabs: function () { 128 | //not needed any more. 129 | } 130 | , 131 | /** 132 | * Stops the running of tests in the TestRunnerContainer. 133 | */ 134 | stop: function(){ 135 | this.keepChecking = false; 136 | this.clear(); 137 | } 138 | }; 139 | 140 | /** 141 | * If currentNumTabs is provided, the container is cleared. 142 | */ 143 | function getTestRunnerContainer(testManager){ 144 | 145 | if (typeof(xssme__testrunnercontainer__) == 'undefined' || 146 | !xssme__testrunnercontainer__ ) 147 | { 148 | xssme__testrunnercontainer__ = new TestRunnerContainer(); 149 | } 150 | 151 | if (testManager) { 152 | xssme__testrunnercontainer__.setup(testManager); 153 | 154 | } 155 | 156 | return xssme__testrunnercontainer__; 157 | 158 | } 159 | -------------------------------------------------------------------------------- /content/about.xul: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /content/addAttack.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | function onOk() { 24 | var stringTxtBox = document.getElementById('attackstringtxtbox'); 25 | var sigTxtBox = document.getElementById('sigtxtbox'); 26 | var attackStrContainer = window.arguments[0]; 27 | var prefController = window.arguments[1]; 28 | var prefWindow = window.arguments[2]; 29 | 30 | 31 | if (!stringTxtBox.value.length) 32 | { 33 | alert("Please enter an attack string"); 34 | stringTxtBox.select(); 35 | return false; 36 | } 37 | if (!sigTxtBox.value.length){ 38 | alert("Please enter a signature to identify you by."); 39 | sigTxtBox.select(); 40 | return false; 41 | } 42 | 43 | if (attackStrContainer.addString(stringTxtBox.value, sigTxtBox.value)){ 44 | prefController.makeUI(attackStrContainer.getStrings(), prefWindow, 45 | 'existingSQLIstrings'); 46 | return true; 47 | } 48 | else{ 49 | alert("couldn't add your attack string"); 50 | return false; 51 | } 52 | 53 | 54 | } 55 | 56 | function onCancel(){ 57 | 58 | return true; 59 | } -------------------------------------------------------------------------------- /content/addAttack.xul: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 13 | 34 | 53 | -------------------------------------------------------------------------------- /content/addError.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | function onOk() { 24 | var stringTxtBox = document.getElementById('errorstringtxtbox'); 25 | var errorStrContainer = window.arguments[0]; 26 | var prefController = window.arguments[1]; 27 | var prefWindow = window.arguments[2]; 28 | 29 | 30 | if (!stringTxtBox.value.length) 31 | { 32 | alert("Please enter an error string"); 33 | stringTxtBox.select(); 34 | return false; 35 | } 36 | var wasStringAdded = errorStrContainer.addString(stringTxtBox.value, null); 37 | 38 | dump('was this string (' + stringTxtBox.value + ') added? ' + 39 | wasStringAdded + '\n'); 40 | 41 | if (wasStringAdded){ 42 | prefController.makeUI(errorStrContainer.getStrings(), prefWindow, 43 | 'existingSQLIerrStrings'); 44 | return true; 45 | } 46 | else{ 47 | alert("couldn't add your error string"); 48 | return false; 49 | } 50 | 51 | 52 | } 53 | 54 | function onCancel(){ 55 | 56 | return true; 57 | } -------------------------------------------------------------------------------- /content/addError.xul: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 12 | 33 | 34 | 51 | -------------------------------------------------------------------------------- /content/attackStringContainer.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * AttackStringContainer.js 25 | * requires preferenceStringContainer.js 26 | */ 27 | 28 | 29 | /** 30 | *this object is responsible for dealing with the Attack Strings. 31 | */ 32 | function AttackStringContainer() { 33 | this.init(); 34 | } 35 | AttackStringContainer.prototype = new PreferenceStringContainer(); 36 | dump('creating... AttackStringContainer object\n'); 37 | AttackStringContainer.prototype.init = function (){ 38 | 39 | var attackStrings; 40 | 41 | this.prefBranch = this.prefService.getBranch('extensions.sqlime.'); 42 | this.prefDefaultBranch = this.prefService.getDefaultBranch('extensions.sqlime.') 43 | attackStrings = this.prefBranch.getCharPref('attacks'); 44 | this.strings = sqlime.JSON.fromString(attackStrings); 45 | 46 | 47 | }; 48 | AttackStringContainer.prototype.save = function() { 49 | this.prefBranch.setCharPref('attacks', sqlime.JSON.toString(this.strings)); 50 | 51 | } 52 | 53 | 54 | function getAttackStringContainer(){ 55 | if (typeof(attackStringContainer) === 'undefined' || !attackStringContainer){ 56 | attackStringContainer = new AttackStringContainer(); 57 | } 58 | return attackStringContainer; 59 | } 60 | -------------------------------------------------------------------------------- /content/htmlStringEncoder.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2008 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * HTMLStringEncoder is used to encode strings so that they don't cause 25 | * problems in HTML. 26 | * This object is prefered over the using encodeString() directly as it 27 | * provides a cache so the expensive (O(n)) action of generating encoded 28 | * strings has to only be done once. 29 | * This cache does not check itself to make sure it doesn't grow too big. That's 30 | * up to its user. 31 | * @requires util.js this is a wrapper around the util encodeString function 32 | */ 33 | function HTMLStringEncoder(){ 34 | /** 35 | * the cache, a hash. All keys should be prefixed with 36 | * HTMLStringEncoder.prefix 37 | */ 38 | this.cache = new Object(); 39 | } 40 | 41 | HTMLStringEncoder.prototype = { 42 | /** 43 | * prefix is used to prefix all cache keys 44 | */ 45 | prefix: "html_" 46 | , 47 | /** 48 | * returns an encoded version of str. Checks cache first. 49 | * @returns an encoded version of str 50 | */ 51 | encodeString: function(str) { 52 | var rv = this.cache[this.prefix + str]; 53 | if (rv === undefined ){ 54 | rv = this.cache[this.prefix + str] = encodeString(str); 55 | } 56 | return rv; 57 | } 58 | , 59 | /** 60 | * clears the cache 61 | */ 62 | clear: function(){ 63 | this.cache = new Object(); 64 | } 65 | 66 | } 67 | 68 | function getHTMLStringEncoder() { 69 | if (typeof(__security_compass_html_string_encoder__) === 'undefined') { 70 | __security_compass_html_string_encoder__ = new HTMLStringEncoder; 71 | } 72 | return __security_compass_html_string_encoder__; 73 | } 74 | -------------------------------------------------------------------------------- /content/io.js: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////// 2 | ///////////////////////////////////////////////// 3 | // 4 | // Basic JavaScript File and Directory IO module 5 | // By: MonkeeSage, v0.1 6 | // 7 | ///////////////////////////////////////////////// 8 | ///////////////////////////////////////////////// 9 | 10 | 11 | if (typeof(JSIO) != 'boolean') { 12 | 13 | var JSIO = true; 14 | 15 | ///////////////////////////////////////////////// 16 | // Basic file IO object based on Mozilla source 17 | // code post at forums.mozillazine.org 18 | ///////////////////////////////////////////////// 19 | 20 | // Example use: 21 | // var fileIn = FileIO.open('/test.txt'); 22 | // if (fileIn.exists()) { 23 | // var fileOut = FileIO.open('/copy of test.txt'); 24 | // var str = FileIO.read(fileIn); 25 | // var rv = FileIO.write(fileOut, str); 26 | // alert('File write: ' + rv); 27 | // rv = FileIO.write(fileOut, str, 'a'); 28 | // alert('File append: ' + rv); 29 | // rv = FileIO.unlink(fileOut); 30 | // alert('File unlink: ' + rv); 31 | // } 32 | 33 | var FileIO = { 34 | 35 | localfileCID : '@mozilla.org/file/local;1', 36 | localfileIID : Components.interfaces.nsILocalFile, 37 | 38 | finstreamCID : '@mozilla.org/network/file-input-stream;1', 39 | finstreamIID : Components.interfaces.nsIFileInputStream, 40 | 41 | foutstreamCID : '@mozilla.org/network/file-output-stream;1', 42 | foutstreamIID : Components.interfaces.nsIFileOutputStream, 43 | 44 | sinstreamCID : '@mozilla.org/scriptableinputstream;1', 45 | sinstreamIID : Components.interfaces.nsIScriptableInputStream, 46 | 47 | suniconvCID : '@mozilla.org/intl/scriptableunicodeconverter', 48 | suniconvIID : Components.interfaces.nsIScriptableUnicodeConverter, 49 | 50 | open : function(path) { 51 | try { 52 | var file = Components.classes[this.localfileCID] 53 | .createInstance(this.localfileIID); 54 | file.initWithPath(path); 55 | return file; 56 | } 57 | catch(e) { 58 | return false; 59 | } 60 | }, 61 | readChannel : function(channel, charset){ 62 | var data = new String(); 63 | var inStream = channel.open(); 64 | var scriptableInStream = Components.classes["@mozilla.org/scriptableinputstream;1"]. 65 | createInstance().QueryInterface(Components.interfaces.nsIScriptableInputStream); 66 | scriptableInStream.init(inStream); 67 | 68 | data = scriptableInStream.read(scriptableInStream.available()); 69 | 70 | return data; 71 | }, 72 | read : function(file, charset) { 73 | try { 74 | var data = new String(); 75 | var fiStream = Components.classes[this.finstreamCID] 76 | .createInstance(this.finstreamIID); 77 | var siStream = Components.classes[this.sinstreamCID] 78 | .createInstance(this.sinstreamIID); 79 | fiStream.init(file, 1, 0, false); 80 | siStream.init(fiStream); 81 | data += siStream.read(-1); 82 | siStream.close(); 83 | fiStream.close(); 84 | if (charset) { 85 | data = this.toUnicode(charset, data); 86 | } 87 | return data; 88 | } 89 | catch(e) { 90 | return false; 91 | } 92 | }, 93 | 94 | write : function(file, data, mode, charset) { 95 | try { 96 | var foStream = Components.classes[this.foutstreamCID] 97 | .createInstance(this.foutstreamIID); 98 | if (charset) { 99 | data = this.fromUnicode(charset, data); 100 | } 101 | var flags = 0x02 | 0x08 | 0x20; // wronly | create | truncate 102 | if (mode == 'a') { 103 | flags = 0x02 | 0x10; // wronly | append 104 | } 105 | foStream.init(file, flags, 0664, 0); 106 | foStream.write(data, data.length); 107 | // foStream.flush(); 108 | foStream.close(); 109 | return true; 110 | } 111 | catch(e) { 112 | return false; 113 | } 114 | }, 115 | 116 | create : function(file) { 117 | try { 118 | file.create(0x00, 0664); 119 | return true; 120 | } 121 | catch(e) { 122 | return false; 123 | } 124 | }, 125 | 126 | unlink : function(file) { 127 | try { 128 | file.remove(false); 129 | return true; 130 | } 131 | catch(e) { 132 | return false; 133 | } 134 | }, 135 | 136 | path : function(file) { 137 | try { 138 | return 'file:///' + file.path.replace(/\\/g, '\/') 139 | .replace(/^\s*\/?/, '').replace(/\ /g, '%20'); 140 | } 141 | catch(e) { 142 | return false; 143 | } 144 | }, 145 | 146 | toUnicode : function(charset, data) { 147 | try{ 148 | var uniConv = Components.classes[this.suniconvCID] 149 | .createInstance(this.suniconvIID); 150 | uniConv.charset = charset; 151 | data = uniConv.ConvertToUnicode(data); 152 | } 153 | catch(e) { 154 | // foobar! 155 | } 156 | return data; 157 | }, 158 | 159 | fromUnicode : function(charset, data) { 160 | try { 161 | var uniConv = Components.classes[this.suniconvCID] 162 | .createInstance(this.suniconvIID); 163 | uniConv.charset = charset; 164 | data = uniConv.ConvertFromUnicode(data); 165 | // data += uniConv.Finish(); 166 | } 167 | catch(e) { 168 | // foobar! 169 | } 170 | return data; 171 | } 172 | 173 | } 174 | 175 | 176 | ///////////////////////////////////////////////// 177 | // Basic Directory IO object based on JSLib 178 | // source code found at jslib.mozdev.org 179 | ///////////////////////////////////////////////// 180 | 181 | // Example use: 182 | // var dir = DirIO.open('/test'); 183 | // if (dir.exists()) { 184 | // alert(DirIO.path(dir)); 185 | // var arr = DirIO.read(dir, true), i; 186 | // if (arr) { 187 | // for (i = 0; i < arr.length; ++i) { 188 | // alert(arr[i].path); 189 | // } 190 | // } 191 | // } 192 | // else { 193 | // var rv = DirIO.create(dir); 194 | // alert('Directory create: ' + rv); 195 | // } 196 | 197 | // --------------------------------------------- 198 | // ----------------- Nota Bene ----------------- 199 | // --------------------------------------------- 200 | // Some possible types for get are: 201 | // 'ProfD' = profile 202 | // 'DefProfRt' = user (e.g., /root/.mozilla) 203 | // 'UChrm' = %profile%/chrome 204 | // 'DefRt' = installation 205 | // 'PrfDef' = %installation%/defaults/pref 206 | // 'ProfDefNoLoc' = %installation%/defaults/profile 207 | // 'APlugns' = %installation%/plugins 208 | // 'AChrom' = %installation%/chrome 209 | // 'ComsD' = %installation%/components 210 | // 'CurProcD' = installation (usually) 211 | // 'Home' = OS root (e.g., /root) 212 | // 'TmpD' = OS tmp (e.g., /tmp) 213 | 214 | var DirIO = { 215 | 216 | sep : '/', 217 | 218 | dirservCID : '@mozilla.org/file/directory_service;1', 219 | 220 | propsIID : Components.interfaces.nsIProperties, 221 | 222 | fileIID : Components.interfaces.nsIFile, 223 | 224 | get : function(type) { 225 | try { 226 | var dir = Components.classes[this.dirservCID] 227 | .createInstance(this.propsIID) 228 | .get(type, this.fileIID); 229 | return dir; 230 | } 231 | catch(e) { 232 | return false; 233 | } 234 | }, 235 | 236 | open : function(path) { 237 | return FileIO.open(path); 238 | }, 239 | 240 | create : function(dir) { 241 | try { 242 | dir.create(0x01, 0664); 243 | return true; 244 | } 245 | catch(e) { 246 | return false; 247 | } 248 | }, 249 | 250 | read : function(dir, recursive) { 251 | var list = new Array(); 252 | try { 253 | if (dir.isDirectory()) { 254 | if (recursive == null) { 255 | recursive = false; 256 | } 257 | var files = dir.directoryEntries; 258 | list = this._read(files, recursive); 259 | } 260 | } 261 | catch(e) { 262 | // foobar! 263 | } 264 | return list; 265 | }, 266 | 267 | _read : function(dirEntry, recursive) { 268 | var list = new Array(); 269 | try { 270 | while (dirEntry.hasMoreElements()) { 271 | list.push(dirEntry.getNext() 272 | .QueryInterface(FileIO.localfileIID)); 273 | } 274 | if (recursive) { 275 | var list2 = new Array(); 276 | for (var i = 0; i < list.length; ++i) { 277 | if (list[i].isDirectory()) { 278 | files = list[i].directoryEntries; 279 | list2 = this._read(files, recursive); 280 | } 281 | } 282 | for (i = 0; i < list2.length; ++i) { 283 | list.push(list2[i]); 284 | } 285 | } 286 | } 287 | catch(e) { 288 | // foobar! 289 | } 290 | return list; 291 | }, 292 | 293 | unlink : function(dir, recursive) { 294 | try { 295 | if (recursive == null) { 296 | recursive = false; 297 | } 298 | dir.remove(recursive); 299 | return true; 300 | } 301 | catch(e) { 302 | return false; 303 | } 304 | }, 305 | 306 | path : function (dir) { 307 | return FileIO.path(dir); 308 | }, 309 | 310 | split : function(str, join) { 311 | var arr = str.split(/\/|\\/), i; 312 | str = new String(); 313 | for (i = 0; i < arr.length; ++i) { 314 | str += arr[i] + ((i != arr.length - 1) ? 315 | join : ''); 316 | } 317 | return str; 318 | }, 319 | 320 | join : function(str, split) { 321 | var arr = str.split(split), i; 322 | str = new String(); 323 | for (i = 0; i < arr.length; ++i) { 324 | str += arr[i] + ((i != arr.length - 1) ? 325 | this.sep : ''); 326 | } 327 | return str; 328 | } 329 | 330 | } 331 | 332 | if (navigator.platform.toLowerCase().indexOf('win') > -1) { 333 | DirIO.sep = '\\'; 334 | } 335 | 336 | } 337 | -------------------------------------------------------------------------------- /content/json.js: -------------------------------------------------------------------------------- 1 | /* ***** BEGIN LICENSE BLOCK ***** 2 | * Version: MPL 1.1/GPL 2.0/LGPL 2.1 3 | * 4 | * The contents of this file are subject to the Mozilla Public License Version 5 | * 1.1 (the "License"); you may not use this file except in compliance with 6 | * the License. You may obtain a copy of the License at 7 | * http://www.mozilla.org/MPL/ 8 | * 9 | * Software distributed under the License is distributed on an "AS IS" basis, 10 | * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 11 | * for the specific language governing rights and limitations under the 12 | * License. 13 | * 14 | * The Original Code is Mozilla code. 15 | * 16 | * The Initial Developer of the Original Code is 17 | * Simon Bünzli 18 | * Portions created by the Initial Developer are Copyright (C) 2006-2007 19 | * the Initial Developer. All Rights Reserved. 20 | * 21 | * Contributor(s): 22 | * 23 | * Alternatively, the contents of this file may be used under the terms of 24 | * either the GNU General Public License Version 2 or later (the "GPL"), or 25 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 26 | * in which case the provisions of the GPL or the LGPL are applicable instead 27 | * of those above. If you wish to allow use of your version of this file only 28 | * under the terms of either the GPL or the LGPL, and not to allow others to 29 | * use your version of this file under the terms of the MPL, indicate your 30 | * decision by deleting the provisions above and replace them with the notice 31 | * and other provisions required by the GPL or the LGPL. If you do not delete 32 | * the provisions above, a recipient may use your version of this file under 33 | * the terms of any one of the MPL, the GPL or the LGPL. 34 | * 35 | * ***** END LICENSE BLOCK ***** */ 36 | 37 | /* downloaded from http://lxr.mozilla.org/seamonkey/source/js/src/xpconnect/loader/JSON.jsm?raw=1 */ 38 | 39 | 40 | /** 41 | * Utilities for JavaScript code to handle JSON content. 42 | * See http://www.json.org/ for comprehensive information about JSON. 43 | * 44 | * Import this module through 45 | * 46 | * Components.utils.import("resource://gre/modules/JSON.jsm"); 47 | * 48 | * Usage: 49 | * 50 | * var newJSONString = JSON.toString( GIVEN_JAVASCRIPT_OBJECT ); 51 | * var newJavaScriptObject = JSON.fromString( GIVEN_JSON_STRING ); 52 | * 53 | * Note: For your own safety, Objects/Arrays returned by 54 | * JSON.fromString aren't instanceof Object/Array. 55 | */ 56 | 57 | // The following code is a loose adaption of Douglas Crockford's code 58 | // from http://www.json.org/json.js (public domain'd) 59 | 60 | // Notable differences: 61 | // * Unserializable values such as |undefined| or functions aren't 62 | // silently dropped but always lead to a TypeError. 63 | // * An optional key blacklist has been added to JSON.toString 64 | 65 | sqlime.JSON = { 66 | /** 67 | * Converts a JavaScript object into a JSON string. 68 | * 69 | * @param aJSObject is the object to be converted 70 | * @param aKeysToDrop is an optional array of keys which will be 71 | * ignored in all objects during the serialization 72 | * @return the object's JSON representation 73 | * 74 | * Note: aJSObject MUST not contain cyclic references. 75 | */ 76 | toString: function JSON_toString(aJSObject, aKeysToDrop) { 77 | // these characters have a special escape notation 78 | const charMap = { "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f", 79 | "\r": "\\r", '"': '\\"', "\\": "\\\\" }; 80 | 81 | // we use a single string builder for efficiency reasons 82 | var pieces = []; 83 | 84 | // this recursive function walks through all objects and appends their 85 | // JSON representation (in one or several pieces) to the string builder 86 | function append_piece(aObj) { 87 | if (typeof aObj == "boolean") { 88 | pieces.push(aObj ? "true" : "false"); 89 | } 90 | else if (typeof aObj == "number" && isFinite(aObj)) { 91 | // there is no representation for infinite numbers or for NaN! 92 | pieces.push(aObj.toString()); 93 | } 94 | else if (typeof aObj == "string") { 95 | aObj = aObj.replace(/[\\"\x00-\x1F\u0080-\uFFFF]/g, function($0) { 96 | // use the special escape notation if one exists, otherwise 97 | // produce a general unicode escape sequence 98 | return charMap[$0] || 99 | "\\u" + ("0000" + $0.charCodeAt(0).toString(16)).slice(-4); 100 | }); 101 | pieces.push('"' + aObj + '"') 102 | } 103 | else if (aObj === null) { 104 | pieces.push("null"); 105 | } 106 | // if it looks like an array, treat it as such - this is required 107 | // for all arrays from either outside this module or a sandbox 108 | else if (aObj instanceof Array || 109 | typeof aObj == "object" && "length" in aObj && 110 | (aObj.length === 0 || aObj[aObj.length - 1] !== undefined)) { 111 | pieces.push("["); 112 | for (var i = 0; i < aObj.length; i++) { 113 | append_piece(aObj[i]); 114 | pieces.push(","); 115 | } 116 | if (pieces[pieces.length - 1] == ",") 117 | pieces.pop(); // drop the trailing colon 118 | pieces.push("]"); 119 | } 120 | else if (typeof aObj == "object") { 121 | pieces.push("{"); 122 | for (var key in aObj) { 123 | // allow callers to pass objects containing private data which 124 | // they don't want the JSON string to contain (so they don't 125 | // have to manually pre-process the object) 126 | if (aKeysToDrop && aKeysToDrop.indexOf(key) != -1) 127 | continue; 128 | 129 | append_piece(key.toString()); 130 | pieces.push(":"); 131 | append_piece(aObj[key]); 132 | pieces.push(","); 133 | } 134 | if (pieces[pieces.length - 1] == ",") 135 | pieces.pop(); // drop the trailing colon 136 | pieces.push("}"); 137 | } 138 | else { 139 | throw new TypeError("No JSON representation for this object!"); 140 | } 141 | } 142 | append_piece(aJSObject); 143 | 144 | return pieces.join(""); 145 | }, 146 | 147 | /** 148 | * Converts a JSON string into a JavaScript object. 149 | * 150 | * @param aJSONString is the string to be converted 151 | * @return a JavaScript object for the given JSON representation 152 | */ 153 | fromString: function JSON_fromString(aJSONString) { 154 | if (!this.isMostlyHarmless(aJSONString)) 155 | throw new SyntaxError("No valid JSON string!"); 156 | 157 | var s = new Components.utils.Sandbox("about:blank"); 158 | return Components.utils.evalInSandbox("(" + aJSONString + ")", s); 159 | }, 160 | 161 | /** 162 | * Checks whether the given string contains potentially harmful 163 | * content which might be executed during its evaluation 164 | * (no parser, thus not 100% safe! Best to use a Sandbox for evaluation) 165 | * 166 | * @param aString is the string to be tested 167 | * @return a boolean 168 | */ 169 | isMostlyHarmless: function JSON_isMostlyHarmless(aString) { 170 | const maybeHarmful = /[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/; 171 | const jsonStrings = /"(\\.|[^"\\\n\r])*"/g; 172 | 173 | return !maybeHarmful.test(aString.replace(jsonStrings, "")); 174 | } 175 | }; 176 | -------------------------------------------------------------------------------- /content/overlay.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * This function checks whether the context menu needs to be dispalyed and then 25 | * makes sure that that is the state of the context menu 26 | */ 27 | 28 | function checkContextMenu() { 29 | var prefService = Components.classes['@mozilla.org/preferences-service;1']. 30 | getService(Components.interfaces.nsIPrefService); 31 | var branch = prefService.getBranch('extensions.sqlime.'); 32 | var showContextMenu = true; //default 33 | dump('::checkContextMenu branch.prefHasUserValue(\'showcontextmenu\') == '); 34 | dump(branch.prefHasUserValue('showcontextmenu')); 35 | dump('\n'); 36 | if (branch.prefHasUserValue('showcontextmenu')) { 37 | showContextMenu = branch.getBoolPref('showcontextmenu'); 38 | } 39 | 40 | var contextMenu = document.getElementById('sqlimecontextmenu'); 41 | dump('::checkContextMenu contextMenu == ' + contextMenu + '\n'); 42 | dump('::checkContextMenu showcontextmenu == '); 43 | dump(showContextMenu +'\n'); 44 | contextMenu.setAttribute('collapsed', !showContextMenu); 45 | } 46 | 47 | function XssOverlay() {} 48 | 49 | XssOverlay.prototype = { 50 | contextMenuObserver: null 51 | , 52 | onLoad: function() { 53 | 54 | var prefService = Components.classes['@mozilla.org/preferences-service;1']. 55 | getService(Components.interfaces.nsIPrefService); 56 | 57 | var branch = prefService.getBranch(''); 58 | 59 | var observableBranch = branch. 60 | QueryInterface(Components.interfaces.nsIPrefBranch2); 61 | 62 | this.contextMenuObserver = new Xss_PrefObserver(checkContextMenu); 63 | 64 | checkContextMenu(); 65 | 66 | dump('mainwindow::onLoad contextMenuObserver ==' + this.contextMenuObserver +'\n'); 67 | 68 | 69 | observableBranch.addObserver('extensions.sqlime.showcontextmenu', this.contextMenuObserver, false); 70 | } 71 | , 72 | onUnload: function() { 73 | var prefService = Components.classes['@mozilla.org/preferences-service;1']. 74 | getService(Components.interfaces.nsIPrefService); 75 | 76 | var branch = prefService.getBranch(''); 77 | 78 | var observableBranch = branch. 79 | QueryInterface(Components.interfaces.nsIPrefBranch2); 80 | 81 | observableBranch.removeObserver('extensions.sqlime.showcontextmenu', this.contextMenuObserver) 82 | } 83 | }; 84 | 85 | var xssOverlay = new XssOverlay(); 86 | 87 | window.addEventListener('load', xssOverlay.onLoad, false); 88 | window.addEventListener('unload', xssOverlay.onUnload, false); 89 | -------------------------------------------------------------------------------- /content/overlay.xul: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 26 | 119 | 120 | -------------------------------------------------------------------------------- /content/progressListener.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | const STATE_START = Components.interfaces.nsIWebProgressListener.STATE_START; 24 | const STATE_STOP = Components.interfaces.nsIWebProgressListener.STATE_STOP; 25 | const STATE_IS_WINDOW = Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW; 26 | const STATE_IS_DOCUMENT = Components.interfaces.nsIWebProgressListener.STATE_IS_DOCUMENT; 27 | 28 | const LISTEN_ON_WINDOW = 1; 29 | const LISTEN_ON_DOCUMENT = 2; 30 | 31 | function sqlimeProgressListener(funcToCall, listenOn) { 32 | 33 | this.func = funcToCall 34 | this.listenOn = listenOn != null ? listenOn : STATE_IS_WINDOW; 35 | dump('created a listener... mode is ' + listenOn + '\n'); 36 | this.interfaceName = "nsIWebProgressListener"; 37 | }; 38 | 39 | sqlimeProgressListener.prototype = 40 | { 41 | QueryInterface: function(aIID) 42 | { 43 | if (aIID.equals(Components.interfaces.nsIWebProgressListener) || 44 | aIID.equals(Components.interfaces.nsISupportsWeakReference) || 45 | aIID.equals(Components.interfaces.nsISupports)) 46 | { 47 | return this; 48 | } 49 | throw Components.results.NS_NOINTERFACE; 50 | return null; 51 | }, 52 | 53 | onStateChange: function(aProgress, aRequest, aFlag, aStatus) 54 | { 55 | dump('got a state change. aFlag is ' + aFlag.toString(16) + '\n'); 56 | dump('got a state change. we are listening on ' + 57 | this.listenOn.toString(16) + '\n'); 58 | // Components sometimes seems to disappear or or malfunction so we're 59 | // just using the literal constant here. 60 | // if((aFlag & 0x00000010) && 61 | // (aFlag & 0x00080000) ) 62 | if ((aFlag & STATE_STOP) && (aFlag & this.listenOn)) { 63 | this.func(); 64 | } 65 | return 0; 66 | }, 67 | 68 | onLocationChange: function(aProgress, aRequest, aURI) 69 | { 70 | 71 | return 0; 72 | }, 73 | 74 | // For definitions of the remaining functions see XULPlanet.com 75 | onProgressChange: function() {return 0;}, 76 | onStatusChange: function() {return 0;}, 77 | onSecurityChange: function() {return 0;}, 78 | onLinkIconAvailable: function() {return 0;} 79 | }; 80 | -------------------------------------------------------------------------------- /content/results.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 9 | Results for http://www.domain.tld/url.ext 10 | 45 | 46 | 47 | 48 | 49 |

SQL Inject Me Test Results for http://domain.tld/url.ext

50 |

Here are the results for the 9999 tests run:

51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
Passed:
 
45%
Warning:
 
25%
Failed:
 
30%
70 |
71 | Form 1 72 |
73 | Test 1 74 |

Result: Failed

75 |
    76 |
  • Field 1: value1
  • 77 |
  • Field 2: value2
  • 78 |
79 |
80 |
81 | Test 2 82 |

Result: Warning

83 |
    84 |
  • Field 1: value1
  • 85 |
  • Field 2: value2
  • 86 |
87 |
88 |
89 | Test 1 90 |

Result: Passed

91 |
    92 |
  • Field 1: value1
  • 93 |
  • Field 2: value2
  • 94 |
95 |
96 |
97 | 98 | 99 | -------------------------------------------------------------------------------- /content/sidebarBuilder.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2008 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | function SidebarBuilder() { 24 | 25 | this.toBeAdded = new Array(); 26 | var prefService = Components.classes['@mozilla.org/preferences-service;1']. 27 | getService(Components.interfaces.nsIPrefService); 28 | var branch = prefService.getBranch('extensions.sqlime.'); 29 | 30 | this.time = branch.getIntPref('sidebarbuildingstop'); 31 | this.isRunning = true; 32 | } 33 | 34 | SidebarBuilder.prototype = { 35 | setup: function(){ 36 | this.isRunning = true; 37 | this.toBeAdded = new Array(); 38 | } 39 | , 40 | start: function(self){ 41 | if (!self) { 42 | self = this; 43 | } 44 | if (self.toBeAdded.length > 0 && self.isRunning) { 45 | 46 | var parent, child, postFunc; 47 | 48 | [parent, child, postFunc] = self.toBeAdded.pop(); 49 | 50 | dump('\nAdding '+child+'('+ child.nodeName+') -> '+parent + '('+parent.nodeName+')'); 51 | 52 | parent.appendChild(child); 53 | 54 | if (postFunc) postFunc(parent, child); 55 | 56 | setTimeout(self.start, self.time, self); 57 | 58 | } 59 | 60 | 61 | } 62 | , 63 | add: function(parent, child, postFunc) { 64 | this.toBeAdded.push([parent,child, postFunc]); 65 | } 66 | , 67 | stop: function() { 68 | this.isRunning = false; 69 | this.toBeAdded = null; 70 | } 71 | } 72 | 73 | function getSidebarBuilder() { 74 | if (typeof(__xssme_sidebar_builder__) == 'undefined' || 75 | !__xssme_sidebar_builder__) 76 | { 77 | __xssme_sidebar_builder__ = new SidebarBuilder(); 78 | } 79 | return __xssme_sidebar_builder__; 80 | } 81 | -------------------------------------------------------------------------------- /content/sqlime.js: -------------------------------------------------------------------------------- 1 | sqlime = {} -------------------------------------------------------------------------------- /content/sqlime_sidebar.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * Sidebar.js 25 | * @requires AttackRunner.js 26 | */ 27 | 28 | /** 29 | * These constants are used as ids for the types of test we can run. 30 | */ 31 | const TestType_AllTestsForForm = 1; 32 | const TestType_PrefNumTestsForForm = 2; 33 | const TestType_OneTestForForm = 3; 34 | const TestType_AllTestsForAllForms = 4; 35 | 36 | const STOP_ALL = Components.interfaces.nsIWebNavigation.STOP_ALL; 37 | 38 | const __sqli_me_prefs_to_disable = [ 39 | {"name": "security.warn_entering_secure", "type":"bool", "ourValue": false}, 40 | {"name": "security.warn_entering_weak", "type":"bool", "ourValue": false}, 41 | {"name": "security.warn_leaving_secure", "type":"bool", "ourValue": false}, 42 | {"name": "security.warn_submit_insecure", "type":"bool", "ourValue": false}, 43 | {"name": "security.warn_viewing_mixed", "type":"bool", "ourValue": false}, 44 | {"name": "dom.max_chrome_script_run_time", "type":"int", "ourValue": 0}, 45 | {"name": "signon.autofillForms", "type":"bool", "ourValue":false}, /* to remove autofilling forms in Fx3 */ 46 | {"name": "signon.prefillForms", "type":"bool", "ourValue":false}, /* same as above but for Fx2 */ 47 | {"name": "signon.rememberSignons", "type":"bool", "ourValue":false}, 48 | {"name": "accessibility.typeaheadfind.enablesound", "type":"bool", "ourValue":false} 49 | ]; 50 | 51 | /** 52 | * get a reference to the main firefox window 53 | */ 54 | function getMainWindow(){ 55 | var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor) 56 | .getInterface(Components.interfaces.nsIWebNavigation) 57 | .QueryInterface(Components.interfaces.nsIDocShellTreeItem) 58 | .rootTreeItem 59 | .QueryInterface(Components.interfaces.nsIInterfaceRequestor) 60 | .getInterface(Components.interfaces.nsIDOMWindow); 61 | return mainWindow; 62 | } 63 | 64 | /** 65 | * get a reference to the document object of the page that is being viewed now 66 | */ 67 | function getMainHTMLDoc(){ 68 | var mainWindow = getMainWindow(); 69 | var elTabBrowser = mainWindow.document.getElementById('content'); 70 | var currentDocument = elTabBrowser.contentDocument; 71 | return currentDocument; 72 | } 73 | 74 | 75 | function getMainHTMLWindow() { 76 | var mainWindow = getMainWindow(); 77 | var elTabBrowser = mainWindow.document.getElementById('content'); 78 | var win = elTabBrowser.contentWindow; 79 | return win; 80 | } 81 | 82 | function extension(){ 83 | //do nothing right now... 84 | this.plistener = null; 85 | this.warningDialog = null; 86 | this.typeAheadSound = true; //default for 87 | this.prefs = new Array(); 88 | } 89 | 90 | extension.prototype = { 91 | getTestType: function(event){ 92 | var tabbox = document.getElementById('sidebarformtabbox'); 93 | var rv = new Object(); 94 | var buttonClicked = event.explicitOriginalTarget; 95 | 96 | if (buttonClicked.className && buttonClicked.className === 97 | 'run_form_test') 98 | { 99 | 100 | rv.singleFormTest = true; 101 | 102 | if (tabbox.selectedPanel == null) { 103 | tabbox.selectedIndex = 0 104 | } 105 | 106 | if ( tabbox.selectedPanel. 107 | getElementsByAttribute('class', 'TestType').item(0). 108 | selectedItem.value == TestType_AllTestsForForm) 109 | { 110 | rv.allTests = true; 111 | } 112 | else { 113 | rv.allTests = false; 114 | } 115 | 116 | } 117 | else { 118 | rv.singleFormTest = false; 119 | if (buttonClicked.id === 'test_all_forms_with_all_attacks'){ 120 | rv.allTests=true; 121 | } 122 | else { 123 | rv.allTests = false; 124 | } 125 | } 126 | 127 | /* cache the number of attacks early */ 128 | rv.count = getAttackStringContainer().getStrings().length; 129 | if (rv.allTests === false) { 130 | var prefNumAttacks = this.getPreferredNumberOfAttacks(); 131 | 132 | rv.count = (prefNumAttacks > rv.count) ? rv.count : prefNumAttacks; 133 | 134 | } 135 | 136 | return rv; 137 | } 138 | , 139 | getMarkedFieldsForPanel:function(formPanel, all, formIndex) { 140 | var fieldUIs = formPanel.getElementsByAttribute('class', 'nolabel'); 141 | var fieldsToTest = new Array(); 142 | 143 | for(var i =0; i < fieldUIs.length; i++){ 144 | if (fieldUIs[i].checked || all === true){ 145 | var fieldToTest = new Object(); 146 | fieldToTest.index = parseInt(fieldUIs[i].getAttribute('formElementIndex')); 147 | fieldToTest.name = getMainHTMLDoc().forms[formIndex].elements[fieldToTest.index].name; 148 | fieldsToTest.push(fieldToTest); 149 | } 150 | } 151 | return fieldsToTest; 152 | } 153 | , 154 | /** 155 | * iterate through all these fields and find all the marked ones 156 | * @param testType the type of test that is being run. 157 | * @returns a list of fields to test 158 | */ 159 | getFieldsToTest: function(testType) { 160 | var rv = null; 161 | var tabbox = document.getElementById('sidebarformtabbox'); 162 | var mainDoc = getMainWindow().document.getElementById('content').contentDocument; 163 | 164 | if (testType.singleFormTest) { 165 | rv = this.getMarkedFieldsForPanel(tabbox.selectedPanel, false, tabbox.selectedIndex); 166 | for each (field in rv) { 167 | field.formIndex = tabbox.selectedIndex; 168 | field.formName = getHTMLFormElementNameOrLabel(mainDoc.forms[tabbox.selectedIndex]); 169 | } 170 | } 171 | else { 172 | /* @todo is using ._tabpanels safe here? ._tabpanels is a 173 | cached version of the panels */ 174 | for (var n = 0; n < tabbox._tabpanels.childNodes.length; n++) { 175 | /* @todo is using ._tabpanels safe here? ._tabpanels is a 176 | cached version of the panels */ 177 | var temp = this.getMarkedFieldsForPanel(tabbox._tabpanels. 178 | childNodes.item(n), true, n); 179 | for each (field in temp) { 180 | field.formIndex = n; 181 | field.formName = getHTMLFormElementNameOrLabel(mainDoc.forms[n]); 182 | 183 | } 184 | if (rv) { 185 | rv = rv.concat(temp); 186 | } 187 | else { 188 | rv = temp; 189 | } 190 | } 191 | } 192 | return rv; 193 | } 194 | , 195 | run_tests: function(event){ 196 | 197 | var canRunTests = this.preTest(); 198 | 199 | if (canRunTests == false){ 200 | alert('Could not run tests as test are already running. Please ' + 201 | 'wait for these tests to finish.') 202 | return; 203 | } 204 | 205 | var testType = this.getTestType(event); 206 | var fieldsToTest = this.getFieldsToTest(testType); 207 | var testCount = 0; 208 | var tabManager = new TabManager(getMainWindow().getBrowser().selectedTab.linkedBrowser); 209 | 210 | if (fieldsToTest.length === 0) { 211 | alert('Please make sure you have selected fields to test.') 212 | this.postTest(); 213 | testCount = fieldsToTest.length * heuristicTestChars.length; 214 | return; 215 | } 216 | else { 217 | testCount = fieldsToTest.length * testType.count; 218 | } 219 | 220 | this.warningDialog = window.openDialog( 221 | 'chrome://sqlime/content/whiletestruns.xul', 'whiletestruns', 222 | 'chrome,dialog,dependant=yes', testCount, testType); 223 | 224 | var testManager = getTestManager(this); 225 | 226 | testManager.runTest(testType, fieldsToTest, tabManager); 227 | } 228 | , 229 | createActionUI: function() { 230 | var box = document.createElement('hbox'); 231 | var menulist = document.createElement('menulist'); 232 | var menupopup = document.createElement('menupopup'); 233 | var runTests_mi = document.createElement('menuitem'); 234 | var runTopTests_mi = document.createElement('menuitem'); 235 | var submitThisForm_mi = document.createElement('menuitem'); 236 | var button = document.createElement('button'); 237 | var rv = new Object(); 238 | 239 | rv.menuitems = []; 240 | 241 | runTests_mi.setAttribute('label', "Run all tests"); 242 | runTests_mi.setAttribute('value', TestType_AllTestsForForm); 243 | runTests_mi.setAttribute('selected', TestType_AllTestsForForm); 244 | 245 | runTopTests_mi.setAttribute('label', "Run top " + this. 246 | getPreferredNumberOfAttacks() + " tests"); 247 | runTopTests_mi.setAttribute('value', TestType_PrefNumTestsForForm); 248 | 249 | 250 | submitThisForm_mi.setAttribute('value', TestType_OneTestForForm); 251 | 252 | rv.menuitems.push(runTopTests_mi); 253 | rv.menuitems.push(runTests_mi); 254 | 255 | //menulist.setAttribute("editable", false); 256 | rv.menupopup= menupopup; 257 | 258 | button.setAttribute('label', "Execute"); 259 | button.setAttribute('command', 'sqlime_do_test'); 260 | button.className = 'run_form_test'; 261 | 262 | menulist.setAttribute('class', 'TestType'); 263 | rv.menulist = menulist; 264 | 265 | 266 | rv.button = button; 267 | 268 | rv.box = box; 269 | 270 | return rv; 271 | } 272 | , 273 | syncSidebarToForm: function(sidebarElement, formElement){ 274 | 275 | 276 | var assignSidebarValueToFormElement = function(event){ 277 | formElement.value=sidebarElement.value.toString(); 278 | } 279 | 280 | var assignFormElementValueToSideBar = function(event){ 281 | sidebarElement.value = formElement.value.toString(); 282 | } 283 | 284 | var w = window; 285 | var htmlContentWindow = getMainHTMLWindow(); 286 | 287 | var releaseMemory = function(event){ 288 | formElement.removeEventListener('keypress', 289 | assignFormElementValueToSideBar, true); 290 | formElement.removeEventListener('mouseup', 291 | assignFormElementValueToSideBar, true); 292 | formElement.removeEventListener('change', 293 | assignFormElementValueToSideBar, true); 294 | sidebarElement.removeEventListener('input', 295 | assignSidebarValueToFormElement, true); 296 | sidebarElement.removeEventListener('click', 297 | assignSidebarValueToFormElement, true); 298 | w.removeEventListener('unload', arguments.callee, true); 299 | htmlContentWindow.removeEventListener('unload', arguments.callee, 300 | true); 301 | } 302 | 303 | formElement.addEventListener('keypress', assignFormElementValueToSideBar, true); 304 | formElement.addEventListener('mouseup', assignFormElementValueToSideBar, true); 305 | formElement.addEventListener('change', assignFormElementValueToSideBar, true); 306 | sidebarElement.addEventListener('input', assignSidebarValueToFormElement, true); 307 | sidebarElement.addEventListener('click', assignSidebarValueToFormElement, true); 308 | htmlContentWindow.addEventListener('unload', releaseMemory, true); 309 | w.addEventListener('unload', releaseMemory, true); 310 | 311 | 312 | } 313 | , 314 | do_generate_form_ui: function() { 315 | var q = 0; 316 | var maindoc = getMainWindow().document.getElementById('content').contentDocument; 317 | var box = document.getElementById('sqlime_here_be_tabs'); 318 | var docforms = maindoc.getElementsByTagName('form'); 319 | var unnamedFormCounter = 0; //used for generating the unnamed form names 320 | var tabbox = document.createElement('tabbox'); 321 | var tabs = document.createElement('tabs'); 322 | var tabpanels = document.createElement('tabpanels'); 323 | var fieldsLabel = document.createElement('label'); 324 | var sidebarBuilder = getSidebarBuilder(); 325 | fieldsLabel.setAttribute('value', "These are the fields in this form:"); 326 | 327 | tabbox.setAttribute('id', 'sidebarformtabbox'); 328 | //we only want to put things in a clean box. 329 | if (box.childNodes.length !== 0) { 330 | for (var i = 0; i < box.childNodes.length; i++) { 331 | box.removeChild(box.childNodes[i]); 332 | } 333 | } 334 | 335 | // create the form UI 336 | // Note that the addition of the DOM is seperated from the creation of 337 | // it in the hopes that it will make for a faster overall operation 338 | // even though it does require a bit more work in the code. This is 339 | // based on Mossop(David Townshed)'s advice. 340 | if (maindoc.forms.length !== 0){ 341 | var attackStringContainer = getAttackStringContainer(); 342 | attackStringContainer.init(); 343 | 344 | var newTabs = []; 345 | var newTabForms= []; 346 | var newTabPanels = []; 347 | var newTabActions = []; 348 | var newTabPanelVbox = []; 349 | 350 | for (var i = 0; i < maindoc.forms.length; i++){ 351 | 352 | var aForm = maindoc.forms[i]; 353 | var formname = null; 354 | var formPanel = document.createElement("tabpanel"); 355 | var fieldsWithUI = new Object(); 356 | var formTab = document.createElement("tab"); 357 | 358 | dump(q++ + "\n"); 359 | 360 | // Since the name attribute is deprecated for the form tag we first 361 | // check the id attribute, then the name attribute and then consider 362 | // it unnamed. 363 | if (aForm.id){ 364 | formname = aForm.id; 365 | } 366 | else if (aForm.name){ 367 | formname = aForm.name; 368 | } 369 | else { 370 | formname = "Unnamed form " + (++unnamedFormCounter); 371 | } 372 | 373 | formTab.setAttribute("label", formname); 374 | 375 | dump('aForm.elements.length: ' + aForm.elements.length +'\n'); 376 | 377 | //iterate through the forms and generate the DOM. 378 | if (aForm.elements.length !== 0){ 379 | for (var n = 0; n < aForm.elements.length; n++){ 380 | var sidebarElement = null; 381 | dump('aForm.elements[' + n + '] = ' +aForm.elements[n] + 382 | '- ' + aForm.elements[n].id +'\n'); 383 | if (aForm.elements[n].name){ 384 | sidebarElement = 385 | fieldsWithUI[aForm.elements[n].name] = 386 | createFieldUI(aForm.elements[n], n); 387 | } 388 | else if (aForm.elements[n].id){ 389 | sidebarElement = 390 | fieldsWithUI[aForm.elements[n].id] = 391 | createFieldUI(aForm.elements[n], n ); 392 | } 393 | else { 394 | sidebarElement = 395 | fieldsWithUI["form" + n + "_"+ 396 | Math.round(Math.random() * 10000000)] = 397 | createFieldUI(aForm.elements[n], n); 398 | } 399 | sidebarElement = sidebarElement.getElementsByAttribute('editable', 'true')[0]; 400 | this.syncSidebarToForm(sidebarElement, aForm.elements[n]); 401 | 402 | } 403 | 404 | } 405 | 406 | var actionButtons = this.createActionUI(); 407 | newTabs.push(formTab); 408 | newTabForms.push(fieldsWithUI); 409 | newTabPanels.push(formPanel); 410 | newTabActions.push(actionButtons); 411 | newTabPanelVbox.push(document.createElement("vbox")); 412 | 413 | } 414 | 415 | /* the order of the below is very important. If the order is 416 | changed then not only will the display change but some things 417 | will break (certain attributes are checked only by grandparents 418 | on addition to the DOM, ex. selected). */ 419 | 420 | //Add the form UI to the DOM. 421 | for (var i = newTabs.length-1; i >= 0; i--) { 422 | 423 | for each(var fieldUI in newTabForms[i]) { 424 | sidebarBuilder.add(newTabPanelVbox[i], fieldUI, selectFirstMenuItemForField); 425 | } 426 | 427 | /* the order from here ...*/ 428 | sidebarBuilder.add(newTabActions[i].box, 429 | newTabActions[i].menulist); 430 | 431 | sidebarBuilder.add(newTabActions[i].menulist, 432 | newTabActions[i].menupopup); 433 | 434 | for each(var mi in newTabActions[i].menuitems){ 435 | //newTabActions[i].menupopup.appendChild(mi); 436 | sidebarBuilder.add(newTabActions[i].menupopup, mi); 437 | } 438 | 439 | /* to here is particularly crucial and annoying */ 440 | 441 | sidebarBuilder.add(newTabActions[i].box, 442 | newTabActions[i].button); 443 | sidebarBuilder.add(newTabPanelVbox[i], 444 | newTabActions[i].box); 445 | sidebarBuilder.add(newTabPanels[i], newTabPanelVbox[i]); 446 | sidebarBuilder.add(tabs, newTabs[i]); 447 | sidebarBuilder.add(tabpanels, newTabPanels[i]); 448 | } 449 | 450 | 451 | sidebarBuilder.add(tabbox, tabpanels); 452 | sidebarBuilder.add(tabbox, tabs); 453 | 454 | } 455 | else { 456 | 457 | var noformPanel = document.createElement("tabpanel"); 458 | var noformTab = document.createElement("tab"); 459 | var labelinpanel = document.createElement("label"); 460 | var noformPanelVbox = document.createElement("vbox"); 461 | 462 | labelinpanel.setAttribute("value", "Sorry, this page has no forms."); 463 | 464 | noformTab.setAttribute("label", "No Forms"); 465 | 466 | sidebarBuilder.add(tabs, noformTab); 467 | sidebarBuilder.add(tabpanels, noformPanel); 468 | sidebarBuilder.add(noformPanel, noformPanelVbox); 469 | sidebarBuilder.add(noformPanelVbox, labelinpanel); 470 | sidebarBuilder.add(tabbox, tabpanels); 471 | sidebarBuilder.add(tabbox, tabs); 472 | 473 | } 474 | 475 | sidebarBuilder.add(box, tabbox); 476 | 477 | sidebarBuilder.start(); 478 | 479 | } 480 | , 481 | addAllMainWindowEventListeners: function() { 482 | 483 | var mainWindow = getMainWindow(); 484 | var ourCaller = this; 485 | this.windowEventClosure = function(){ourCaller.do_generate_form_ui()}; 486 | mainWindow.getBrowser().tabContainer. 487 | addEventListener("TabSelect", 488 | this.windowEventClosure, false); 489 | 490 | this.plistener = new sqlimeProgressListener( 491 | this.windowEventClosure); 492 | 493 | mainWindow.document.getElementById('content'). 494 | addProgressListener(this.plistener, 495 | Components.interfaces.nsIWebProgress.NOTIFY_STATE_DOCUMENT); 496 | 497 | this.sidebarBuilderPauseObserver = new Xss_PrefObserver(watchSidebarBuilderPausePref); 498 | 499 | var prefService = Components.classes['@mozilla.org/preferences-service;1']. 500 | getService(Components.interfaces.nsIPrefService); 501 | 502 | var branch = prefService.getBranch(''); 503 | 504 | var observableBranch = branch. 505 | QueryInterface(Components.interfaces.nsIPrefBranch2); 506 | 507 | observableBranch.addObserver('extensions.sqlime.sidebarbuildingstop', 508 | this.sidebarBuilderPauseObserver, false); 509 | 510 | } 511 | , 512 | removeAllMainWindowEventListeners: function (){ 513 | var mainWindow = getMainWindow(); 514 | 515 | mainWindow.document.getElementById('content'). 516 | removeProgressListener(this.plistener); 517 | 518 | if (this.windowEventClosure) { 519 | mainWindow.getBrowser().tabContainer. 520 | removeEventListener('TabSelect', 521 | this.windowEventClosure, 522 | false); 523 | this.windowEventListenerClosure = null; 524 | } 525 | var prefService = Components.classes['@mozilla.org/preferences-service;1']. 526 | getService(Components.interfaces.nsIPrefService); 527 | 528 | var branch = prefService.getBranch(''); 529 | 530 | var observableBranch = branch. 531 | QueryInterface(Components.interfaces.nsIPrefBranch2); 532 | 533 | observableBranch.removeObserver('extensions.sqlime.sidebarbuildingstop', 534 | this.sidebarBuilderPauseObserver) 535 | 536 | } 537 | , 538 | getPreferredNumberOfAttacks: function(){ 539 | var prefs = Components.classes["@mozilla.org/preferences-service;1"]. 540 | getService(Components.interfaces.nsIPrefService); 541 | var branch = prefs.getBranch("extensions.sqlime."); 542 | return branch.getIntPref("prefnumattacks"); 543 | } 544 | , 545 | /** 546 | * This function does two things: 547 | * 1. Checks if we can run a test 548 | * 2. Preps the browser for testing (changing prefs, etc.) 549 | * @returns true if we can test, false otherwise. 550 | */ 551 | preTest: function() { 552 | var rv = false; 553 | if (this.warningDialog === null){ 554 | rv = true; 555 | 556 | var prefService = Components. 557 | classes['@mozilla.org/preferences-service;1']. 558 | getService(Components.interfaces.nsIPrefService); 559 | var branch = prefService.getBranch(""); 560 | for each (var prefInfo in __sqli_me_prefs_to_disable) { 561 | var origValue; 562 | var errorState = false; 563 | switch(prefInfo.type){ 564 | case 'bool': 565 | try { 566 | origValue = branch.getBoolPref(prefInfo.name); 567 | branch.setBoolPref(prefInfo.name, prefInfo.ourValue); 568 | } 569 | catch(e){ 570 | Components.utils.reportError(e +' with '+ prefInfo.name); 571 | errorState = true; 572 | } 573 | break; 574 | case 'int': 575 | try { 576 | origValue = branch.getIntPref(prefInfo.name); 577 | branch.setIntPref(prefInfo.name, prefInfo.ourValue); 578 | } 579 | catch(e){ 580 | Components.utils.reportError(e + ' with '+ prefInfo.name); 581 | errorState = true 582 | } 583 | break; 584 | } 585 | 586 | if (!errorState) { 587 | 588 | var backupPref = { 589 | 'name': prefInfo.name, 590 | 'type': prefInfo.type, 591 | 'origValue': origValue}; 592 | 593 | this.prefs.push(backupPref); 594 | } 595 | } 596 | 597 | } 598 | return rv; 599 | 600 | } 601 | , 602 | postTest: function(){ 603 | this.warningDialog.close(); 604 | this.warningDialog = null; 605 | var prefService = Components. 606 | classes['@mozilla.org/preferences-service;1']. 607 | getService(Components.interfaces.nsIPrefService); 608 | var branch = prefService.getBranch(""); 609 | for each(var backupPref in this.prefs) { 610 | switch(backupPref.type){ 611 | case 'bool': 612 | try { 613 | branch.setBoolPref(backupPref.name, backupPref.origValue); 614 | } 615 | catch(e){ 616 | Components.utils.reportError(e +'with '+ backupPref.name); 617 | } 618 | break; 619 | case 'int': 620 | try { 621 | branch.setIntPref(backupPref.name, backupPref.origValue); 622 | } 623 | catch(e){ 624 | Components.utils.reportError(e + 'with '+ backupPref.name); 625 | } 626 | break; 627 | } 628 | } 629 | 630 | this.prefs.splice(0, this.prefs.length); 631 | } 632 | , 633 | calculateWorseCaseNumTestsToRun: function(testType, fieldsToTest) { 634 | 635 | var rv = 0; 636 | 637 | var numFieldsToTest = fieldsToTest.length; 638 | 639 | if (testType.heuristicTest) { 640 | 641 | var numTestChars = this.getHeuristicTestChars().length; 642 | 643 | rv += numFieldsToTest * numTestChars; 644 | 645 | } 646 | 647 | rv += numFieldsToTest*testType.count*2; // *2 because there are both DOM and string tests to run 648 | Components.utils.reportError("worse case num tests = ("+numFieldsToTest+"*" +numTestChars+"+"+numFieldsToTest+ "*"+ testType.count+") = "+ 649 | "("+ (numFieldsToTest*numTestChars) +"+"+ (numFieldsToTest*testType.count)+") = " +((numFieldsToTest*numTestChars) + (numFieldsToTest*testType.count))+ " = " + rv); 650 | return rv; 651 | 652 | } 653 | , 654 | /** 655 | * Notify's the warningDialog (if it exists) that it should change its 656 | * state to notify them 657 | */ 658 | generatingReport: function(){ 659 | if (this.warningDialog && this.warningDialog.closed === false) { 660 | this.warningDialog.generatingReport(); 661 | } 662 | } 663 | , 664 | /** 665 | * Called by the testmanager and resultsmanager to report that a test has 666 | * been completed so that the popup's UI can be updated 667 | */ 668 | finishedTest: function() { 669 | Components.utils.reportError("foo"); 670 | if (this.warningDialog.closed === false && typeof(this.warningDialog.finishedTest) == 'function') { 671 | this.warningDialog.finishedTest(); 672 | } 673 | else if (typeof(this.warningDialog.finishedTest) != 'function') { 674 | Components.utils.reportError('warning dialog\'s finished test function is missing.'); 675 | } 676 | } 677 | } 678 | 679 | 680 | /** 681 | * This function takes a form returns an associative array (Object object) of 682 | * field name => field UI pairs (with the UI being appropriate for plugging 683 | * into a tabpanel for display. Recursive. 684 | * @param form a form 685 | * @param fields 686 | * @returns an associative array (Object) of field name => field UI pairs 687 | */ 688 | function getFormFieldsUI(aForm, allFields) { 689 | var fields = allFields ? allFields : new Object(); 690 | 691 | for (var child in aForm.elements){ 692 | dump('examining child: ' + child + " " + child.nodeName+"\n"); 693 | if (isFormField(child)){ 694 | if (!fields[child.name]){ //We don't want a million option UIs 695 | // even if there are a million 696 | // options 697 | var childUI = createFieldUI(child); 698 | fields[child.name] = childUI; 699 | } 700 | dump(child.nodeName + "is a form field\n"); 701 | } 702 | else { 703 | dump(child.nodeName + "is NOT a form field\n"); 704 | fields = getForFieldsUI(child, fields); 705 | } 706 | } 707 | 708 | return fields; 709 | } 710 | /** 711 | * generate the ui for one form field. 712 | * Another option is to use XBL but it really doesn't seem to be worth 713 | * the effort 714 | * @param node a form field 715 | * @param elementIndex the index of the element in the form's elements array. 716 | * @returns the root of the ui for a form field (a groupbox). 717 | */ 718 | function createFieldUI(node, elementIndex){ 719 | 720 | // var uid = Math.round(Math.random() * 100000000000); 721 | dump("creating field ui\n"); 722 | var root = document.createElement("groupbox"); 723 | root.setAttribute("flex", 0); 724 | 725 | var caption = document.createElement("caption"); 726 | 727 | if (node.name){ 728 | caption.setAttribute("label", node.name); 729 | } 730 | else if(node.id){ 731 | caption.setAttribute("label", node.id); 732 | } 733 | 734 | var hbox = document.createElement("hbox"); 735 | dump("creating field ui...\n"); 736 | var checkbox = document.createElement("checkbox"); 737 | checkbox.className = "nolabel"; 738 | checkbox.setAttribute('formElementIndex', elementIndex); 739 | 740 | var menulist = document.createElement("menulist"); 741 | menulist.setAttribute("editable", true); 742 | 743 | dump("creating field ui.......\n"); 744 | var menupopup = document.createElement("menupopup"); 745 | 746 | var firstMenuItem = document.createElement("menuitem"); 747 | if (node.value && node.value.length){ 748 | firstMenuItem.setAttribute("label", node.value); 749 | } 750 | else { 751 | firstMenuItem.setAttribute("label", 752 | "Change this to the value you want tested"); 753 | } 754 | firstMenuItem.setAttribute("selected", true); 755 | 756 | menupopup.appendChild(firstMenuItem); 757 | 758 | dump("creating field ui............................\n"); 759 | var attackStringContainer = getAttackStringContainer(); 760 | var attacks = attackStringContainer.getStrings(); 761 | for (var i = 0; i < attacks.length; i++){ 762 | var aMenuItem = document.createElement("menuitem"); 763 | aMenuItem.setAttribute('label', attacks[i].string); 764 | aMenuItem.setAttribute('width', '100'); 765 | aMenuItem.setAttribute('crop', 'end'); 766 | menupopup.appendChild(aMenuItem); 767 | dump("menupopup childnodes length: " + menupopup.childNodes.length+"\n"); 768 | } 769 | 770 | menulist.appendChild(menupopup); 771 | menulist.selectedIndex = 0; 772 | 773 | hbox.appendChild(checkbox); 774 | hbox.appendChild(menulist); 775 | 776 | root.appendChild(caption); 777 | root.appendChild(hbox); 778 | dump("creating field ui................................................\n"); 779 | return root; 780 | 781 | } 782 | 783 | /** 784 | * This function checks whether the passed in DOMNode is form field or some 785 | * other type of tag. 786 | * @param node the node to check 787 | * @returns true if the elemenet is a form field, false otherwise 788 | */ 789 | function isFormField(node){ 790 | 791 | switch (node.tagName.toLowerCase()){ 792 | case "input": 793 | case "option": 794 | case "button": 795 | case "textarea": 796 | case "submit": 797 | return true; 798 | default: 799 | return false; 800 | } 801 | } 802 | 803 | /** 804 | * Watches the sidebar builder pause time preference and sets 805 | */ 806 | function watchSidebarBuilderPausePref(subject, topic, data) { 807 | var prefService = Components.classes['@mozilla.org/preferences-service;1']. 808 | getService(Components.interfaces.nsIPrefService); 809 | var branch = prefService.getBranch('extensions.sqlime.'); 810 | 811 | getSidebarBuilder().time = branch.getIntPref('sidebarbuildingstop'); 812 | } 813 | /** 814 | * This function is used to make sure that the first tab panel is selected 815 | * in a tabbox 816 | * @param parent the tabbox 817 | * @param child the tabpanels element 818 | */ 819 | function ensureFirstTabPanelIsSelected(parent, child) { 820 | parent.selectedIndex= parent._tabpanels.selectedIndex = 0; 821 | } 822 | 823 | /** 824 | * This function is used to make sure that first child of the menu drop down 825 | * box. 826 | * @param parent 827 | * @param child menu list box. 828 | */ 829 | function ensureFirstChildOfMenuBox(parent, child) { 830 | parent.selectedIndex = 0; 831 | dump('changing index.\n') 832 | } 833 | 834 | /** 835 | * Selects the first item in a menubox. Used with the retun value of 836 | * createFieldUI. 837 | * @param parent 838 | * @param child the groupbox holding a field's UI as returned by createFieldUI() 839 | */ 840 | function selectFirstMenuItemForField(parent, child) { 841 | 842 | dump("child.childNodes[1].childNodes[1].selectedIndex" + child.childNodes[1].childNodes[1].selectedIndex + " " + typeof(child.childNodes[1].childNodes[1].selectedIndex) + " "+ child.childNodes[1].childNodes[1].nodeName + "\n"); 843 | child.childNodes[1].childNodes[1].selectedIndex = 1; 844 | dump("child.childNodes[1].childNodes[1].selectedIndex" + child.childNodes[1].childNodes[1].selectedIndex + " " + typeof(child.childNodes[1].childNodes[1].selectedIndex) + " "+ child.childNodes[1].childNodes[1].nodeName + "\n"); 845 | dump('changing fieldUI Index\n') 846 | 847 | } 848 | -------------------------------------------------------------------------------- /content/sqlime_sidebar.xul: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 30 | 116 | 117 | -------------------------------------------------------------------------------- /content/sqlimeevaluators.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * sqlimeevaluators.js 25 | * This file holds a number of JS evaluators 26 | * @require Results.js 27 | * @require ErrorStringContainer.js 28 | */ 29 | 30 | /** 31 | * Checks the source of a page for stored error strings 32 | */ 33 | function checkSrcForErrorString(streamListener) { 34 | 35 | var errorContainer = getErrorStringContainer(); 36 | var results = new Array(); 37 | var doc = streamListener.data; 38 | var stringEncoder = getHTMLStringEncoder(); 39 | dump("\nStart freeze..."); 40 | for each (var error in errorContainer.getStrings()){ 41 | var result; 42 | 43 | if (doc.indexOf(error.string) !== -1) { 44 | result = new Result(RESULT_TYPE_ERROR, 100, "Error string found: '" + stringEncoder.encodeString(error.string) + "'"); 45 | } 46 | else { 47 | result = new Result(RESULT_TYPE_PASS, 100, "Error string not found: '" + stringEncoder.encodeString(error.string) + "'"); 48 | } 49 | 50 | results.push(result); 51 | } 52 | dump("\nEnd freeze..."); 53 | 54 | 55 | return results; 56 | } 57 | 58 | /** 59 | * Checks the browser for stored error strings. 60 | */ 61 | function checkForErrorString(browser) { 62 | 63 | var errorContainer = getErrorStringContainer(); 64 | var results = new Array(); 65 | var doc = browser.contentDocument.toString(); 66 | var stringEncoder = getHTMLStringEncoder(); 67 | dump("\nStart freeze..."); 68 | for each (var error in errorContainer.getStrings()){ 69 | var result; 70 | 71 | if (doc.indexOf(error.string) !== -1) { 72 | result = new Result(RESULT_TYPE_ERROR, 100, "Error string found: '" + stringEncoder.encodeString(error.string) + "'"); 73 | } 74 | else { 75 | result = new Result(RESULT_TYPE_PASS, 100, "Error string not found: '" + stringEncoder.encodeString(error.string) + "'"); 76 | } 77 | 78 | results.push(result); 79 | } 80 | dump("\nEnd freeze..."); 81 | 82 | 83 | return results; 84 | } 85 | 86 | function checkForServerResponseCode(streamListener){ 87 | var nsiHttpChannel = streamListener.attackRunner.channel.QueryInterface(Components.interfaces.nsIHttpChannel); 88 | var stringEncoder = getHTMLStringEncoder(); 89 | try{ 90 | if ((nsiHttpChannel.responseStatus === undefined || nsiHttpChannel.responseStatus === null)){ 91 | return null; 92 | } 93 | else { 94 | var result; 95 | var responseCode = nsiHttpChannel.responseStatus; 96 | var displayString = "Server Status Code: " + stringEncoder.encodeString(responseCode.toString()) + " " + 97 | stringEncoder.encodeString(nsiHttpChannel.responseStatusText); 98 | if (responseCode == 200){ 99 | result = new Result(RESULT_TYPE_PASS, 100, displayString ); 100 | } 101 | else { 102 | result = new Result(RESULT_TYPE_ERROR, 100, displayString); 103 | } 104 | } 105 | return [result]; 106 | } 107 | catch(err){ 108 | Components.utils.reportError(err); 109 | return []; 110 | } 111 | } -------------------------------------------------------------------------------- /content/tabbrowsermanager.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * tabbrowsermanager.js 25 | * Much of this system relies on working with the tab browser. This file 26 | * encapsulates all that functionality. 27 | */ 28 | 29 | /** 30 | * Captures information about the target page from the browser in the foreground tab, 31 | * since the user may change the state of that browser while the tests are in progress. 32 | * @param browser a browser pointed at the page that the test battery will be run against 33 | * @return a (new) TabManager object for use with the current test battery 34 | */ 35 | function TabManager(browser){ 36 | 37 | // Cache the URL, referrer and postdata of the browser, for access via loadTargetPage(). 38 | // Cache its contentDocument as a basis for comparison, to ensure other browsers have loaded correctly. 39 | this.targetContentDocument = browser.contentDocument; 40 | this.targetPagePostData = null; 41 | var sh = browser.sessionHistory; 42 | if (sh.count) { 43 | var currentEntry = sh.getEntryAtIndex((sh.index), false); 44 | if (currentEntry.postData) { 45 | var postDataStream = Components.classes["@mozilla.org/scriptableinputstream;1"] 46 | .createInstance(Components.interfaces.nsIScriptableInputStream); 47 | postDataStream.init(currentEntry.postData); 48 | // Supposedly it's bad to retrieve all postData at once, 49 | // in case there's a lot of it, because other pseudothreads can't interrupt? 50 | var buffer = null; 51 | while (foo = postDataStream.read(512)) { 52 | this.targetPostData += buffer; 53 | } 54 | } 55 | this.targetPage = currentEntry.URI.spec; 56 | this.targetPageReferrer = currentEntry.referrerURI || null; 57 | } 58 | else { 59 | this.targetPage = browser.webNavigation.currentURI.spec; 60 | this.targetPageReferrer = null; 61 | } 62 | 63 | // Extract a list of the forms on the page. 64 | this.tabForms = new Array(); 65 | var forms = browser.docShell.document.forms; 66 | for (var i = 0; i < forms.length; i++) { 67 | this.tabForms[i] = new Array(); 68 | this.tabForms[i].elements ={}; 69 | this.tabForms[i].elements.length = forms[i].elements.length; 70 | this.tabForms[i].action = forms[i].action ? forms[i].action : browser.contentDocument. 71 | location.toString(); 72 | this.tabForms[i].method = forms[i].method; 73 | 74 | for (var j = 0; j < forms[i].elements.length; j++) { 75 | var elem = forms[i].elements[j]; 76 | var elemToUse = {}; 77 | elemToUse.nodeName = elem.nodeName; 78 | elemToUse.name = elem.name; 79 | switch (elem.nodeName.toLowerCase()) { 80 | case 'submit': 81 | case 'reset': 82 | case 'image': 83 | case 'button': 84 | case 'fieldset': 85 | this.tabForms[i].push({}); 86 | this.tabForms[i].elements[elem.name] = this.tabForms[i]. 87 | elements[j] = {}; 88 | break; 89 | case 'checkbox': 90 | case 'radio': 91 | elemToUse.checked = elem.checked; 92 | elemToUse.name = elem.name 93 | this.tabForms[i].push(elemToUse); 94 | this.tabForms[i].elements[elemToUse.name] = this.tabForms[i]. 95 | elements[j] = elemToUse; 96 | break; 97 | default: 98 | elemToUse.value = elem.value; 99 | elemToUse.name = elem.name 100 | this.tabForms[i].push(elemToUse); 101 | this.tabForms[i].elements[elemToUse.name] = this.tabForms[i]. 102 | elements[j] = elemToUse; 103 | } 104 | } 105 | if (! this.tabForms[forms[i].name]){ 106 | this.tabForms[forms[i].name] = this.tabForms[i]; 107 | } 108 | } 109 | 110 | this.index = browser.webNavigation.sessionHistory.index; 111 | } 112 | 113 | TabManager.prototype = { 114 | /** 115 | * Point a browser at the target page recorded by this TabManager. 116 | * @param browser the browser to point to the target page 117 | */ 118 | loadTargetPage: function (browser) { 119 | browser.webNavigation.loadURI(this.targetPage, 0, this.targetPageReferrer, this.targetPagePostData, null); 120 | } 121 | , 122 | writeTabForms: function(forms, testFormIndex, testFieldIndex, testData){ 123 | dump('-=-=-=-writeTabForms::forms ' + forms[0]); 124 | if (forms[testFormIndex] === undefined){ 125 | dump('got an undefined\n'); 126 | } 127 | dump('&& and the test form is : '+forms[testFormIndex]+ ' with '+ 128 | forms[testFormIndex].elements.length+'elements\n'); 129 | for (var formIndex = 0; 130 | formIndex < forms.length; 131 | formIndex++) 132 | { 133 | for (var elementIndex = 0; 134 | elementIndex < forms[formIndex].elements.length; 135 | elementIndex++) 136 | { 137 | var element = forms[formIndex].elements[elementIndex]; 138 | dump('checking whether this field ('+formIndex + ',' +elementIndex +')should be loaded with an evil value: ' + (formIndex === testFormIndex && elementIndex === testFieldIndex) + '\n'); 139 | if (formIndex !== null && 140 | formIndex === testFormIndex && 141 | elementIndex === testFieldIndex && 142 | testData !== null 143 | ) 144 | { 145 | dump('going to force element ' +element.name +' ('+ elementIndex 146 | +') to have value ' + testData+ '\n'); 147 | if(element.nodeName.toLowerCase() === 'select') { 148 | var newOption = forms[formIndex].ownerDocument.createElement('option'); 149 | newOption.setAttribute('value', testData.string); 150 | newOption.innerHTML = testData.string; 151 | element.options[element.options.length] = newOption; 152 | element.selectedIndex = element.options.length - 1; 153 | } 154 | else { 155 | element.value = testData.string; 156 | } 157 | dump('element[' + elementIndex + '] has value' + 158 | element.value + ' \n'); 159 | } 160 | else if (element.nodeName.toLowerCase() == 'submit' || 161 | element.nodeName.toLowerCase() == 'reset' || 162 | element.nodeName.toLowerCase() == 'image' || 163 | element.nodeName.toLowerCase() == 'button') 164 | { 165 | // don't care, this is here just to make sure the elements 166 | // are parallel. 167 | } 168 | else if (element.nodeName.toLowerCase() == 'checkbox' || 169 | element.nodeName.toLowerCase() == 'radio') 170 | { 171 | element.checked = this.tabForms[formIndex][elementIndex]; 172 | } 173 | else { 174 | element.value = this.tabForms[formIndex][elementIndex]; 175 | } 176 | } 177 | } 178 | } 179 | , 180 | getTabData: function(testFormIndex, testFieldIndex, testString){ 181 | var rv = new Array(); 182 | var formIndex = testFormIndex; 183 | var forms = this.tabForms; 184 | for (var elementIndex = 0; 185 | elementIndex < forms[formIndex].elements.length; 186 | elementIndex++) 187 | { 188 | var element = forms[formIndex].elements[elementIndex]; 189 | var fieldInfo = new Object(); 190 | fieldInfo.name = element.name; 191 | fieldInfo.data = (elementIndex == testFieldIndex && testString)?testString:element.value; 192 | fieldInfo.tested = (elementIndex == testFieldIndex); 193 | rv.push(fieldInfo); 194 | } 195 | return rv; 196 | } 197 | , 198 | /** 199 | * This returns the data in a form 200 | */ 201 | getFormDataForURL: function(testFormIndex, testFieldIndex, 202 | testData) 203 | { 204 | var formIndex = testFormIndex; 205 | var rv = ''; 206 | var forms = this.tabForms; 207 | for (var elementIndex = 0; 208 | elementIndex < forms[testFormIndex].elements.length; 209 | elementIndex++) 210 | { 211 | var element = forms[testFormIndex].elements[elementIndex]; 212 | if (rv.length != 0){ 213 | rv+='&'; 214 | } 215 | 216 | if (elementIndex == testFieldIndex) { 217 | rv += element.name +'='+testData; 218 | } 219 | else if (element.value) { 220 | rv += element.name +'='+element.value; 221 | } 222 | else if (element.checked !== undefined ) { 223 | rv += element + '=' + element.checked?1:0; 224 | } 225 | } 226 | return rv; 227 | 228 | } 229 | }; -------------------------------------------------------------------------------- /content/util.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2007 Security Compass 3 | 4 | This file is part of SQL Inject Me. 5 | 6 | SQL Inject Me is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | SQL Inject Me is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with SQL Inject Me. If not, see . 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * util.js 25 | * Utility Functions. 26 | */ 27 | 28 | const EXTENSION_NAME = 'xssme@security.compass'; 29 | 30 | /** 31 | * This takes a string of a piece of encoded XML and decodes it. 32 | * Specifically, this checks checks for encoded nested ]]> code. 33 | * Note: No XML parsing or checking is done. 34 | * @param xmlString 35 | * @returns a decoded string of a piece of XML (same piece) 36 | */ 37 | function decodeXML(xmlString) { 38 | 39 | var regex = ']]]]>'; 41 | 42 | return xmlString.replace(regex, replaced, 'gm'); 43 | 44 | } 45 | 46 | /** 47 | * This takes a string of a piece of XML and decodes it. 48 | * Specifically, this checks checks for nested ']]>' code. 49 | * Note: No XML parsing or checking is done. 50 | * @param xmlString 51 | * @returns an encoded string of a piece of XML (same piece) 52 | */ 53 | function encodeXML(xmlString) { 54 | 55 | var regex = ']]>'; 56 | var replaced = ']]]]>. 18 | 19 | If you have any questions regarding SQL Inject Me please contact 20 | tools@securitycompass.com 21 | */ 22 | 23 | /** 24 | * NOTE: in this file all uses of the keyword *this* refer to the window. 25 | * We're modifying this window so that other windows (e.g. the sidebar) can 26 | * interact with it directly. 27 | */ 28 | 29 | /** 30 | * whiletestruns.js 31 | * Holding JS code for whiletestruns.xul 32 | */ 33 | function OK(){ 34 | 35 | var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"] 36 | .getService(Components.interfaces.nsIPromptService); 37 | var rv = false; 38 | 39 | rv = prompts.confirmEx(null, 40 | "Are you sure you want to close this window?", 41 | "Are you sure you want to close this window? It's useful to " + 42 | "remind you not to use the testing window. Also closing this window will NOT stop the tests.", 43 | prompts.STD_YES_NO_BUTTONS, "", "", "", null, new Object()); 44 | 45 | return !rv; 46 | 47 | } 48 | 49 | /** 50 | * This function is called when a test is finished 51 | */ 52 | this.finishedTest = function() { 53 | this.numTestsComplete++; 54 | if (this.numTestsComplete > this.maxNumTests) { 55 | Components.utils.reportError('Too many tests have been completed'); 56 | } 57 | } 58 | 59 | this.clearNumTests = function() { 60 | this.numTestsComplete = 0; 61 | } 62 | 63 | this.updateUI = function() { 64 | 65 | this.bar.value = this.numTestsComplete / this.maxNumTests * 100 66 | this.span.innerHTML = this.numTestsComplete.toString() + '/' + this.maxNumTests.toString(); 67 | 68 | } 69 | 70 | this.startThoroughTesting = function(numVulnerableFields) { 71 | this.bar.value = 100; 72 | this.span.innerHTML = this.maxNumTests.toString() + '/' + this.maxNumTests.toString(); 73 | 74 | this.bar = document.getElementById('thoroughBar'); 75 | this.span = document.getElementById('thoroughTestCount'); 76 | 77 | this.maxNumTests = 2*numVulnerableFields*this.testType.count; 78 | this.numTestsComplete = 0; 79 | 80 | //document.getElementById('heuristicsComplete').style.visibility = 'visible'; 81 | } 82 | 83 | function onUnLoad() { 84 | //alert(this.numTestsComplete + ' of ' +this.maxNumTests); 85 | this.bar = null; 86 | this.span = null; 87 | } 88 | 89 | /** 90 | * called when the page loads 91 | */ 92 | function onLoad() { 93 | this.clearNumTests(); 94 | window.centerWindowOnScreen(); 95 | this.maxNumTests = window.arguments[0]; 96 | this.testType = window.arguments[1]; 97 | this.bar = null; 98 | this.span = null; 99 | 100 | if (this.testType.heuristicTest) { 101 | document.getElementById('heuristicTestingBox').style.visibility = 'visible'; 102 | //document.getElementById('heuristicsComplete').style.visibility = 'hidden'; 103 | this.bar = document.getElementById('heuristicBar'); 104 | this.span = document.getElementById('heuristicTestCount'); 105 | } 106 | else { 107 | this.bar = document.getElementById('thoroughBar'); 108 | this.span = document.getElementById('thoroughTestCount'); 109 | } 110 | 111 | //update UI every 1/5 second 112 | window.setInterval(this.updateUI, 200); 113 | } 114 | 115 | function generatingReport() { 116 | document.getElementById('duringTest').style.visibility = 'collapse'; 117 | document.getElementById('generatingReport').style.visibility = 'visible'; 118 | } 119 | -------------------------------------------------------------------------------- /content/whiletestruns.xul: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 18 | 39 |