├── chrome.manifest
├── content
├── AttackHttpResponseObserver.js
├── AttackRunner.js
├── FieldResult.js
├── PrefObserver.js
├── Results.js
├── ResultsManager.js
├── TestManager.js
├── TestRunnerContainer.js
├── XSS-strings.xml
├── about.xul
├── addAttack.js
├── addAttack.xul
├── addError.js
├── attackStringContainer.js
├── io.js
├── json.js
├── overlay.js
├── overlay.xul
├── preferenceStringContainer.js
├── preferences.fx2.js
├── preferences.fx3.js
├── preferences.js
├── preferences.xul
├── progressListener.js
├── results.html
├── sidebarBuilder.js
├── tabbrowsermanager.js
├── util.js
├── whiletestruns.js
├── whiletestruns.xul
├── xssme_StreamListener.js
├── xssme_sidebar.js
├── xssme_sidebar.xul
└── xssmeevaluators.js
├── defaults
└── preferences
│ └── xssme.js
├── gpl-3.0.txt
├── install.rdf
├── locale
└── en-US
│ ├── overlay.dtd
│ ├── prefwindow.dtd
│ ├── xssme.dtd
│ └── xssme.properties
├── readme.txt
└── skin
├── overlay.css
├── preferences.css
├── small_logo_sc.png
├── tiny_logo.png
├── toolbar-button.png
├── whiletestruns.css
└── xssme_sidebar.css
/chrome.manifest:
--------------------------------------------------------------------------------
1 | content xssme content/
2 | locale xssme en-US locale/en-US/
3 | skin xssme classic/1.0 skin/
4 | overlay chrome://browser/content/browser.xul chrome://xssme/content/overlay.xul
5 | style chrome://global/content/customizeToolbar.xul chrome://xssme/skin/overlay.css
6 | # *SHOCK* Fx2 and Fx3 are have a moderately different API here's some overriding
7 | override chrome://xssme/content/preferences.js chrome://xssme/content/preferences.fx2.js appversion<3.0
8 | override chrome://xssme/content/preferences.js chrome://xssme/content/preferences.fx3.js appversion>=3.0
9 |
10 |
--------------------------------------------------------------------------------
/content/AttackHttpResponseObserver.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 |
37 | QueryInterface: function(iid) {
38 | if (iid.equals(Components.interfaces.nsIObserver) ||
39 | iid.equals(Components.interfaces.nsISupports))
40 | {
41 | return this;
42 | }
43 |
44 | throw Components.results.NS_ERROR_NO_INTERFACE;
45 | },
46 |
47 | observe: function(subject, topic, data) {
48 |
49 | if (topic == AttackHttpResponseObserver_topic){
50 | try {
51 | this.resultsManager.gotChannelForAttackRunner(subject.
52 | QueryInterface(Components.interfaces.nsIHttpChannel),
53 | this.attackRunner);
54 | }
55 | catch(err) {
56 | dump('AttackHttpResponseObserver::observe: ' + err + '\n');
57 | }
58 | }
59 |
60 | }
61 |
62 | };
--------------------------------------------------------------------------------
/content/AttackRunner.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 | * uniqueID is important for heuristic tests which need a random string in
38 | * order to find the char they sent
39 | */
40 | this.uniqueID = Math.floor(Date.now() * Math.random());
41 |
42 | }
43 |
44 | AttackRunner.prototype = {
45 | testData: null
46 | ,
47 | submitForm: function(browser, formIndex){
48 | var forms = browser.webNavigation.document.forms;
49 | var formFound = false;
50 | for (var i = 0; i < forms.length && !formFound; i++){
51 | if (i == formIndex){
52 | dump('submitting form ... ' + i + ' ' + (i == formIndex) + '\n');
53 | if (forms[i].target) forms[i].target = null;
54 | forms[i].submit();
55 | formFound = true;
56 | }
57 | //debug code..
58 | else {
59 | dump('this form is not it... ' + i + ' ' + (i == formIndex) + '\n');
60 | }
61 | }
62 | return formFound;
63 | }
64 | ,
65 | /**
66 | * Begin an individual test.
67 | * @param formPanel currently unused
68 | * @param formIndex index, in the list of forms, of the one being tested
69 | * @param field the field to inject
70 | * @param testValue the input containing the injection
71 | * @param resultsManager evaluates the results of the test
72 | * @param tabWrapper contains the tab to run the test in
73 | * @param tabManager provides information about the target page
74 | */
75 | do_test: function(formPanel, formIndex, field, testValue, resultsManager,
76 | tabWrapper, tabManager)
77 | {
78 | var wroteTabData = false;
79 | var self = this; //make sure we always have a reference to this object
80 | var browser = tabWrapper.tab.linkedBrowser;
81 |
82 | this.testValue = testValue;
83 | this.formIndex = formIndex;
84 | this.fieldIndex = field.index;
85 | this.field = field;
86 | browser.webNavigation.stop(Components.interfaces.nsIWebNavigation.STOP_ALL);
87 |
88 | setTimeout(function() {afterWorkTabStopped()}, 10);
89 |
90 | function afterWorkTabStopped(){
91 | browser.addEventListener('pageshow',
92 | afterWorkTabHasLoaded, false);
93 | tabManager.loadTargetPage(browser);
94 | }
95 |
96 | function afterWorkTabHasLoaded(event) {
97 |
98 | var formData = null;
99 | browser.removeEventListener('pageshow',
100 | afterWorkTabHasLoaded, false);
101 |
102 | var loadSuccessful = compareContentDocuments(tabManager.targetContentDocument, browser.contentDocument)
103 |
104 | if (loadSuccessful === false) {
105 | getTestManager().cannotRunTests();
106 | return;
107 | }
108 |
109 | //this will copy all the form data...
110 | try {
111 | if (field)
112 | {
113 | tabManager.writeTabForms(browser.contentDocument.
114 | forms, formIndex, field.index, testValue);
115 | formData = tabManager.getFormDataForURL(browser.
116 | contentDocument.forms, formIndex, field.index,
117 | testValue);
118 | }
119 | else
120 | {
121 | tabManager.writeTabForms(browser.contentDocument.
122 | forms, formIndex, null, null);
123 | formData = tabManager.getFormDataForURL(browser.
124 | contentDocument.forms, formIndex, null, null);
125 | }
126 | }
127 | catch(e) {
128 | Components.utils.reportError(e + " " + (browser.webNavigation.currentURI?browser.webNavigation.currentURI.spec:"null"))
129 | }
130 | dump('AttackRunner::afterWorkTabHasLoaded testValue===' + testValue + '\n');
131 |
132 |
133 | self.testData = tabManager.getTabData(browser.
134 | contentDocument.forms, formIndex, field.index);
135 |
136 | self.do_source_test(formPanel, formIndex, field, testValue,
137 | resultsManager, browser,
138 | formData);
139 |
140 | //if (window.navigator.platform.match("win", "i")) {
141 | browser.addEventListener('pageshow',
142 | afterWorkTabHasSubmittedAndLoaded, false);
143 | //}
144 | //else {
145 | // setTimeout(function(){browser.addEventListener('pageshow',
146 | // afterWorkTabHasSubmittedAndLoaded, false)}, 0);
147 | //}
148 |
149 |
150 | var formGotSubmitted = self.submitForm(browser, formIndex);
151 |
152 | }
153 |
154 | //this should fire only *after* the form has been sumbitted and the new
155 | //page has loaded.
156 | function afterWorkTabHasSubmittedAndLoaded(event){
157 |
158 | browser.removeEventListener('pageshow', afterWorkTabHasSubmittedAndLoaded, false);
159 | var results = resultsManager.evaluate(event.currentTarget, self);
160 | /* @todo this should be moved to resultsmanager */
161 | for each (result in results){
162 | tabManager.addFieldData(result);
163 | }
164 | tabWrapper.inUse = false;
165 |
166 |
167 | }
168 |
169 |
170 |
171 | }
172 | ,
173 | do_source_test:function(formPanel, formIndex, field, testValue,
174 | resultsManager, browser, formData)
175 | {
176 | // the IO service
177 | var ioService = Components.classes['@mozilla.org/network/io-service;1']
178 | .getService(Components.interfaces.nsIIOService);
179 | var formURL = browser.contentDocument.URL;
180 | var form = browser.contentDocument.forms[formIndex];
181 | var formAction = form.action ? form.action : browser.contentDocument.
182 | location.toString();
183 |
184 | dump('AttackRunner::do_source_test formAction=== '+formAction+'\n');
185 | if (form.method.toLowerCase() != 'post'){
186 | formAction += formAction.indexOf('?') === -1 ? '?' : '&';
187 | formAction += formData;
188 | }
189 |
190 | dump('attackrunner::do_source_test::formAction == ' + formAction + '\n');
191 | dump('attackrunner::do_source_test::formData == ' + formData + '\n');
192 |
193 | var uri = ioService.newURI(formAction, null, null);
194 | var referingURI = ioService.newURI(formURL, null, null);
195 | var channel = ioService.newChannelFromURI(uri);
196 | channel.QueryInterface(Components.interfaces.nsIHttpChannel).
197 | referrer = referingURI;
198 |
199 | if (form.method.toLowerCase() == 'post'){
200 | var inputStream = Components.
201 | classes['@mozilla.org/io/string-input-stream;1'].
202 | createInstance(Components.interfaces.nsIStringInputStream);
203 | inputStream.setData(formData, formData.length);
204 | channel.QueryInterface(Components.interfaces.nsIUploadChannel).
205 | setUploadStream(inputStream,
206 | 'application/x-www-form-urlencoded', -1);
207 | channel.QueryInterface(Components.interfaces.nsIHttpChannel).
208 | requestMethod = 'POST';
209 | }
210 |
211 | var streamListener = new StreamListener(this, resultsManager);
212 | streamListener.testData = this.testData;
213 | resultsManager.addSourceListener(streamListener);
214 |
215 | channel.asyncOpen(streamListener, null);
216 |
217 | }
218 |
219 | }
220 |
--------------------------------------------------------------------------------
/content/FieldResult.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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(field){
32 | this.field = field;
33 | this.results = new Array();
34 | this.maxValue = 0;
35 | this.maxValueType = 0;
36 | this.state = 0;
37 | }
38 |
39 | /**
40 | * These consts are used to check what kind of rsults does this fieldresult
41 | * have.
42 | */
43 | const fieldresult_has_pass = 0x0001;
44 | const fieldresult_has_warn = 0x0002;
45 | const fieldresult_has_error = 0x0004;
46 |
47 | FieldResult.prototype = {
48 | addResults: function (resultsToAdd) {
49 |
50 | for each(var result in resultsToAdd) {
51 | if (this.maxValueType < result.type){
52 | this.maxValue = result.value;
53 | this.maxValueType = result.type;
54 | }
55 | else if (this.maxValueType === result.type ) {
56 | if (this.maxValue < result.value) {
57 | this.maxValue = result.value;
58 | }
59 | }
60 | this.state = this.state | result.type;
61 | this.results.push(result);
62 | }
63 | }
64 | ,
65 | count: function(){
66 | var numTestsRun = 0;
67 | var numPasses = 0;
68 | var numWarnings = 0;
69 | var numFailes = 0;
70 | for each(var r in this.results) {
71 | numTestsRun++;
72 | switch(r.type){
73 | case RESULT_TYPE_ERROR:
74 | numFailes++;
75 | break;
76 | case RESULT_TYPE_WARNING:
77 | numWarnings++;
78 | break;
79 | case RESULT_TYPE_PASS:
80 | numPasses++;
81 | break;
82 | }
83 | }
84 | return [numTestsRun, numFailes, numWarnings, numPasses];
85 | }
86 | ,
87 | getSubmitState: function(){
88 | return this.results[0].testData;
89 | }
90 | ,
91 | sort: function(){
92 | var errors = new Array();
93 | var warnings = new Array();
94 | var passes = new Array();
95 |
96 | for each(var result in this.results) {
97 | switch(result.type){
98 | case RESULT_TYPE_ERROR:
99 | errors.push(result);
100 | break;
101 | case RESULT_TYPE_WARNING:
102 | warnings.push(result);
103 | break;
104 | case RESULT_TYPE_PASS:
105 | passes.push(result);
106 | break;
107 | }
108 | }
109 |
110 | return this.results = errors.concat(warnings, passes);
111 | }
112 | }
--------------------------------------------------------------------------------
/content/PrefObserver.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 | dump('Result::Ctor (' + type+ ' ' + value+ ' ' + message + '\n');
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/content/TestManager.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2008 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 | * @param heuristicTestChars a string, the characters to inject
54 | */
55 | runTest: function (testType, fieldsToTest, tabManager, heuristicTestChars) {
56 | this.testType = testType;
57 |
58 | this.clear();
59 |
60 | this.fieldsToTest = fieldsToTest;
61 | this.heuristicTestChars = heuristicTestChars;
62 | this.tabManager = tabManager;
63 |
64 | if (testType.heuristicTest) {
65 | this.waitingForHeuristicTests = true;
66 | this.runHeuristicTest();
67 | }
68 | else {
69 | this.runThoroughTest(testType, fieldsToTest);
70 | }
71 | }
72 | ,
73 | /**
74 | * This is a function that AttackRunner requires its resultsmanager to have
75 | */
76 | addSourceListener: function(sourceListener, attackRunner) {
77 |
78 | }
79 | ,
80 | /**
81 | * called by testRunners to report their results
82 | * @param browser a browser instance with the results
83 | * @param
84 | */
85 | evaluate: function(browser, attackRunner) {
86 |
87 | }
88 | ,
89 | /**
90 | * called by a streamlistener to report the results of a source test
91 | * @param streamListener the streamListener that is reporting the results
92 | */
93 | evaluateSource: function(streamListener) {
94 |
95 | var resultData = streamListener.data;
96 | var testValue = streamListener.attackRunner.testValue;
97 |
98 | if (resultData.indexOf(testValue.string) !== -1) {
99 | var vulnerableField = streamListener.attackRunner.field;
100 | var isVulnerablFieldAlreadyLogged = false;
101 | if (this.vulnerableFields.length > 0) {
102 | for each (var value in this.vulnerableFields) {
103 | var areFormIndexsSame = value.formIndex === vulnerableField.formIndex;
104 | if (areFormIndexsSame) {
105 | var areFieldsSame = value.index === vulnerableField.index;
106 | if (areFieldsSame) {
107 | value.vulnerableChars += testValue.string[testValue.string.length-1];
108 | isVulnerablFieldAlreadyLogged = true;
109 | break;
110 | }
111 | }
112 | }
113 | }
114 |
115 | if (isVulnerablFieldAlreadyLogged === false) {
116 | streamListener.attackRunner.field.vulnerableChars = testValue.string[testValue.string.length-1];
117 | this.vulnerableFields.push(streamListener.attackRunner.field);
118 | }
119 |
120 | }
121 |
122 | this.controller.finishedTest();
123 |
124 | this.resultsStillExpected--;
125 | }
126 | ,
127 | /**
128 | * Runs the heuristic tests.
129 | */
130 | runHeuristicTest: function() {
131 | var self = this;
132 | var testRunnerContainer = getTestRunnerContainer();
133 |
134 | testRunnerContainer.clear();
135 |
136 | for each (var c in this.heuristicTestChars) {
137 | for each (var field in this.fieldsToTest) {
138 | var testRunner = new AttackRunner();
139 |
140 | var testValue = new Object();
141 | testValue.string = testRunner.uniqueID.toString() + c.toString();
142 |
143 | this.resultsStillExpected++;
144 |
145 | testRunnerContainer.addTestRunner(testRunner,
146 | null,
147 | field.formIndex,
148 | field,
149 | testValue,
150 | self);
151 |
152 | }
153 | }
154 |
155 | getTestRunnerContainer(getMainWindow().document.
156 | getElementById('content').mTabs.length, self);
157 |
158 | if (testRunnerContainer.keepChecking === false) {
159 | testRunnerContainer.keepChecking = true;
160 | }
161 |
162 | testRunnerContainer.start(this.tabManager);
163 | }
164 | ,
165 | /**
166 | * runs non-heuristic tests on the fields.
167 | * @param testType with all strings or just the top strings.
168 | * @param vulnerableFields fields painted by the heuristic tests
169 | */
170 | runThoroughTest: function(testType, vulnerableFields) {
171 |
172 | this.resultsManager = new ResultsManager(this.controller);
173 |
174 | this.resultsManager.addEvaluator(checkForVulnerableElement);
175 | this.resultsManager.addSourceEvaluator(checkForExactAttackText);
176 |
177 | getTestRunnerContainer().clear();
178 | var testStrings = getAttackStringContainer().getStrings();
179 | var numberOfTests;
180 | if (testType.allTests)
181 | numberOfTests = testStrings.length;
182 | else {
183 | numberOfTests = this.controller.getPreferredNumberOfAttacks();
184 | }
185 |
186 | for each (var field in vulnerableFields) {
187 |
188 | for (var n = 0; n < numberOfTests && testStrings[n]; n++) {
189 |
190 | var testRunner = new AttackRunner();
191 | this.resultsManager.registerAttack(testRunner);
192 |
193 | getTestRunnerContainer().addTestRunner(testRunner, null,
194 | field.formIndex, field, testStrings[n],
195 | this.resultsManager);
196 |
197 | }
198 |
199 | }
200 |
201 | var self = this;
202 | var testRunnerContainer = getTestRunnerContainer(getMainWindow().
203 | document.getElementById('content').mTabs.length, self);
204 |
205 | if (testRunnerContainer.keepChecking === false) {
206 | testRunnerContainer.keepChecking = true;
207 | }
208 | testRunnerContainer.start(this.tabManager);
209 |
210 | }
211 | ,
212 | /**
213 | * this is called by the testRunnerContainer when all tests are definitely
214 | * complete.
215 | */
216 | doneTesting: function() {
217 | var self = this;
218 | function checkAgain() {
219 | self.doneTesting();
220 | }
221 | if (this.waitingForHeuristicTests === true) {
222 |
223 | if (this.resultsStillExpected === 0) {
224 | this.waitingForHeuristicTests = false;
225 | if (this.vulnerableFields.length > 0) {
226 | this.waitingForHeuristicTests = false;
227 | function doRunThoroughTests(){
228 | getTestRunnerContainer().clearWorkTabs();
229 | self.controller.warningDialog.startThoroughTesting(self.vulnerableFields.length, self.testType);
230 | self.runThoroughTest(self.testType, self.vulnerableFields);
231 | }
232 | window.setTimeout(doRunThoroughTests, 0);
233 | }
234 | else {
235 | this.resultsManager = new ResultsManager(self.controller)
236 | this.resultsManager.showResults(this);
237 | getTestRunnerContainer().clearWorkTabs();
238 | this.controller.postTest();
239 | }
240 | }
241 | else {
242 | window.setTimeout(checkAgain, 1);
243 | }
244 | }
245 | else if (this.controller) {
246 | if (this.resultsManager.allResultsLogged === false){
247 | dump('\nnot done yet...');
248 | window.setTimeout(checkAgain, 100);
249 | //Components.utils.reportError('results not all logged yet');
250 | return
251 | }
252 | getTestRunnerContainer().clearWorkTabs();
253 | this.resultsManager.showResults(this);
254 | this.controller.postTest();
255 | }
256 |
257 | }
258 | ,
259 | /**
260 | * clears the object and makes it ready for use for a new set of tests.
261 | */
262 | clear: function() {
263 | this.resultsManager = null;
264 |
265 | this.vulnerableFields.splice(0,this.vulnerableFields.length);
266 |
267 | }
268 | ,
269 | /**
270 | * Called when an AttackRunner cannot test because it is in an error state.
271 | */
272 | cannotRunTests: function() {
273 | getTestRunnerContainer().stop();
274 | getTestRunnerContainer().clearWorkTabs();
275 |
276 | var resultsManager = null;
277 | if (this.resultsManager) {
278 | resultsManager = this.resultsManager;
279 | }
280 | else {
281 | resultsManager = new ResultsManager(this.controller);
282 | }
283 | resultsManager.showResults(this, "There was an error while testing this site. This was likely due to Mozilla bug 420025. 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 and hope to have this fixed soon.");
284 | this.controller.postTest();
285 |
286 | Components.utils.reportError(
287 | 'The loading of this page in a work tab as not successful: ' +
288 | getMainHTMLDoc().documentURI);
289 | }
290 | }
291 |
292 | /**
293 | * The getInstance method for the TestManager singleton
294 | */
295 | function getTestManager(controller) {
296 | if (typeof(xssme__testmanager__) == 'undefined' ||
297 | !xssme__testmanager__)
298 | {
299 | xssme__testmanager__ = new TestManager();
300 | }
301 | // @todo: there has to be a better way...
302 | if (controller) {
303 | xssme__testmanager__.controller = controller;
304 | }
305 |
306 | return xssme__testmanager__;
307 | }
308 |
309 |
--------------------------------------------------------------------------------
/content/TestRunnerContainer.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 |
60 | // Do we have any more tests to run?
61 | if (!this.testRunners.length) {
62 | this.keepChecking = false;
63 | this.testManager.doneTesting();
64 | return;
65 | }
66 |
67 | // Begin the next test in the first available tab and move that tab to the back of the queue.
68 | for (var i = 0; i < this.tabWrappers.length; i++) {
69 | if (!this.tabWrappers[i].inUse) {
70 | this.tabWrappers[i].inUse = true;
71 | this.testRunners.pop().do_test(this.formPanels.pop(),
72 | this.formIndexes.pop(),
73 | this.fields.pop(),
74 | this.testValues.pop(),
75 | this.resultsManagers.pop(),
76 | this.tabWrappers[i],
77 | tabManager);
78 | this.tabWrappers.push(this.tabWrappers.splice(i, 1)[0]);
79 | break;
80 | }
81 | }
82 |
83 | var self = this;
84 | setTimeout(function() { self.start(tabManager); }, 1);
85 | }
86 | ,
87 | numWorkTabs: 6
88 | ,
89 | getNumWorkTabs: function(){
90 | var prefService = Components.classes['@mozilla.org/preferences-service;1'].
91 | getService(Components.interfaces.nsIPrefService);
92 | var branch = prefService.getBranch('extensions.xssme.');
93 | if (branch.prefHasUserValue('numtabstouse') ){
94 | return branch.getIntPref('numtabstouse');
95 | }
96 | else {
97 | return this.numWorkTabs;
98 | }
99 | }
100 | ,
101 | clear: function (){
102 | this.testRunners.splice(0, this.testRunners.length);
103 | this.formPanels.splice(0, this.formPanels.length);
104 | this.formIndexes.splice(0, this.formPanels.length);
105 | this.fields.splice(0, this.formPanels.length);
106 | this.testValues.splice(0, this.formPanels.length);
107 | this.resultsManagers.splice(0, this.formPanels.length);
108 | //if (this.tabWrappers)
109 | // this.tabWrappers.splice(0, this.tabWrappers.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: getMainWindow().document.getElementById('content').addTab('about:blank')
123 | };
124 | }
125 | }
126 | ,
127 | clearWorkTabs: function () {
128 | for (var i = 0; i < this.tabWrappers.length; i++)
129 | getMainWindow().gBrowser.removeTab(this.tabWrappers[i].tab);
130 | }
131 | ,
132 | /**
133 | * Stops the running of tests in the TestRunnerContainer.
134 | */
135 | stop: function(){
136 | this.keepChecking = false;
137 | this.clear();
138 | }
139 | };
140 |
141 | /**
142 | * If currentNumTabs is provided, the container is cleared.
143 | */
144 | function getTestRunnerContainer(currentNumTabs, testManager){
145 |
146 | if (typeof(xssme__testrunnercontainer__) == 'undefined' ||
147 | !xssme__testrunnercontainer__ )
148 | {
149 | xssme__testrunnercontainer__ = new TestRunnerContainer();
150 | }
151 |
152 | if (currentNumTabs && testManager) {
153 | xssme__testrunnercontainer__.setup(testManager);
154 |
155 | }
156 |
157 | return xssme__testrunnercontainer__;
158 |
159 | }
--------------------------------------------------------------------------------
/content/XSS-strings.xml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SecurityCompass/XSSMe/1e87473220231ceb135c5d9eab6570b45fd693eb/content/XSS-strings.xml
--------------------------------------------------------------------------------
/content/about.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
41 |
--------------------------------------------------------------------------------
/content/addAttack.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 |
52 |
--------------------------------------------------------------------------------
/content/addError.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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/attackStringContainer.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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.xssme.');
42 | this.prefDefaultBranch = this.prefService.getDefaultBranch('extensions.xssme.')
43 | if (this.prefBranch.prefHasUserValue('attacks')){
44 | attackStrings = this.prefBranch.getCharPref('attacks');
45 | this.strings = JSON.parse(attackStrings);
46 | }
47 | else {
48 | var ioService = Components.classes["@mozilla.org/network/io-service;1"].
49 | getService(Components.interfaces.nsIIOService);
50 | var chromeURL = ioService.
51 | newURI("chrome://xssme/content/XSS-strings.xml", null, null);
52 |
53 | var chromeRegistry = Components.classes["@mozilla.org/chrome/chrome-registry;1"]
54 | .getService(Components.interfaces.nsIChromeRegistry);
55 | var defaultAttacksURL= chromeRegistry.convertChromeURL(chromeURL);
56 | var defaultAttacksChannel= ioService.newChannelFromURI(defaultAttacksURL);
57 | var defaultAttacksXML = FileIO.readChannel(defaultAttacksChannel, null);
58 |
59 |
60 | importAttackFromXMLString(defaultAttacksXML, this);
61 |
62 | }
63 |
64 | };
65 | AttackStringContainer.prototype.save = function() {
66 | this.prefBranch.setCharPref('attacks', JSON.stringify(this.strings));
67 |
68 | }
69 |
70 |
71 | function getAttackStringContainer(){
72 | if (typeof(attackStringContainer) === 'undefined' || !attackStringContainer){
73 | attackStringContainer = new AttackStringContainer();
74 | }
75 | return attackStringContainer;
76 | }
77 |
--------------------------------------------------------------------------------
/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.stringify( GIVEN_JAVASCRIPT_OBJECT );
51 | * var newJavaScriptObject = JSON.parse( 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.stringify
64 |
65 | // If canonical parser is installed, don't bother
66 | if ( typeof( JSON ) === "undefined" || !JSON ) {
67 | JSON = {
68 | /**
69 | * Converts a JavaScript object into a JSON string.
70 | *
71 | * @param aJSObject is the object to be converted
72 | * @param aKeysToDrop is an optional array of keys which will be
73 | * ignored in all objects during the serialization
74 | * @return the object's JSON representation
75 | *
76 | * Note: aJSObject MUST not contain cyclic references.
77 | */
78 | stringify: function JSON_toString(aJSObject, aKeysToDrop) {
79 | // these characters have a special escape notation
80 | const charMap = { "\b": "\\b", "\t": "\\t", "\n": "\\n", "\f": "\\f",
81 | "\r": "\\r", '"': '\\"', "\\": "\\\\" };
82 |
83 | // we use a single string builder for efficiency reasons
84 | var pieces = [];
85 |
86 | // this recursive function walks through all objects and appends their
87 | // JSON representation (in one or several pieces) to the string builder
88 | function append_piece(aObj) {
89 | if (typeof aObj == "boolean") {
90 | pieces.push(aObj ? "true" : "false");
91 | }
92 | else if (typeof aObj == "number" && isFinite(aObj)) {
93 | // there is no representation for infinite numbers or for NaN!
94 | pieces.push(aObj.toString());
95 | }
96 | else if (typeof aObj == "string") {
97 | aObj = aObj.replace(/[\\"\x00-\x1F\u0080-\uFFFF]/g, function($0) {
98 | // use the special escape notation if one exists, otherwise
99 | // produce a general unicode escape sequence
100 | return charMap[$0] ||
101 | "\\u" + ("0000" + $0.charCodeAt(0).toString(16)).slice(-4);
102 | });
103 | pieces.push('"' + aObj + '"')
104 | }
105 | else if (aObj === null) {
106 | pieces.push("null");
107 | }
108 | // if it looks like an array, treat it as such - this is required
109 | // for all arrays from either outside this module or a sandbox
110 | else if (aObj instanceof Array ||
111 | typeof aObj == "object" && "length" in aObj &&
112 | (aObj.length === 0 || aObj[aObj.length - 1] !== undefined)) {
113 | pieces.push("[");
114 | for (var i = 0; i < aObj.length; i++) {
115 | append_piece(aObj[i]);
116 | pieces.push(",");
117 | }
118 | if (pieces[pieces.length - 1] == ",")
119 | pieces.pop(); // drop the trailing colon
120 | pieces.push("]");
121 | }
122 | else if (typeof aObj == "object") {
123 | pieces.push("{");
124 | for (var key in aObj) {
125 | // allow callers to pass objects containing private data which
126 | // they don't want the JSON string to contain (so they don't
127 | // have to manually pre-process the object)
128 | if (aKeysToDrop && aKeysToDrop.indexOf(key) != -1)
129 | continue;
130 |
131 | append_piece(key.toString());
132 | pieces.push(":");
133 | append_piece(aObj[key]);
134 | pieces.push(",");
135 | }
136 | if (pieces[pieces.length - 1] == ",")
137 | pieces.pop(); // drop the trailing colon
138 | pieces.push("}");
139 | }
140 | else {
141 | throw new TypeError("No JSON representation for this object!");
142 | }
143 | }
144 | append_piece(aJSObject);
145 |
146 | return pieces.join("");
147 | },
148 |
149 | /**
150 | * Converts a JSON string into a JavaScript object.
151 | *
152 | * @param aJSONString is the string to be converted
153 | * @return a JavaScript object for the given JSON representation
154 | */
155 | parse: function JSON_fromString(aJSONString) {
156 | if (!this.isMostlyHarmless(aJSONString))
157 | throw new SyntaxError("No valid JSON string!");
158 |
159 | var s = new Components.utils.Sandbox("about:blank");
160 | return Components.utils.evalInSandbox("(" + aJSONString + ")", s);
161 | },
162 |
163 | /**
164 | * Checks whether the given string contains potentially harmful
165 | * content which might be executed during its evaluation
166 | * (no parser, thus not 100% safe! Best to use a Sandbox for evaluation)
167 | *
168 | * @param aString is the string to be tested
169 | * @return a boolean
170 | */
171 | isMostlyHarmless: function JSON_isMostlyHarmless(aString) {
172 | const maybeHarmful = /[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/;
173 | const jsonStrings = /"(\\.|[^"\\\n\r])*"/g;
174 |
175 | return !maybeHarmful.test(aString.replace(jsonStrings, ""));
176 | }
177 | };
178 | }
--------------------------------------------------------------------------------
/content/overlay.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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.xssme.');
32 | var showContextMenu = true; //default
33 |
34 | if (branch.prefHasUserValue('showcontextmenu')) {
35 | showContextMenu = branch.getBoolPref('showcontextmenu');
36 | }
37 |
38 | var contextMenu = document.getElementById('xssmecontextmenu');
39 | contextMenu.setAttribute('collapsed', !showContextMenu);
40 | }
41 |
42 | function XssOverlay() {}
43 |
44 | XssOverlay.prototype = {
45 | contextMenuObserver: null
46 | ,
47 | onLoad: function() {
48 |
49 | var prefService = Components.classes['@mozilla.org/preferences-service;1'].
50 | getService(Components.interfaces.nsIPrefService);
51 |
52 | var branch = prefService.getBranch('');
53 |
54 | var observableBranch = branch.
55 | QueryInterface(Components.interfaces.nsIPrefBranch2);
56 |
57 | this.contextMenuObserver = new Xss_PrefObserver(checkContextMenu);
58 |
59 | checkContextMenu();
60 |
61 | dump('mainwindow::onLoad contextMenuObserver ==' + this.contextMenuObserver +'\n');
62 |
63 |
64 | observableBranch.addObserver('extensions.xssme.showcontextmenu', this.contextMenuObserver, false);
65 | }
66 | ,
67 | onUnload: function() {
68 | dump('XssOverlay::onUnload this.contextMenuObserver' + this.contextMenuObserver + '\n');
69 | //Do nothing right now.
70 | var prefService = Components.classes['@mozilla.org/preferences-service;1'].
71 | getService(Components.interfaces.nsIPrefService);
72 |
73 | var branch = prefService.getBranch('');
74 |
75 | var observableBranch = branch.
76 | QueryInterface(Components.interfaces.nsIPrefBranch2);
77 |
78 | observableBranch.removeObserver('extensions.xssme.showcontextmenu', this.contextMenuObserver)
79 | }
80 | };
81 |
82 | var xssOverlay = new XssOverlay();
83 |
84 | window.addEventListener('load', xssOverlay.onLoad, false);
85 | window.addEventListener('unload', xssOverlay.onUnload, false);
86 |
--------------------------------------------------------------------------------
/content/overlay.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
26 |
27 |
28 |
29 |
30 |
38 |
39 |
40 |
47 |
48 |
49 |
50 |
51 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/content/preferenceStringContainer.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | /**
24 | * preferenceStringContainer.js
25 | * requires JSON.
26 | */
27 |
28 |
29 | /**
30 | * the PreferenceStringContainer object is a base class for any kind of object
31 | * which has deal with an array of strings held in preferences.
32 | * (e.g. AttackStringContainer, ResultStringContainer).
33 | */
34 | function PreferenceStringContainer() {
35 | this.strings = Array();
36 | this.prefBranch = null;
37 | this.prefService = Components.classes['@mozilla.org/preferences-service;1'].
38 | getService(Components.interfaces.nsIPrefService);
39 | }
40 | dump('creating... preferenceStringContainer object\n');
41 | PreferenceStringContainer.prototype = {
42 | /**
43 | * init is responsible for reading and loading a preference into
44 | */
45 | init: function() {
46 |
47 | }
48 | ,
49 | getStrings: function(force){
50 | if (force === true){
51 | this.init();
52 | }
53 | return this.strings;
54 | }
55 | ,
56 | addString: function(string, signature) {
57 | dump('PreferenceStringContainer::addString: ' + string+ ' ' + signature + '\n');
58 | if (!string) {
59 | return false;
60 | }
61 |
62 | var preference = new Object();
63 | preference.string = string;
64 | preference.sig = signature;
65 | if (this.strings.every(checkUnique, preference)){
66 | this.strings.push(preference);
67 | this.save();
68 | return true;
69 | }
70 | else {
71 | return false;
72 | }
73 | }
74 | ,
75 | /**
76 | * save is responsible for taking this.strings and saving it into
77 | * preferences.
78 | */
79 | save: function() {
80 | }
81 | ,
82 | swap: function (index1, index2){
83 | if (typeof(this.strings[index1]) === "undefined" ||
84 | this.strings[index1] === null ||
85 | typeof(this.strings[index2]) === "undefined" ||
86 | this.strings[index2] === null)
87 | {
88 | return false;
89 | }
90 |
91 | [this.strings[index2], this.strings[index1]] =
92 | [this.strings[index1], this.strings[index2]]
93 |
94 | this.save();
95 |
96 | return true;
97 | }
98 | };
99 |
100 | /**
101 | * used by addString to ensure that a given (in this.string) is not in the
102 | * container
103 | */
104 | function checkUnique(element, index, array){
105 | dump("checkunique: " + (this.string) + " " + (element.string) + " \n");
106 | dump("checkunique: " + (this.string != element.string) + " \n");
107 | return this.string != element.string;
108 | }
109 |
--------------------------------------------------------------------------------
/content/preferences.fx2.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | /**
24 | * prefereneces.js
25 | * @requires JSON
26 | * @requires AttackStringContainer
27 | * @requires util.js
28 | */
29 | function PreferencesController() {
30 | this.init();
31 | }
32 |
33 | PreferencesController.prototype = {
34 | init: function(){
35 | getAttackStringContainer();
36 |
37 | var attacks = attackStringContainer.getStrings();
38 | if (attacks.length) {
39 | this.makeUI(attacks);
40 | }
41 | else {
42 | var label = document.getElementById('noattackslbl');
43 | label.style.visibility = 'visible';
44 | }
45 | }
46 | ,
47 | makeUI: function(attacks, aWindow){
48 | var theWindow
49 | if (typeof(aWindow) === 'undefined' || !aWindow){
50 | theWindow = window;
51 | }
52 | else {
53 | theWindow = aWindow;
54 | }
55 |
56 | var listbox = theWindow.document.getElementById('existingXSSstrings');
57 | while (listbox.itemCount > 0) {
58 | listbox.removeItemAt(0);
59 | }
60 | for(var i = 0; i < attacks.length; i++){
61 | listbox.appendItem(attacks[i].string, i);
62 | }
63 | }
64 | ,
65 | removeAttack: function(){
66 | this.removeItem(getAttackStringContainer(), 'existingXSSstrings');
67 | }
68 | ,
69 | removeItem: function(container, listboxID){
70 | var listbox = document.getElementById(listboxID);
71 | var selectedAttacks = listbox.selectedItems;
72 | var strings = container.getStrings();
73 | var n = 0;
74 | for (var i = 0; i < selectedAttacks.length; i++){
75 | strings[selectedAttacks[i].value] = null;
76 | }
77 | while (n < strings.length){
78 | if (strings[n] === null){
79 | strings.splice(n, 1);
80 | }
81 | else{
82 | n++; //only incrememnt if attacks[n]!==null. Otherwise we'll
83 | // strings which are adjacent.
84 | }
85 | }
86 | container.save();
87 | this.makeUI(container.getStrings(), window, listboxID);
88 | }
89 | ,
90 | exportAttacks: function(){
91 | var exportDoc = document.implementation.createDocument("", "", null);
92 | var root = exportDoc.createElement('exportedattacks');
93 | var xmlAttacks = exportDoc.createElement('attacks');
94 | getAttackStringContainer();
95 | var attacks = attackStringContainer.getStrings();
96 | for each (var attack in attacks){
97 | var xmlAttack = exportDoc.createElement('attack');
98 | var xmlString = exportDoc.createElement('attackString');
99 | var xmlSig = exportDoc.createElement('signature');
100 | // var txtString = exportDoc.createTextNode('');
101 | var txtSig = exportDoc.createTextNode(attack.sig);
102 | var txtString = exportDoc.createCDATASection(encodeXML(attack.string));
103 | xmlString.appendChild(txtString);
104 | xmlSig.appendChild(txtSig);
105 | xmlAttack.appendChild(xmlString);
106 | xmlAttack.appendChild(xmlSig);
107 | xmlAttacks.appendChild(xmlAttack);
108 | }
109 | root.appendChild(xmlAttacks);
110 | exportDoc.appendChild(root);
111 | var serializer = new XMLSerializer();
112 | var xml = serializer.serializeToString(exportDoc);
113 | dump(xml);dump('\n');
114 |
115 | var nsIFilePicker = Components.interfaces.nsIFilePicker;
116 | var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
117 | picker.init(window, "Select File To Export To", nsIFilePicker.modeSave);
118 | picker.appendFilter("XML Files", '*.xml');
119 | picker.appendFilter("All Files", '*');
120 | picker.defaultExtension = '.xml';
121 |
122 | var resultOfPicker = picker.show();
123 | if (resultOfPicker == nsIFilePicker.returnCancel){
124 | return false;
125 | }
126 | var exportFile = picker.file;
127 |
128 | var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
129 | .createInstance(Components.interfaces.nsIFileOutputStream);
130 |
131 | foStream.init(exportFile, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate
132 | foStream.write(xml, xml.length);
133 | foStream.close();
134 | return true;
135 |
136 | }
137 | ,
138 | importAttacks: function(){
139 | var nsIFilePicker = Components.interfaces.nsIFilePicker;
140 | var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
141 | picker.init(window, "Select File To Import From", nsIFilePicker.modeOpen);
142 | picker.appendFilter("XML Files", '*.xml');
143 | picker.appendFilter("All Files", '*');
144 | var resultOfPicker = picker.show();
145 | if (resultOfPicker == nsIFilePicker.returnCancel){
146 | return false;
147 | }
148 | var importFile = picker.file;
149 | var attackStringContainer = getAttackStringContainer();
150 | importAttacksFromXMLFile(importFile);
151 | this.makeUI(attackStringContainer.getStrings(), window);
152 | return true;
153 | }
154 | ,
155 | moveAttackStringUp: function(){
156 | this.moveItemUp(getAttackStringContainer(), 'existingXSSstrings');
157 | }
158 | ,
159 | moveErrorStringUp: function(){
160 | this.moveItemUp(getErrorStringContainer(), 'existingSQLIerrStrings');
161 | }
162 | ,
163 | moveItemUp: function(container, listboxID){
164 | var listbox = document.getElementById(listboxID);
165 | var selectedIndex = listbox.selectedIndex;
166 | var selectedItemValue = listbox.selectedItem.value
167 | var selectedItemLabel = listbox.selectedItem.label;
168 | if (listbox.selectedItem.previousSibling == null) {
169 | return false;
170 | }
171 | var newValue = listbox.selectedItem.previousSibling.value;
172 |
173 | if (listbox.selectedItems.length != 1){
174 | alert("sorry, only one item can be moved at a time");
175 | return false;
176 | }
177 |
178 | container.swap(listbox.selectedItem.value,
179 | listbox.selectedItem.previousSibling.value);
180 | container.save();
181 |
182 | listbox.ensureIndexIsVisible(selectedIndex - 1);
183 |
184 | listbox.selectedItem.previousSibling.value = selectedItemValue
185 |
186 | listbox.removeItemAt(selectedIndex)
187 | listbox.insertItemAt(selectedIndex-1, selectedItemLabel, newValue)
188 |
189 | listbox.selectedIndex = selectedIndex - 1;
190 | return true;
191 |
192 | }
193 | ,
194 | moveAttackStringDown: function(){
195 | this.moveItemDown(getAttackStringContainer(), 'existingXSSstrings');
196 | }
197 | ,
198 | moveErrorStringDown: function(){
199 | this.moveItemDown(getErrorStringContainer(), 'existingSQLIerrStrings');
200 | }
201 | ,
202 | moveItemDown: function(container, listboxID){
203 |
204 | var listbox = document.getElementById(listboxID);
205 | var selectedIndex = listbox.selectedIndex;
206 | var selectedItem = listbox.selectedItem;
207 |
208 | if (selectedIndex + 1 >= listbox.getRowCount()) {
209 | return true;
210 | }
211 |
212 | var selectedItemValue = listbox.selectedItem.value
213 | var selectedItemLabel = listbox.selectedItem.label;
214 | if (listbox.selectedItem.nextSibling == null) {
215 | return false;
216 | }
217 | var newValue = listbox.selectedItem.nextSibling.value;
218 | if (listbox.selectedItems.length != 1){
219 | alert("sorry, only one item can be moved at a time");
220 | return false;
221 | }
222 |
223 | container.swap(listbox.selectedItem.value, listbox.selectedItem.nextSibling.value);
224 | container.save();
225 |
226 |
227 |
228 | listbox.selectedItem.nextSibling.value = selectedItemValue
229 |
230 | listbox.removeItemAt(selectedIndex)
231 | if (selectedIndex + 1 >= listbox.getRowCount()) {
232 |
233 | listbox.appendChild(selectedItem)
234 | listbox.selectedIndex = selectedIndex = listbox.getRowCount()-1;
235 |
236 | }
237 | else {
238 | listbox.insertItemAt(selectedIndex+1, selectedItemLabel, newValue)
239 | listbox.selectedIndex = ++selectedIndex ;
240 | }
241 |
242 | listbox.ensureIndexIsVisible(selectedIndex );
243 |
244 | return true;
245 |
246 | }
247 | };
248 |
249 |
--------------------------------------------------------------------------------
/content/preferences.fx3.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | /**
24 | * prefereneces.js
25 | * @requires JSON
26 | * @requires AttackStringContainer
27 | * @requires util.js
28 | */
29 | function PreferencesController() {
30 | this.init();
31 | }
32 |
33 | PreferencesController.prototype = {
34 | init: function(){
35 | getAttackStringContainer();
36 |
37 | var attacks = attackStringContainer.getStrings();
38 | if (attacks.length) {
39 | this.makeUI(attacks);
40 | }
41 | else {
42 | var label = document.getElementById('noattackslbl');
43 | label.style.visibility = 'visible';
44 | }
45 | }
46 | ,
47 | makeUI: function(attacks, aWindow){
48 | var theWindow
49 | if (typeof(aWindow) === 'undefined' || !aWindow){
50 | theWindow = window;
51 | }
52 | else {
53 | theWindow = aWindow;
54 | }
55 |
56 | var listbox = theWindow.document.getElementById('existingXSSstrings');
57 | while (listbox.itemCount > 0) {
58 | listbox.removeItemAt(0);
59 | }
60 | for(var i = 0; i < attacks.length; i++){
61 | listbox.appendItem(attacks[i].string, i);
62 | }
63 | }
64 | ,
65 | removeAttack: function(){
66 | this.removeItem(getAttackStringContainer(), 'existingXSSstrings');
67 | }
68 | ,
69 | removeItem: function(container, listboxID){
70 | var listbox = document.getElementById(listboxID);
71 | var selectedAttacks = listbox.selectedItems;
72 | var strings = container.getStrings();
73 | var n = 0;
74 | for (var i = 0; i < selectedAttacks.length; i++){
75 | strings[selectedAttacks[i].value] = null;
76 | }
77 | while (n < strings.length){
78 | if (strings[n] === null){
79 | strings.splice(n, 1);
80 | }
81 | else{
82 | n++; //only incrememnt if attacks[n]!==null. Otherwise we'll
83 | // strings which are adjacent.
84 | }
85 | }
86 | container.save();
87 | this.makeUI(container.getStrings(), window, listboxID);
88 | }
89 | ,
90 | exportAttacks: function(){
91 | var exportDoc = document.implementation.createDocument("", "", null);
92 | var root = exportDoc.createElement('exportedattacks');
93 | var xmlAttacks = exportDoc.createElement('attacks');
94 | getAttackStringContainer();
95 | var attacks = attackStringContainer.getStrings();
96 | for each (var attack in attacks){
97 | var xmlAttack = exportDoc.createElement('attack');
98 | var xmlString = exportDoc.createElement('attackString');
99 | var xmlSig = exportDoc.createElement('signature');
100 | // var txtString = exportDoc.createTextNode('');
101 | var txtSig = exportDoc.createTextNode(attack.sig);
102 | var txtString = exportDoc.createCDATASection(encodeXML(attack.string));
103 | xmlString.appendChild(txtString);
104 | xmlSig.appendChild(txtSig);
105 | xmlAttack.appendChild(xmlString);
106 | xmlAttack.appendChild(xmlSig);
107 | xmlAttacks.appendChild(xmlAttack);
108 | }
109 | root.appendChild(xmlAttacks);
110 | exportDoc.appendChild(root);
111 | var serializer = new XMLSerializer();
112 | var xml = serializer.serializeToString(exportDoc);
113 | dump(xml);dump('\n');
114 |
115 | var nsIFilePicker = Components.interfaces.nsIFilePicker;
116 | var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
117 | picker.init(window, "Select File To Export To", nsIFilePicker.modeSave);
118 | picker.appendFilter("XML Files", '*.xml');
119 | picker.appendFilter("All Files", '*');
120 | picker.defaultExtension = '.xml';
121 |
122 | var resultOfPicker = picker.show();
123 | if (resultOfPicker == nsIFilePicker.returnCancel){
124 | return false;
125 | }
126 | var exportFile = picker.file;
127 |
128 | var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
129 | .createInstance(Components.interfaces.nsIFileOutputStream);
130 |
131 | foStream.init(exportFile, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate
132 | foStream.write(xml, xml.length);
133 | foStream.close();
134 | return true;
135 |
136 | }
137 | ,
138 | importAttacks: function(){
139 | var nsIFilePicker = Components.interfaces.nsIFilePicker;
140 | var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
141 | picker.init(window, "Select File To Import From", nsIFilePicker.modeOpen);
142 | picker.appendFilter("XML Files", '*.xml');
143 | picker.appendFilter("All Files", '*');
144 | var resultOfPicker = picker.show();
145 | if (resultOfPicker == nsIFilePicker.returnCancel){
146 | return false;
147 | }
148 | var importFile = picker.file;
149 | var attackStringContainer = getAttackStringContainer();
150 | importAttacksFromXMLFile(importFile);
151 | this.makeUI(attackStringContainer.getStrings(), window);
152 | return true;
153 | }
154 | ,
155 | moveAttackStringUp: function(){
156 | this.moveItemUp(getAttackStringContainer(), 'existingXSSstrings');
157 | }
158 | ,
159 | moveErrorStringUp: function(){
160 | this.moveItemUp(getErrorStringContainer(), 'existingSQLIerrStrings');
161 | }
162 | ,
163 | moveItemUp: function(container, listboxID){
164 | var listbox = document.getElementById(listboxID);
165 | var selectedIndex = listbox.selectedIndex;
166 | var selectedItemValue = listbox.selectedItem.value
167 | var selectedItemLabel = listbox.selectedItem.label;
168 | if (listbox.selectedItem.previousSibling == null) {
169 | return false;
170 | }
171 | var newValue = listbox.selectedItem.previousSibling.value;
172 | if (listbox.selectedItems.length != 1){
173 | alert("sorry, only one item can be moved at a time");
174 | return false;
175 | }
176 |
177 | container.swap(listbox.selectedItem.value,
178 | listbox.selectedItem.previousSibling.value);
179 | container.save();
180 |
181 | listbox.ensureIndexIsVisible(selectedIndex - 1);
182 |
183 | listbox.selectedItem.previousSibling.value = selectedItemValue
184 |
185 | listbox.removeItemAt(selectedIndex)
186 | listbox.insertItemAt(selectedIndex-1, selectedItemLabel, newValue)
187 |
188 | listbox.selectedIndex = selectedIndex - 1;
189 | return true;
190 |
191 | }
192 | ,
193 | moveAttackStringDown: function(){
194 | this.moveItemDown(getAttackStringContainer(), 'existingXSSstrings');
195 | }
196 | ,
197 | moveErrorStringDown: function(){
198 | this.moveItemDown(getErrorStringContainer(), 'existingSQLIerrStrings');
199 | }
200 | ,
201 | moveItemDown: function(container, listboxID){
202 |
203 | var listbox = document.getElementById(listboxID);
204 | var selectedIndex = listbox.selectedIndex;
205 | var selectedItem = listbox.selectedItem;
206 |
207 | if (selectedIndex + 1 >= listbox.getRowCount()) {
208 | return true;
209 | }
210 |
211 | var selectedItemValue = listbox.selectedItem.value
212 | var selectedItemLabel = listbox.selectedItem.label;
213 | var newValue = listbox.selectedItem.nextSibling.value;
214 | if (listbox.selectedItems.length != 1){
215 | alert("sorry, only one item can be moved at a time");
216 | return false;
217 | }
218 |
219 | container.swap(listbox.selectedItem.value,
220 | listbox.selectedItem.nextSibling.value);
221 | container.save();
222 |
223 | listbox.ensureIndexIsVisible(selectedIndex + 1);
224 |
225 | listbox.selectedItem.nextSibling.value = selectedItemValue
226 |
227 | if (selectedIndex + 2 >= listbox.getRowCount()) {
228 | listbox.selectedItem = listbox.getItemAtIndex(listbox.getRowCount() -1)
229 | Components.utils.reportError("last is going to get moved up")
230 | this.moveItemUp(container, listboxID)
231 | listbox.selectedIndex = listbox.getRowCount() -1
232 | }
233 | else {
234 | listbox.removeItemAt(selectedIndex)
235 | listbox.insertItemAt(selectedIndex+1, selectedItemLabel, newValue)
236 | listbox.selectedIndex = ++selectedIndex
237 | }
238 |
239 | listbox.ensureIndexIsVisible(selectedIndex );
240 |
241 | return true;
242 |
243 | }
244 | };
245 |
246 |
--------------------------------------------------------------------------------
/content/preferences.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | /**
24 | * prefereneces.js
25 | * @requires JSON
26 | * @requires AttackStringContainer
27 | * @requires util.js
28 | */
29 | function PreferencesController() {
30 | this.init();
31 | }
32 |
33 | PreferencesController.prototype = {
34 | init: function(){
35 | getAttackStringContainer();
36 |
37 | var attacks = attackStringContainer.getStrings();
38 | if (attacks.length) {
39 | this.makeUI(attacks);
40 | }
41 | else {
42 | var label = document.getElementById('noattackslbl');
43 | label.style.visibility = 'visible';
44 | }
45 | }
46 | ,
47 | makeUI: function(attacks, aWindow){
48 | var theWindow
49 | if (typeof(aWindow) === 'undefined' || !aWindow){
50 | theWindow = window;
51 | }
52 | else {
53 | theWindow = aWindow;
54 | }
55 |
56 | var listbox = theWindow.document.getElementById('existingXSSstrings');
57 | while (listbox.itemCount > 0) {
58 | listbox.removeItemAt(0);
59 | }
60 | for(var i = 0; i < attacks.length; i++){
61 | listbox.insertItemAt(i, attacks[i].string, i);
62 | }
63 | }
64 | ,
65 | removeAttack: function(){
66 | this.removeItem(getAttackStringContainer(), 'existingXSSstrings');
67 | }
68 | ,
69 | removeItem: function(container, listboxID){
70 | var listbox = document.getElementById(listboxID);
71 | var selectedAttacks = listbox.selectedItems;
72 | var strings = container.getStrings();
73 | var n = 0;
74 | for (var i = 0; i < selectedAttacks.length; i++){
75 | strings[selectedAttacks[i].value] = null;
76 | }
77 | while (n < strings.length){
78 | if (strings[n] === null){
79 | strings.splice(n, 1);
80 | }
81 | else{
82 | n++; //only incrememnt if attacks[n]!==null. Otherwise we'll
83 | // strings which are adjacent.
84 | }
85 | }
86 | container.save();
87 | this.makeUI(container.getStrings(), window, listboxID);
88 | }
89 | ,
90 | exportAttacks: function(){
91 | var exportDoc = document.implementation.createDocument("", "", null);
92 | var root = exportDoc.createElement('exportedattacks');
93 | var xmlAttacks = exportDoc.createElement('attacks');
94 | getAttackStringContainer();
95 | var attacks = attackStringContainer.getStrings();
96 | for each (var attack in attacks){
97 | var xmlAttack = exportDoc.createElement('attack');
98 | var xmlString = exportDoc.createElement('attackString');
99 | var xmlSig = exportDoc.createElement('signature');
100 | // var txtString = exportDoc.createTextNode('');
101 | var txtSig = exportDoc.createTextNode(attack.sig);
102 | var txtString = exportDoc.createCDATASection(encodeXML(attack.string));
103 | xmlString.appendChild(txtString);
104 | xmlSig.appendChild(txtSig);
105 | xmlAttack.appendChild(xmlString);
106 | xmlAttack.appendChild(xmlSig);
107 | xmlAttacks.appendChild(xmlAttack);
108 | }
109 | root.appendChild(xmlAttacks);
110 | exportDoc.appendChild(root);
111 | var serializer = new XMLSerializer();
112 | var xml = serializer.serializeToString(exportDoc);
113 | dump(xml);dump('\n');
114 |
115 | var nsIFilePicker = Components.interfaces.nsIFilePicker;
116 | var picker = Components.classes['@mozilla.org/filepicker;1'].createInstance(nsIFilePicker);
117 | picker.init(window, "Select File To Export To", nsIFilePicker.modeSave);
118 | picker.appendFilter("XML Files", '*.xml');
119 | picker.appendFilter("All Files", '*');
120 | picker.defaultExtension = '.xml';
121 |
122 | var resultOfPicker = picker.show();
123 | if (resultOfPicker == nsIFilePicker.returnCancel){
124 | return false;
125 | }
126 | var exportFile = picker.file;
127 |
128 | var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
129 | .createInstance(Components.interfaces.nsIFileOutputStream);
130 |
131 | foStream.init(exportFile, 0x02 | 0x08 | 0x20, 0666, 0); // write, create, truncate
132 | foStream.write(xml, xml.length);
133 | foStream.close();
134 | return true;
135 |
136 | }
137 | ,
138 | importAttacks: function(){
139 | var nsIFilePicker = Components.interfaces.nsIFilePicker;
140 | var picker = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
141 | picker.init(window, "Select File To Import From", nsIFilePicker.modeOpen);
142 | picker.appendFilter("XML Files", '*.xml');
143 | picker.appendFilter("All Files", '*');
144 | var resultOfPicker = picker.show();
145 | if (resultOfPicker == nsIFilePicker.returnCancel){
146 | return false;
147 | }
148 | var importFile = picker.file;
149 | var attackStringContainer = getAttackStringContainer();
150 | importAttacksFromXMLFile(importFile);
151 | this.makeUI(attackStringContainer.getStrings(), window);
152 | return true;
153 | }
154 | ,
155 | moveAttackStringUp: function(){
156 | this.moveItemUp(getAttackStringContainer(), 'existingXSSstrings');
157 | }
158 | ,
159 | moveErrorStringUp: function(){
160 | this.moveItemUp(getErrorStringContainer(), 'existingSQLIerrStrings');
161 | }
162 | ,
163 | moveItemUp: function(container, listboxID){
164 | var listbox = document.getElementById(listboxID);
165 | var selectedIndex = listbox.selectedIndex;
166 | var selectedItemValue = listbox.selectedItem.value
167 | var selectedItemLabel = listbox.selectedItem.label;
168 | var newValue = listbox.selectedItem.previousSibling.value;
169 | if (listbox.selectedItems.length != 1){
170 | alert("sorry, only one item can be moved at a time");
171 | return false;
172 | }
173 |
174 | container.swap(listbox.selectedItem.value,
175 | listbox.selectedItem.previousSibling.value);
176 | container.save();
177 |
178 | listbox.ensureIndexIsVisible(selectedIndex - 1);
179 |
180 | listbox.selectedItem.previousSibling.value = selectedItemValue
181 |
182 | listbox.removeItemAt(selectedIndex)
183 | listbox.insertItemAt(selectedIndex-1, selectedItemLabel, newValue)
184 |
185 | listbox.selectedIndex = selectedIndex - 1;
186 | return true;
187 |
188 | }
189 | ,
190 | moveAttackStringDown: function(){
191 | this.moveItemDown(getAttackStringContainer(), 'existingXSSstrings');
192 | }
193 | ,
194 | moveErrorStringDown: function(){
195 | this.moveItemDown(getErrorStringContainer(), 'existingSQLIerrStrings');
196 | }
197 | ,
198 | moveItemDown: function(container, listboxID){
199 |
200 | var listbox = document.getElementById(listboxID);
201 | var selectedIndex = listbox.selectedIndex;
202 | var selectedItemValue = listbox.selectedItem.value
203 | var selectedItemLabel = listbox.selectedItem.label;
204 | var newValue = listbox.selectedItem.nextSibling.value;
205 | if (listbox.selectedItems.length != 1){
206 | alert("sorry, only one item can be moved at a time");
207 | return false;
208 | }
209 |
210 | container.swap(listbox.selectedItem.value,
211 | listbox.selectedItem.nextSibling.value);
212 | container.save();
213 |
214 | listbox.ensureIndexIsVisible(selectedIndex + 1);
215 |
216 | listbox.selectedItem.nextSibling.value = selectedItemValue
217 |
218 | listbox.removeItemAt(selectedIndex)
219 | listbox.insertItemAt(selectedIndex+1, selectedItemLabel, newValue)
220 |
221 | listbox.selectedIndex = selectedIndex + 1;
222 | return true;
223 |
224 | }
225 | };
226 |
227 |
--------------------------------------------------------------------------------
/content/preferences.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
28 |
29 |
32 |
36 |
39 |
42 |
45 |
48 |
51 |
52 |
53 |
54 | The higher this value the more cpu time is yielded from generating the side for doing other things (redrawign the screen) but the longer it takes to generate the sidebar.
55 |
56 |
57 |
58 |
59 |
61 |
63 |
65 |
67 |
69 |
71 |
73 |
78 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | IMPORTANT:Please close then open the sidebar (or refresh the current webpage) to make sure that all new attack strings are reloaded.
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
112 |
113 |
--------------------------------------------------------------------------------
/content/progressListener.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 xssmeProgressListener(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 | xssmeProgressListener.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 |
50 |
XSS Me Test Results for http://domain.tld/url.ext
51 |
Here are the results for the 9999 tests run:
52 |
53 |
54 |
Failed:
55 |
56 |
57 |
58 |
59 |
60 |
Warning:
61 |
62 |
63 |
64 |
65 |
Passed:
66 |
67 |
68 |
69 |
70 |
71 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/content/sidebarBuilder.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2008 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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.xssme.');
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.shift();
49 |
50 | parent.appendChild(child);
51 |
52 | if (postFunc) postFunc(parent, child);
53 |
54 | setTimeout(self.start, self.time, self);
55 |
56 | }
57 |
58 |
59 | }
60 | ,
61 | add: function(parent, child, postFunc) {
62 | this.toBeAdded.push([parent,child, postFunc]);
63 | }
64 | ,
65 | stop: function() {
66 | this.isRunning = false;
67 | this.toBeAdded = null;
68 | }
69 | }
70 |
71 | function getSidebarBuilder() {
72 | if (typeof(__xssme_sidebar_builder__) == 'undefined' ||
73 | !__xssme_sidebar_builder__)
74 | {
75 | __xssme_sidebar_builder__ = new SidebarBuilder();
76 | }
77 | return __xssme_sidebar_builder__;
78 | }
79 |
--------------------------------------------------------------------------------
/content/tabbrowsermanager.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 | for (var j = 0; j < forms[i].elements.length; j++) {
69 | var elem = forms[i].elements[j];
70 | switch (elem.nodeName.toLowerCase()) {
71 | case 'submit':
72 | case 'reset':
73 | case 'image':
74 | case 'button':
75 | case 'fieldset':
76 | this.tabForms[i].push(null);
77 | break;
78 | case 'checkbox':
79 | case 'radio':
80 | this.tabForms[i].push(elem.checked);
81 | break;
82 | default:
83 | this.tabForms[i].push(elem.value);
84 | }
85 | }
86 | }
87 |
88 | this.index = browser.webNavigation.sessionHistory.index;
89 | }
90 |
91 | TabManager.prototype = {
92 | /**
93 | * Point a browser at the target page recorded by this TabManager.
94 | * @param browser the browser to point to the target page
95 | */
96 | loadTargetPage: function (browser) {
97 | browser.webNavigation.loadURI(this.targetPage, 0, this.targetPageReferrer, this.targetPagePostData, null);
98 | }
99 | ,
100 | writeTabForms: function(forms, testFormIndex, testFieldIndex, testValue){
101 | if (forms[testFormIndex] === undefined){
102 | Components.utils.reportError('Received an undfined form: ')
103 | }
104 | for (var formIndex = 0;
105 | formIndex < forms.length;
106 | formIndex++)
107 | {
108 | for (var elementIndex = 0;
109 | elementIndex < forms[formIndex].elements.length;
110 | elementIndex++)
111 | {
112 | var element = forms[formIndex].elements[elementIndex];
113 | if (formIndex !== null &&
114 | formIndex === testFormIndex &&
115 | elementIndex === testFieldIndex &&
116 | testValue !== null
117 | )
118 | {
119 | if(element.nodeName.toLowerCase() === 'select') {
120 | var newOption = forms[formIndex].ownerDocument.createElement('option');
121 | var grabTextWithOutTrailingWhitespaceRegExp = /^(.*[^\s])\s*$/;
122 | var attackString =
123 | grabTextWithOutTrailingWhitespaceRegExp.
124 | exec(testValue.string)[1];
125 |
126 | newOption.setAttribute('value', attackString);
127 | newOption.innerHTML = testValue.string;
128 | element.options[element.options.length] = newOption;
129 | element.selectedIndex = element.options.length - 1;
130 | }
131 | else {
132 | element.value = testValue.string;
133 | }
134 | }
135 | else if (element.nodeName.toLowerCase() == 'submit' ||
136 | element.nodeName.toLowerCase() == 'reset' ||
137 | element.nodeName.toLowerCase() == 'image' ||
138 | element.nodeName.toLowerCase() == 'button')
139 | {
140 | // don't care, this is here just to make sure the elements
141 | // are parallel.
142 | }
143 | else if (element.nodeName.toLowerCase() == 'checkbox' ||
144 | element.nodeName.toLowerCase() == 'radio')
145 | {
146 | element.checked = this.tabForms[formIndex][elementIndex];
147 | }
148 | else {
149 | element.value = this.tabForms[formIndex][elementIndex];
150 | }
151 | }
152 | }
153 | }
154 | ,
155 | getTabData: function(forms, testFormIndex, testFieldIndex){
156 | var rv = new Array();
157 | var formIndex = testFormIndex;
158 |
159 | for (var elementIndex = 0;
160 | elementIndex < forms[formIndex].elements.length;
161 | elementIndex++)
162 | {
163 | var element = forms[formIndex].elements[elementIndex];
164 | var fieldInfo = new Object();
165 | fieldInfo.name = element.name;
166 | fieldInfo.data = element.value;
167 | fieldInfo.tested = (elementIndex == testFieldIndex);
168 | rv.push(fieldInfo);
169 | }
170 | return rv;
171 | }
172 | ,
173 | /**
174 | * This returns the data in a form
175 | */
176 | getFormDataForURL: function(forms, testFormIndex, testFieldIndex,
177 | testValue)
178 | {
179 | var formIndex = testFormIndex;
180 | var rv = '';
181 | for (var elementIndex = 0;
182 | elementIndex < forms[testFormIndex].elements.length;
183 | elementIndex++)
184 | {
185 | var element = forms[testFormIndex].elements[elementIndex];
186 | if (element.value) {
187 | if (rv.length != 0){
188 | rv+='&';
189 | }
190 | rv += element.name +'='+element.value;
191 | }
192 | }
193 | return rv;
194 |
195 | }
196 | };
--------------------------------------------------------------------------------
/content/util.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 = ']]]]>1?'s':'')+' encountered.')
163 | }
164 | }
165 | else {
166 | alert("Couldn't find any attacks. No Attacks imported.");
167 | return false;
168 | }
169 | }
170 |
171 | function importAttacksFromXMLFile(importFile, container) {
172 | var fileContents = FileIO.read(importFile);
173 | return importAttackFromXMLString(fileContents, container);
174 | }
175 |
176 | function getMonthName(monthNumber) {
177 | var months = new Array();
178 | months[0] = "January";
179 | months[1] = "February";
180 | months[2] = "March";
181 | months[3] = "April";
182 | months[4] = "May";
183 | months[5] = "June";
184 | months[6] = "July";
185 | months[7] = "August";
186 | months[8] = "September";
187 | months[9] = "October";
188 | months[10] = "November";
189 | months[11] = "December";
190 | return months[monthNumber];
191 | }
192 |
193 | /**
194 | * This function checks the success whether the work tab's content document
195 | * match the original tab's content document (in ways that we care about).
196 | * @returns true if same otherwise false.
197 | */
198 | function compareContentDocuments(origTabContentDocument, workTabContentDocument) {
199 | var rv = true;
200 | if (workTabContentDocument.forms) {
201 | if (origTabContentDocument.forms.length ===
202 | workTabContentDocument.forms.length)
203 | {
204 | for (var i = 0; i < origTabContentDocument.forms.length && rv; i++) {
205 | if (workTabContentDocument.forms[i]){
206 | if (workTabContentDocument.forms[i].elements){
207 | for (var n = 0; n < origTabContentDocument.forms[i].elements.length && rv; n++){
208 | if (workTabContentDocument.forms[i].elements[i]) {
209 | if (origTabContentDocument.forms[i].elements[i].type !=
210 | workTabContentDocument.forms[i].elements[i].type) {
211 | rv = false;
212 | }
213 | }
214 | }
215 | }
216 | else {
217 | rv = false;
218 | }
219 | }
220 | else {
221 | rv = false;
222 | }
223 | }
224 | }
225 | else {
226 | rv = false;
227 | }
228 | }
229 | else {
230 | rv = false;
231 | }
232 | return rv
233 | }
234 |
235 | function getHTMLFormElementNameOrLabel(element) {
236 | return element.name?element.name:element.id;
237 | }
238 |
--------------------------------------------------------------------------------
/content/whiletestruns.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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, "Warning! Closing this dialog box will not terminate the XSS Me test.",
40 | "Warning! Closing this dialog box will not terminate the XSS Me test. If you wish to terminate the test, you may do so by closing the XSS Me sidebar. This is not recommended as it may result in a slight memory leak.",
41 | prompts.STD_YES_NO_BUTTONS, "", "", "", null, new Object());
42 |
43 | return !rv;
44 |
45 | }
46 |
47 | /**
48 | * This function is called when a test is finished
49 | */
50 | this.finishedTest = function() {
51 | this.numTestsComplete++;
52 | if (this.numTestsComplete > this.maxNumTests) {
53 | Components.utils.reportError('Too many tests have been completed');
54 | }
55 | }
56 |
57 | this.clearNumTests = function() {
58 | this.numTestsComplete = 0;
59 | }
60 |
61 | this.updateUI = function() {
62 |
63 | this.bar.value = this.numTestsComplete / this.maxNumTests * 100
64 | this.span.innerHTML = this.numTestsComplete.toString() + '/' + this.maxNumTests.toString();
65 |
66 | }
67 |
68 | this.startThoroughTesting = function(numVulnerableFields) {
69 | this.bar.value = 100;
70 | this.span.innerHTML = this.maxNumTests.toString() + '/' + this.maxNumTests.toString();
71 |
72 | this.bar = document.getElementById('thoroughBar');
73 | this.span = document.getElementById('thoroughTestCount');
74 |
75 | this.maxNumTests = 2*numVulnerableFields*this.testType.count;
76 | this.numTestsComplete = 0;
77 |
78 | //document.getElementById('heuristicsComplete').style.visibility = 'visible';
79 | }
80 |
81 | function onUnLoad() {
82 | //alert(this.numTestsComplete + ' of ' +this.maxNumTests);
83 | this.bar = null;
84 | this.span = null;
85 | }
86 |
87 | /**
88 | * called when the page loads
89 | */
90 | function onLoad() {
91 | this.clearNumTests();
92 | window.centerWindowOnScreen();
93 | this.maxNumTests = window.arguments[0];
94 | this.testType = window.arguments[1];
95 | this.bar = null;
96 | this.span = null;
97 |
98 | if (this.testType.heuristicTest) {
99 | document.getElementById('heuristicTestingBox').style.visibility = 'visible';
100 | //document.getElementById('heuristicsComplete').style.visibility = 'hidden';
101 | this.bar = document.getElementById('heuristicBar');
102 | this.span = document.getElementById('heuristicTestCount');
103 | }
104 | else {
105 | this.bar = document.getElementById('thoroughBar');
106 | this.span = document.getElementById('thoroughTestCount');
107 | }
108 |
109 | //update UI every 1/5 second
110 | window.setInterval(this.updateUI, 200);
111 | }
112 |
--------------------------------------------------------------------------------
/content/whiletestruns.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
56 |
--------------------------------------------------------------------------------
/content/xssme_StreamListener.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | /**
24 | * StreamListener
25 | */
26 |
27 | function StreamListener(attackRunner, resultsManager) {
28 | this.attackRunner = attackRunner;
29 | this.resultsManager = resultsManager;
30 | this.done = false;
31 | }
32 |
33 | StreamListener.prototype = {
34 | data: ""
35 | ,
36 | testData: null
37 | ,
38 | // nsIStreamListener
39 | onStartRequest: function (aRequest, aContext) {
40 | //do nothing...
41 | }
42 | ,
43 | onDataAvailable: function (aRequest, aContext, aStream, aSourceOffset, aLength) {
44 | var scriptableInputStream =
45 | Components.classes["@mozilla.org/scriptableinputstream;1"]
46 | .createInstance(Components.interfaces.nsIScriptableInputStream);
47 | scriptableInputStream.init(aStream);
48 |
49 | this.data += scriptableInputStream.read(aLength);
50 | }
51 | ,
52 | onStopRequest: function (aRequest, aContext, aStatus) {
53 | this.done = true;
54 | dump('\n---- Here is the raw source of the result:----\n')
55 | dump(this.data);
56 | dump('\n--- end of raw source ---');
57 | this.resultsManager.evaluateSource(this);
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/xssme_sidebar.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS 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 __xss_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 | ];
49 |
50 | /**
51 | * get a reference to the main firefox window
52 | */
53 | function getMainWindow(){
54 | var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
55 | .getInterface(Components.interfaces.nsIWebNavigation)
56 | .QueryInterface(Components.interfaces.nsIDocShellTreeItem)
57 | .rootTreeItem
58 | .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
59 | .getInterface(Components.interfaces.nsIDOMWindow);
60 | return mainWindow;
61 | }
62 |
63 | /**
64 | * get a reference to the document object of the page that is being viewed now
65 | */
66 | function getMainHTMLDoc(){
67 | var mainWindow = getMainWindow();
68 | var elTabBrowser = mainWindow.document.getElementById('content');
69 | var currentDocument = elTabBrowser.contentDocument;
70 | return currentDocument;
71 | }
72 |
73 | function extension(){
74 | //do nothing right now...
75 | this.plistener=null;
76 | this.warningDialog = null;
77 | this.sidebarBuilderPauseObserver = null;
78 | this.prefs = new Array();
79 | }
80 |
81 | extension.prototype = {
82 | /**
83 | * Get what type of test is it? oneform/manyform, allstring/prefstring,
84 | * heuristic/thorough.
85 | * @returns an int with XSS_ME_TestType_One_forms
86 | */
87 | getTestType: function(event){
88 | var tabbox = document.getElementById('sidebarformtabbox');
89 | var rv = new Object();
90 | var buttonClicked = event.explicitOriginalTarget;
91 | var prefs = Components.classes["@mozilla.org/preferences-service;1"].
92 | getService(Components.interfaces.nsIPrefService);
93 | var branch = prefs.getBranch("extensions.xssme.");
94 | try {
95 |
96 | if (branch.prefHasUserValue('useheuristictests')) {
97 | rv.heuristicTest = branch.getBoolPref('useheuristictests');
98 | }
99 | else {
100 | rv.heuristicTest = true;
101 | }
102 | }
103 | catch (e) {
104 | rv.heuristicTest = true;
105 | }
106 | if (buttonClicked.className && buttonClicked.className ===
107 | 'run_form_test')
108 | {
109 |
110 | rv.singleFormTest = true;
111 |
112 | if ( tabbox.selectedPanel.
113 | getElementsByAttribute('class', 'TestType').item(0).
114 | selectedItem.value == TestType_AllTestsForForm)
115 | {
116 | rv.allTests = true;
117 | }
118 | else {
119 | rv.allTests = false;
120 | }
121 |
122 | }
123 | else {
124 | rv.singleFormTest = false;
125 | if (buttonClicked.id === 'test_all_forms_with_all_attacks'){
126 | rv.allTests=true;
127 | }
128 | else {
129 | rv.allTests = false;
130 | }
131 | }
132 |
133 | /* cache the number of attacks early */
134 | rv.count = getAttackStringContainer().getStrings().length;
135 | if (rv.allTests === false) {
136 | var prefNumAttacks = this.getPreferredNumberOfAttacks();
137 |
138 | rv.count = (prefNumAttacks > rv.count) ? rv.count : prefNumAttacks;
139 |
140 | }
141 |
142 | return rv;
143 | }
144 | ,
145 | getMarkedFieldsForPanel:function(formPanel, all, formIndex) {
146 | var fieldUIs = formPanel.getElementsByAttribute('class', 'nolabel');
147 | var fieldsToTest = new Array();
148 |
149 | for(var i =0; i < fieldUIs.length; i++){
150 | if (fieldUIs[i].checked || all === true){
151 | var fieldToTest = new Object();
152 | fieldToTest.index = parseInt(fieldUIs[i].getAttribute('formElementIndex'));
153 | fieldToTest.name = getMainHTMLDoc().forms[formIndex].elements[fieldToTest.index].name;
154 | fieldsToTest.push(fieldToTest);
155 | }
156 | }
157 | return fieldsToTest;
158 | }
159 | ,
160 | /**
161 | * gets all the characters to use for heuristic testing.
162 | */
163 | getHeuristicTestChars: function() {
164 |
165 | var prefs = Components.classes["@mozilla.org/preferences-service;1"].
166 | getService(Components.interfaces.nsIPrefService);
167 | var branch = prefs.getBranch("extensions.xssme.");
168 | var rv = "";
169 | try {
170 | rv = branch.getCharPref('testchars');
171 | }
172 | catch(e) {
173 | Components.utils.reportError('XSS Me. Could not access preference extensions.xssme.testchars');
174 | }
175 |
176 | return rv;
177 | }
178 | ,
179 | /**
180 | * iterate through all these fields and find all the marked ones
181 | * @param testType the type of test that is being run.
182 | * @returns a list of fields to test
183 | */
184 | getFieldsToTest: function(testType) {
185 |
186 | var rv = null;
187 | var tabbox = document.getElementById('sidebarformtabbox');
188 | var mainDoc = getMainWindow().document.getElementById('content').contentDocument;
189 |
190 | if (testType.singleFormTest) {
191 | rv = this.getMarkedFieldsForPanel(tabbox.selectedPanel, false, tabbox.selectedIndex);
192 | for each (field in rv) {
193 | field.formIndex = tabbox.selectedIndex;
194 | field.formName = getHTMLFormElementNameOrLabel(mainDoc.forms[tabbox.selectedIndex]);
195 | }
196 | }
197 | else {
198 | /* @todo is using ._tabpanels safe here? ._tabpanels is a
199 | cached version of the panels */
200 | for (var n = 0; n < tabbox.tabpanels.childNodes.length; n++) {
201 | /* @todo is using ._tabpanels safe here? ._tabpanels is a
202 | cached version of the panels */
203 | var temp = this.getMarkedFieldsForPanel(tabbox.tabpanels.
204 | childNodes.item(n), true, n);
205 | for each (field in temp) {
206 | field.formIndex = n;
207 | field.formName = getHTMLFormElementNameOrLabel(mainDoc.forms[n]);
208 |
209 | }
210 | if (rv) {
211 | rv = rv.concat(temp);
212 | }
213 | else {
214 | rv = temp;
215 | }
216 | }
217 | }
218 | return rv;
219 | }
220 | ,
221 | run_tests: function(event){
222 |
223 | var canRunTests = this.preTest();
224 |
225 | if (canRunTests == false){
226 | alert('Could not run tests as test are already running. Please ' +
227 | 'wait for these tests to finish ')
228 | return;
229 | }
230 |
231 | var testType = this.getTestType(event);
232 | var fieldsToTest = this.getFieldsToTest(testType);
233 | if (fieldsToTest.length === 0) {
234 | alert('Please make sure you have selected fields to test.')
235 | this.postTest();
236 | return;
237 | }
238 | var tabManager = new TabManager(getMainWindow().getBrowser().selectedTab.linkedBrowser);
239 | var testCount = 0;
240 | var heuristicTestChars = this.getHeuristicTestChars();
241 | if (testType.heuristicTest) {
242 | testCount = fieldsToTest.length * heuristicTestChars.length;
243 | }
244 | else {
245 | testCount = fieldsToTest.length * testType.count * 2;
246 | //needs *2 because we have 2 types of tests (source and in browser)
247 | }
248 |
249 | this.warningDialog = window.openDialog(
250 | 'chrome://xssme/content/whiletestruns.xul', 'whiletestruns',
251 | 'chrome,dialog,dependant=yes', testCount, testType);
252 |
253 |
254 | var testManager = getTestManager(this);
255 |
256 | testManager.runTest(testType, fieldsToTest, tabManager, heuristicTestChars);
257 | }
258 | ,
259 | createActionUI: function() {
260 | var box = document.createElement('hbox');
261 | var menulist = document.createElement('menulist');
262 | var menupopup = document.createElement('menupopup');
263 | var runTests_mi = document.createElement('menuitem');
264 | var runTopTests_mi = document.createElement('menuitem');
265 | var submitThisForm_mi = document.createElement('menuitem');
266 | var button = document.createElement('button');
267 | var rv = new Object();
268 |
269 | rv.menuitems = [];
270 |
271 | runTests_mi.setAttribute('label', "Run all tests");
272 | runTests_mi.setAttribute('value', TestType_AllTestsForForm);
273 | runTopTests_mi.setAttribute('label', "Run top " + this.
274 | getPreferredNumberOfAttacks() + " tests");
275 | runTopTests_mi.setAttribute('value', TestType_PrefNumTestsForForm);
276 |
277 | submitThisForm_mi.setAttribute('value', TestType_OneTestForForm);
278 |
279 | rv.menuitems.push(runTests_mi);
280 | rv.menuitems.push(runTopTests_mi);
281 |
282 | //menulist.setAttribute("editable", false);
283 | rv.menupopup= menupopup;
284 |
285 | button.setAttribute('label', "Execute");
286 | button.setAttribute('command', 'xssme_do_test');
287 | button.className = 'run_form_test';
288 |
289 | menulist.setAttribute('class', 'TestType');
290 | rv.menulist = menulist;
291 |
292 |
293 | rv.button = button;
294 |
295 | rv.box = box;
296 |
297 | return rv;
298 | }
299 | ,
300 | syncSidebarToForm: function(sidebarElement, formElement){
301 |
302 |
303 | var assignSidebarValueToFormElement = function(event){
304 | formElement.value=sidebarElement.value;
305 | }
306 |
307 | var assignFormElementValueToSideBar = function(event){
308 | sidebarElement.value = formElement.value.toString();
309 | }
310 |
311 | formElement.addEventListener('keypress',
312 | assignFormElementValueToSideBar, true);
313 | formElement.addEventListener('mouseup',
314 | assignFormElementValueToSideBar, true);
315 | formElement.addEventListener('change',
316 | assignFormElementValueToSideBar, true);
317 | sidebarElement.addEventListener('input',
318 | assignSidebarValueToFormElement, true);
319 | sidebarElement.addEventListener('click',
320 | assignSidebarValueToFormElement, true);
321 |
322 |
323 | }
324 | ,
325 | do_generate_form_ui: function() {
326 | var q = 0;
327 | var maindoc = getMainWindow().document.getElementById('content').contentDocument;
328 | var box = document.getElementById('xssme_here_be_tabs');
329 | var docforms = maindoc.getElementsByTagName('form');
330 | var unnamedFormCounter = 0; //used for generating the unnamed form names
331 | var tabbox = document.createElement('tabbox');
332 | var tabs = document.createElement('tabs');
333 | var tabpanels = document.createElement('tabpanels');
334 |
335 | tabbox.setAttribute('id', 'sidebarformtabbox');
336 | //we only want to put things in a clean box.
337 | if (box.childNodes.length !== 0) {
338 | for (var i = 0; i < box.childNodes.length; i++) {
339 | box.removeChild(box.childNodes[i]);
340 | }
341 | }
342 |
343 | tabbox.setAttribute('flex', 1);
344 |
345 | //box.appendChild(tabbox);
346 | getSidebarBuilder().add(box, tabbox);
347 |
348 | // create the form UI
349 | // Note that the addition of the DOM is seperated from the creation of
350 | // it in the hopes that it will make for a faster overall operation
351 | // even though it does require a bit more work in the code. This is
352 | // based on Mossop(David Townshed)'s advice.
353 | if (maindoc.forms.length !== 0){
354 | var attackStringContainer = getAttackStringContainer();
355 | attackStringContainer.init();
356 |
357 | var newTabs = [];
358 | var newTabForms= [];
359 | var newTabPanels = [];
360 | var newTabActions = [];
361 | var newTabPanelVbox = [];
362 |
363 |
364 | for (var i = 0; i < maindoc.forms.length; i++){
365 |
366 | var aForm = maindoc.forms[i];
367 | var formname = null;
368 | var formPanel = document.createElement("tabpanel");
369 | var fieldsWithUI = new Object();
370 |
371 | var formTab = document.createElement("tab");
372 |
373 | dump(q++ + "\n");
374 |
375 | // Since the name attribute is deprecated for the form tag we first
376 | // check the id attribute, then the name attribute and then consider
377 | // it unnamed.
378 | if (aForm.id){
379 | formname = aForm.id;
380 | }
381 | else if (aForm.name){
382 | formname = aForm.name;
383 | }
384 | else {
385 | formname = "Unnamed form " + (++unnamedFormCounter);
386 | }
387 |
388 | formTab.setAttribute("label", formname);
389 |
390 | dump('aForm.elements.length: ' + aForm.elements.length +'\n');
391 |
392 | //iterate through the forms and generate the DOM.
393 | if (aForm.elements.length !== 0){
394 | for (var n = 0; n < aForm.elements.length; n++){
395 | var sidebarElement = null;
396 | dump('aForm.elements[' + n + '] = ' +aForm.elements[n] +
397 | '- ' + aForm.elements[n].id +'\n');
398 | if (aForm.elements[n].name){
399 | sidebarElement =
400 | fieldsWithUI[aForm.elements[n].name] =
401 | createFieldUI(aForm.elements[n], n);
402 | }
403 | else if (aForm.elements[n].id){
404 | sidebarElement =
405 | fieldsWithUI[aForm.elements[n].id] =
406 | createFieldUI(aForm.elements[n], n );
407 | }
408 | else {
409 | sidebarElement =
410 | fieldsWithUI["form" + n + "_"+
411 | Math.round(Math.random() * 10000000)] =
412 | createFieldUI(aForm.elements[n], n);
413 | }
414 | sidebarElement = sidebarElement.
415 | getElementsByAttribute('editable', 'true')[0];
416 | this.syncSidebarToForm(sidebarElement, aForm.elements[n]);
417 |
418 | }
419 |
420 | }
421 |
422 | var actionButtons = this.createActionUI();
423 | newTabs.push(formTab);
424 | newTabForms.push(fieldsWithUI);
425 | newTabPanels.push(formPanel);
426 | newTabActions.push(actionButtons);
427 | newTabPanelVbox.push(document.createElement("vbox"));
428 |
429 | }
430 |
431 | //Add the form UI to the DOM.
432 | for (var i =0; i < newTabs.length; i++) {
433 | for each(var fieldUI in newTabForms[i]) {
434 | getSidebarBuilder().add(newTabPanelVbox[i], fieldUI);
435 | }
436 |
437 | for each(var mi in newTabActions[i].menuitems){
438 | getSidebarBuilder().add(newTabActions[i].menupopup, mi);
439 | }
440 | getSidebarBuilder().add(newTabActions[i].menulist,
441 | newTabActions[i].menupopup);
442 |
443 | getSidebarBuilder().add(newTabActions[i].box,
444 | newTabActions[i].menulist);
445 | getSidebarBuilder().add(newTabActions[i].box,
446 | newTabActions[i].button);
447 | getSidebarBuilder().add(newTabPanelVbox[i],
448 | newTabActions[i].box);
449 | getSidebarBuilder().add(newTabPanels[i], newTabPanelVbox[i]);
450 | getSidebarBuilder().add(tabs, newTabs[i]);
451 | getSidebarBuilder().add(tabpanels, newTabPanels[i]);
452 | }
453 |
454 | getSidebarBuilder().add(tabbox, tabs);
455 | getSidebarBuilder().add(tabbox, tabpanels, ensureFirstTabPanelIsSelected);
456 |
457 | }
458 | else {
459 |
460 | var noformPanel = document.createElement("tabpanel");
461 | var noformTab = document.createElement("tab");
462 | var labelinpanel = document.createElement("label");
463 | var noformPanelVbox = document.createElement("vbox");
464 |
465 | labelinpanel.setAttribute("value", "Sorry, this page has no forms.");
466 |
467 | noformTab.setAttribute("label", "No Forms");
468 |
469 | getSidebarBuilder().add(tabbox, tabs);
470 | getSidebarBuilder().add(tabbox, tabpanels);
471 |
472 | getSidebarBuilder().add(tabs, noformTab);
473 |
474 | getSidebarBuilder().add(tabpanels, noformPanel);
475 |
476 | getSidebarBuilder().add(noformPanel, noformPanelVbox);
477 |
478 | getSidebarBuilder().add(noformPanelVbox, labelinpanel);
479 |
480 | }
481 |
482 | getSidebarBuilder().start();
483 |
484 | }
485 | ,
486 | addAllMainWindowEventListeners: function() {
487 |
488 | var mainWindow = getMainWindow();
489 | var ourCaller = this;
490 | this.windowEventListenerClosure = function(){ourCaller.do_generate_form_ui()};
491 | mainWindow.getBrowser().tabContainer.
492 | addEventListener("TabSelect",
493 | this.windowEventListenerClosure, false);
494 |
495 | this.plistener = new xssmeProgressListener(this.
496 | windowEventListenerClosure);
497 |
498 | mainWindow.document.getElementById('content').
499 | addProgressListener(this.plistener,
500 | Components.interfaces.nsIWebProgress.NOTIFY_STATE_DOCUMENT);
501 |
502 | this.sidebarBuilderPauseObserver = new Xss_PrefObserver(watchSidebarBuilderPausePref);
503 |
504 | var prefService = Components.classes['@mozilla.org/preferences-service;1'].
505 | getService(Components.interfaces.nsIPrefService);
506 |
507 | var branch = prefService.getBranch('');
508 |
509 | var observableBranch = branch.
510 | QueryInterface(Components.interfaces.nsIPrefBranch2);
511 |
512 | observableBranch.addObserver('extensions.xssme.sidebarbuildingstop',
513 | this.sidebarBuilderPauseObserver, false);
514 |
515 | }
516 | ,
517 | removeAllMainWindowEventListeners: function (){
518 | var mainWindow = getMainWindow();
519 |
520 | mainWindow.document.getElementById('content').
521 | removeProgressListener(this.plistener);
522 |
523 | if (this.windowEventListenerClosure) {
524 | mainWindow.getBrowser().tabContainer.
525 | removeEventListener('TabSelect',
526 | this.windowEventListenerClosure,
527 | false);
528 | this.windowEventListenerClosure = null;
529 | }
530 | var prefService = Components.classes['@mozilla.org/preferences-service;1'].
531 | getService(Components.interfaces.nsIPrefService);
532 |
533 | var branch = prefService.getBranch('');
534 |
535 | var observableBranch = branch.
536 | QueryInterface(Components.interfaces.nsIPrefBranch2);
537 |
538 | observableBranch.removeObserver('extensions.xssme.sidebarbuildingstop',
539 | this.sidebarBuilderPauseObserver)
540 |
541 | }
542 | ,
543 | getPreferredNumberOfAttacks: function(){
544 | var prefs = Components.classes["@mozilla.org/preferences-service;1"].
545 | getService(Components.interfaces.nsIPrefService);
546 | var branch = prefs.getBranch("extensions.xssme.");
547 | return branch.getIntPref("prefnumattacks");
548 | }
549 | ,
550 | /**
551 | * This function holds code that is general for any time we want to do a
552 | * test
553 | */
554 | preTest: function(){
555 | var rv = false;
556 | if (this.warningDialog === null){
557 | rv = true;
558 |
559 | var prefService = Components.
560 | classes['@mozilla.org/preferences-service;1'].
561 | getService(Components.interfaces.nsIPrefService);
562 | var branch = prefService.getBranch("");
563 | for each (var prefInfo in __xss_me_prefs_to_disable) {
564 | var origValue;
565 | var errorState = false;
566 | switch(prefInfo.type){
567 | case 'bool':
568 | try {
569 | origValue = branch.getBoolPref(prefInfo.name);
570 | branch.setBoolPref(prefInfo.name, prefInfo.ourValue);
571 | }
572 | catch(e){
573 | Components.utils.reportError(e +'with '+ prefInfo.name);
574 | errorState = true;
575 | }
576 | break;
577 | case 'int':
578 | try {
579 | origValue = branch.getIntPref(prefInfo.name);
580 | branch.setIntPref(prefInfo.name, prefInfo.ourValue);
581 | }
582 | catch(e){
583 | Components.utils.reportError(e + 'with '+ prefInfo.name);
584 | errorState = true
585 | }
586 | break;
587 | }
588 |
589 | if (errorState === false) {
590 |
591 | var backupPref = {
592 | 'name': prefInfo.name,
593 | 'type': prefInfo.type,
594 | 'origValue': origValue};
595 |
596 | this.prefs.push(backupPref);
597 | }
598 | }
599 |
600 | }
601 | return rv;
602 |
603 | }
604 | ,
605 | postTest: function(){
606 | this.warningDialog.close();
607 | this.warningDialog = null;
608 | var prefService = Components.
609 | classes['@mozilla.org/preferences-service;1'].
610 | getService(Components.interfaces.nsIPrefService);
611 | var branch = prefService.getBranch("");
612 | for each(var backupPref in this.prefs) {
613 | switch(backupPref.type){
614 | case 'bool':
615 | try {
616 | branch.setBoolPref(backupPref.name, backupPref.origValue);
617 | }
618 | catch(e){
619 | Components.utils.reportError(e +'with '+ backupPref.name);
620 | }
621 | break;
622 | case 'int':
623 | try {
624 | branch.setIntPref(backupPref.name, backupPref.origValue);
625 | }
626 | catch(e){
627 | Components.utils.reportError(e + 'with '+ backupPref.name);
628 | }
629 | break;
630 | }
631 | }
632 |
633 | this.prefs.splice(0, this.prefs.length);
634 | }
635 | ,
636 | calculateWorseCaseNumTestsToRun: function(testType, fieldsToTest) {
637 |
638 | var rv = 0;
639 |
640 | var numFieldsToTest = fieldsToTest.length;
641 |
642 | if (testType.heuristicTest) {
643 |
644 | var numTestChars = this.getHeuristicTestChars().length;
645 |
646 | rv += numFieldsToTest * numTestChars;
647 |
648 | }
649 |
650 | rv += numFieldsToTest*testType.count*2; // *2 because there are both DOM and string tests to run
651 | Components.utils.reportError("worse case num tests = ("+numFieldsToTest+"*" +numTestChars+"+"+numFieldsToTest+ "*"+ testType.count+") = "+
652 | "("+ (numFieldsToTest*numTestChars) +"+"+ (numFieldsToTest*testType.count)+") = " +((numFieldsToTest*numTestChars) + (numFieldsToTest*testType.count))+ " = " + rv);
653 | return rv;
654 |
655 | }
656 | ,
657 | /**
658 | * Called by the testmanager and resultsmanager to report that a test has
659 | * been completed so that the popup's UI can be updated
660 | */
661 | finishedTest: function() {
662 | if (this.warningDialog.closed === false && typeof(this.warningDialog.finishedTest) == 'function') {
663 | this.warningDialog.finishedTest();
664 | }
665 | else if (typeof(this.warningDialog.finishedTest) != 'function') {
666 | Components.utils.reportError('warning dialog\'s finished test function is missing.');
667 | }
668 | }
669 | }
670 |
671 |
672 | /**
673 | * This function takes a form returns an associative array (Object object) of
674 | * field name => field UI pairs (with the UI being appropriate for plugging
675 | * into a tabpanel for display. Recursive.
676 | * @param form a form
677 | * @param fields
678 | * @returns an associative array (Object) of field name => field UI pairs
679 | */
680 | function getFormFieldsUI(aForm, allFields) {
681 | var fields = allFields ? allFields : new Object();
682 |
683 | for (var child in aForm.elements){
684 | dump('examining child: ' + child + " " + child.nodeName+"\n");
685 | if (isFormField(child)){
686 | if (!fields[child.name]){ //We don't want a million option UIs
687 | // even if there are a million
688 | // options
689 | var childUI = createFieldUI(child);
690 | fields[child.name] = childUI;
691 | }
692 | dump(child.nodeName + "is a form field\n");
693 | }
694 | else {
695 | dump(child.nodeName + "is NOT a form field\n");
696 | fields = getForFieldsUI(child, fields);
697 | }
698 | }
699 |
700 | return fields;
701 | }
702 | /**
703 | * generate the ui for one form field.
704 | * @param node a form field
705 | * @param elementIndex the index of the element in the form's elements array.
706 | * @returns the root of the ui for a form field (a groupbox).
707 | */
708 | function createFieldUI(node, elementIndex){
709 |
710 | // var uid = Math.round(Math.random() * 100000000000);
711 | dump("creating field ui\n");
712 | var root = document.createElement("groupbox");
713 | root.setAttribute("flex", 0);
714 |
715 | var caption = document.createElement("caption");
716 |
717 | if (node.name){
718 | caption.setAttribute("label", node.name);
719 | }
720 | else if(node.id){
721 | caption.setAttribute("label", node.id);
722 | }
723 |
724 | var hbox = document.createElement("hbox");
725 | dump("creating field ui...\n");
726 | var checkbox = document.createElement("checkbox");
727 | checkbox.className = "nolabel";
728 | checkbox.setAttribute('formElementIndex', elementIndex);
729 |
730 | var menulist = document.createElement("menulist");
731 | menulist.setAttribute("editable", true);
732 | dump("creating field ui.......\n");
733 | var menupopup = document.createElement("menupopup");
734 |
735 | var firstMenuItem = document.createElement("menuitem");
736 | if (node.value && node.value.length){
737 | firstMenuItem.setAttribute("label", node.value);
738 | }
739 | else {
740 | firstMenuItem.setAttribute("label",
741 | "Change this to the value you want tested");
742 | }
743 | menupopup.appendChild(firstMenuItem);
744 |
745 | dump("creating field ui............................\n");
746 | var attackStringContainer = getAttackStringContainer();
747 | var attacks = attackStringContainer.getStrings();
748 | for (var i = 0; i < attacks.length; i++){
749 | var aMenuItem = document.createElement("menuitem");
750 | aMenuItem.setAttribute('label', attacks[i].string);
751 | aMenuItem.setAttribute('width', '100');
752 | aMenuItem.setAttribute('crop', 'end');
753 | menupopup.appendChild(aMenuItem);
754 | dump("menupopup childnodes length: " + menupopup.childNodes.length+"\n");
755 | }
756 |
757 | menulist.appendChild(menupopup);
758 |
759 | hbox.appendChild(checkbox);
760 | hbox.appendChild(menulist);
761 |
762 | root.appendChild(caption);
763 | root.appendChild(hbox);
764 | dump("creating field ui................................................\n");
765 | return root;
766 |
767 | }
768 |
769 | /**
770 | * This function checks whether the passed in DOMNode is form field or some
771 | * other type of tag.
772 | * @param node the node to check
773 | * @returns true if the elemenet is a form field, false otherwise
774 | */
775 | function isFormField(node){
776 |
777 | switch (node.tagName.toLowerCase()){
778 | case "input":
779 | case "option":
780 | case "button":
781 | case "textarea":
782 | case "submit":
783 | return true;
784 | default:
785 | return false;
786 | }
787 | }
788 |
789 | /**
790 | * Watches the sidebar builder pause time preference and sets
791 | */
792 | function watchSidebarBuilderPausePref(subject, topic, data) {
793 | var prefService = Components.classes['@mozilla.org/preferences-service;1'].
794 | getService(Components.interfaces.nsIPrefService);
795 | var branch = prefService.getBranch('extensions.xssme.');
796 |
797 | getSidebarBuilder().time = branch.getIntPref('sidebarbuildingstop');
798 | }
799 |
800 | /**
801 | * This function is used to make sure that the first tab panel is selected
802 | * in a tabbox
803 | * @param parent the tabbox
804 | * @param child the tabpanels element
805 | */
806 | function ensureFirstTabPanelIsSelected(parent, child) {
807 | parent.selectedIndex = parent.tabpanels.selectedIndex = 0;
808 | for each(var menulist in parent.getElementsByTagName("menulist")) {
809 | menulist.selectedIndex = 0;
810 | }
811 | }
812 |
--------------------------------------------------------------------------------
/content/xssme_sidebar.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
30 |
31 |
33 |
35 |
37 |
39 |
41 |
43 |
45 |
47 |
49 |
51 |
53 |
55 |
57 |
59 |
61 |
63 |
65 |
67 |
69 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | XSS-Me is a tool to aid in testing for Cross-Site Scripting vulnerabilities in
84 | the current page.
85 |
86 | Each tab in the sidebar represents a form on the current page and lists all of
87 | the fields in the form.
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
111 |
112 |
--------------------------------------------------------------------------------
/content/xssmeevaluators.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | /**
24 | * xssmeevaluators.js
25 | * This file holds a number of JS evaluators
26 | * @require Results.js
27 | */
28 |
29 | function xssmeTrimRight( s ) {
30 | if ( typeof( String.prototype.trimRight ) === 'undefined' || !String.prototype.trimRight ) {
31 | return s.replace( /\s+$/, '' );
32 | }
33 |
34 | return s.trimRight();
35 | }
36 |
37 | function checkForVulnerableElement(browser, attackRunner) {
38 |
39 | var rv = null;
40 | var document = browser.contentDocument;
41 |
42 | dump('xssmeevaluator on page ' + document.location);
43 | dump(' is ' + (document.wrappedJSObject.vulnerable ) + ' ');
44 | dump((document.wrappedJSObject.vulnerable == true) + '\n');
45 |
46 | if (document.wrappedJSObject.vulnerable && document.wrappedJSObject.vulnerable == true){
47 |
48 | rv = new Result(RESULT_TYPE_ERROR, 100, "DOM was modified by attack string. Field appears to be very vulnerable to XSS String.");// ('"+attackRunner.testValue.string+"')");
49 |
50 | }
51 | else {
52 |
53 | rv = new Result(RESULT_TYPE_PASS, 100, "DOM was not modified by attack string. Field does not appear vulnerable to XSS String");//('"+attackRunner.testValue.string+"')");
54 |
55 | }
56 |
57 | return [rv];
58 |
59 | }
60 |
61 | function checkForExactAttackText(streamListener){
62 |
63 | var rv = null;
64 | var searchString = xssmeTrimRight( streamListener.attackRunner.testValue.string );
65 | var specials = [
66 | '/', '.', '*', '+', '?', '|',
67 | '(', ')', '[', ']', '{', '}', '\\'];
68 | var regex = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
69 | searchString = searchString.replace(regex, '\\$1');
70 | var regex = new RegExp(searchString, 'gm');
71 | dump('xssmeevaluators::checkForExactAttackText: checking for ' +
72 | 'attackRunner.testValue: ' + streamListener.attackRunner.testValue.string + '\n');
73 | /*dump('xssmeevaluators::checkForExactAttackText::streamListener.data '+streamListener.data+'\n');*/
74 | var doesMatch = streamListener.data.match(regex);
75 |
76 | if (doesMatch) {
77 |
78 | rv = new Result(RESULT_TYPE_WARNING, 100, "The unencoded attack string was found in the html of the document. Other browsers may be vulnerable to this XSS string."); //('"+streamListener.attackRunner.testValue.string + "')");
79 |
80 | }
81 | else {
82 |
83 | rv = new Result(RESULT_TYPE_PASS, 100, "The unencoded attack string was not found in the html of the document.");//('"+streamListener.attackRunner.testValue.string + "')");
84 |
85 | }
86 |
87 | return [rv];
88 |
89 | }
90 |
91 |
--------------------------------------------------------------------------------
/defaults/preferences/xssme.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | pref("extensions.xssme.prefnumattacks", 9);
24 | pref("extensions.xssme.showcontextmenu", true);
25 | pref("extensions.xssme.numtabstouse", 6);
26 | pref("extensions.xssme.testchars", ";\\/<>\"'=");
27 | pref("extensions.xssme.useheuristictests", true);
28 | pref("extensions.xssme.sidebarbuildingstop", 3);
29 | pref("extensions.xssme.reportbuilding.showPass", false);
30 |
--------------------------------------------------------------------------------
/install.rdf:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 | xssme@security.compass
6 | XSS Me
7 | 0.4.6
8 | 2
9 | Security Compass
10 | An extension to test for Cross Site Scripting vulnerabilities
11 | chrome://xssme/content/preferences.xul
12 | chrome://xssme/skin/tiny_logo.png
13 |
14 |
15 | {ec8030f7-c20a-464f-9b0e-13a3a9e97384}
16 | 2.0.0.8
17 | 11.*
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/locale/en-US/overlay.dtd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/locale/en-US/prefwindow.dtd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/locale/en-US/xssme.dtd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SecurityCompass/XSSMe/1e87473220231ceb135c5d9eab6570b45fd693eb/locale/en-US/xssme.dtd
--------------------------------------------------------------------------------
/locale/en-US/xssme.properties:
--------------------------------------------------------------------------------
1 | extensions.xssme.description=An extension to test for Cross Site Scripting vulnerabilities
--------------------------------------------------------------------------------
/readme.txt:
--------------------------------------------------------------------------------
1 | XSS-Me
2 | ======
3 | XSS-Me is a part of the Security Compass Exploit-Me series of tools. XSS-Me is
4 | designed to aid in the detection of Cross-Site scripting vulnerabilities. The
5 | tool is a Firefox extenstion that will execute specific attack strings against
6 | forms on your website.
7 |
8 |
9 | Limitations
10 | -----------
11 | Currently XSS-Me is focused on detecting reflected Cross-Site scripting
12 | attacks. While we have plans to implement the detection of stored Cross-Site
13 | scripting we are currently focusing on the speed and accuracy of the reflected
14 | portions of the tool.
15 |
16 |
17 | More Information
18 | ----------------
19 | For more information on XSS-Me please visit:
20 | http://www.securitycompass.com/exploitme.shtml. If you've got any questions,
21 | comments, or suggestions regarding XSS-Me please send them to
22 | tools@securitycompass.com.
23 |
24 |
25 | License
26 | -------
27 | XSS-Me is released under the GNU GPLv3 a copy of which should be included in
28 | this distribution.
--------------------------------------------------------------------------------
/skin/overlay.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | /* This is just an example. You shouldn't do this. */
24 | #xssme-hello
25 | {
26 | }
27 | #xssme-toolbar-button
28 | {
29 | list-style-image: url("chrome://xssme/skin/toolbar-button.png");
30 | -moz-image-region: rect(0px 24px 24px 0px);
31 | }
32 | #xssme-toolbar-button:hover
33 | {
34 | -moz-image-region: rect(24px 24px 48px 0px);
35 | }
36 | [iconsize="small"] #xssme-toolbar-button
37 | {
38 | -moz-image-region: rect( 0px 40px 16px 24px);
39 | }
40 | [iconsize="small"] #xssme-toolbar-button:hover
41 | {
42 | -moz-image-region: rect(24px 40px 40px 24px);
43 | }
44 |
--------------------------------------------------------------------------------
/skin/preferences.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | radio {
24 | list-style-image: url("chrome://browser/skin/preferences/Options.png");
25 | }
26 |
27 | radio[pane=xssgen] {
28 | -moz-image-region: rect(0px, 32px, 32px, 0px);
29 | }
30 |
31 | radio[pane=xssstrings] {
32 | -moz-image-region: rect(0px, 128px, 32px, 96px);
33 | }
--------------------------------------------------------------------------------
/skin/small_logo_sc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SecurityCompass/XSSMe/1e87473220231ceb135c5d9eab6570b45fd693eb/skin/small_logo_sc.png
--------------------------------------------------------------------------------
/skin/tiny_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SecurityCompass/XSSMe/1e87473220231ceb135c5d9eab6570b45fd693eb/skin/tiny_logo.png
--------------------------------------------------------------------------------
/skin/toolbar-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SecurityCompass/XSSMe/1e87473220231ceb135c5d9eab6570b45fd693eb/skin/toolbar-button.png
--------------------------------------------------------------------------------
/skin/whiletestruns.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2008 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | #heuristicTestingBox
24 | {
25 | visibility: collapse;
26 | }
27 |
28 | #heuristcsComplete {
29 | visibility: collapse;
30 | color: green;
31 | }
32 |
33 |
34 |
--------------------------------------------------------------------------------
/skin/xssme_sidebar.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2007 Security Compass
3 |
4 | This file is part of XSS Me.
5 |
6 | XSS 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 | XSS 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 XSS Me. If not, see .
18 |
19 | If you have any questions regarding XSS Me please contact
20 | tools@securitycompass.com
21 | */
22 |
23 | #form1_field1_menulist.activated .menulist-editable-input,
24 | #form1_field2_menulist.activated .menulist-editable-input,
25 | .activated .menulist-editable-input
26 | {
27 | background-color: #FFFF11 !important;
28 | }
29 |
30 | #form1_field1_checkbox .checkbox-label-box,
31 | #form1_field2_checkbox .checkbox-label-box,
32 | .nolabel .checkbox-label-box
33 | {
34 | display: none;
35 | }
36 |
37 | .title {
38 | color: #405068 !important;
39 | }
--------------------------------------------------------------------------------