Popular Vulnerable Code

Nails –Cross Site Scripting

Details

Affected Software:DojoToolkit

Fixed in Version:1.4.2

Issue Type:XSS

Original Code: Found Here

Description

This week’s vulnerability is a DOM based XSS that could be found in a JavaScript file provided by the DojoToolkit.  This JavaScript file was included (via script src) in many pages throughout the DojoToolkit,making those pages vulnerable to XSS.  Unlike traditional XSS bugs,server side processing is not required for certain types of DOM based XSS.  This is an important concept to understand as some code auditors will skip static pages assuming the attacker will not have the ability to control any values used by the page.

The bug starts here:

if(window.location.href.indexOf(“?”) >-1){

The JavaScript pulls the address of the loaded page and checks to see if the address contains the “?” character.  If the “?” character is found,the JavaScript begins parsing and splitting the URI into various arrays.  This parsing and splitting is done in the lines provided below:

var str = window.location.href.substr(window.location.href.indexOf(“?”)+1).split(/#/);
var ary  = str[0].split(/&/);
for(var i=0;i<ary.length;i++){
var split = ary[i].split(/=/),

The vulnerable assignment occurs here:

value = split[1];

The JavaScript above essentially grabs a querystring value (attacker supplied) and assigns it to the “value” variable.  Later,the “value” variable is used in several places,for example:

dojo.config.locale = locale = value;

document.getElementsByTagName(“html”)[0].dir = value;

theme = value;

Considering the assignments listed above,we have a couple different variables that are tainted.  I’ve highlighted the tainted variables in red.  Tracing the “theme” assignment shown above,we see the tainted value being passed to a document.write statement,resulting in XSS.

var themeCss = d.moduleUrl(“dijit.themes”,theme+”/”+theme+”.css”);

var themeCssRtl = d.moduleUrl(“dijit.themes”,theme+”/”+theme+”_rtl.css”);

document.write(‘<link rel=”stylesheet”type=”text/css”href=”‘+themeCss+’”>’);

document.write(‘<link rel=”stylesheet”type=”text/css”href=”‘+themeCssRtl+’”>’);

The patch checked in by the DojoToolkit team sanitizes the “value” JavaScript variable by allowing only word characters (^\w).

Developers Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
if(window.location.href.indexOf("?") >-1){
var str =  window.location.href.substr(window.location.href.indexOf("?")+1).split(/#/);
var ary  = str[0].split(/&/);
for(var i=0;i<ary.length;i++){
var split = ary[i].split(/=/),
key = split[0],
-value = split[1];
+value = split[1].replace(/[^\w]/g,"");// replace() to prevent XSS attack
switch(key){
case "locale":
// locale string | null
dojo.config.locale = locale = value;
break;
case "dir":
// rtl | null
document.getElementsByTagName("html")[0].dir = value;
break;
case "theme":
// tundra | soria | noir | squid | nihilo | null
theme = value;
break;
case "a11y":
if(value){ testMode = "dijit_a11y";}
}
}
}

// always include the default theme files:
if(theme || testMode){

if(theme){
var themeCss = d.moduleUrl("dijit.themes",theme+"/"+theme+".css");
var themeCssRtl =  d.moduleUrl("dijit.themes",theme+"/"+theme+"_rtl.css");
document.write('<link rel="stylesheet"type="text/css" href="'+themeCss+'">');
document.write('<link rel="stylesheet"type="text/css" href="'+themeCssRtl+'">');
}

if(dojo.config.parseOnLoad){
dojo.config.parseOnLoad = false;
dojo.config._deferParsing = true;
}

d.addOnLoad(function(){

// set the classes
var b = dojo.body();
if(theme){
dojo.removeClass(b,defTheme);
if(!d.hasClass(b,theme)){ d.addClass(b,theme);}
var n = d.byId("themeStyles");
if(n){ d.destroy(n);}
}
if(testMode){ d.addClass(b,testMode);}
if(dojo.config._deferParsing){
// attempt to elimiate race condition introduced by this
// test helper file.  120ms to allow CSS to finish/process?
setTimeout(dojo.hitch(d.parser,"parse",b),120);
}

});
}

})();

Nails

I like Nine Inch Nails,and I like hip-hop.
-Axl Rose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
if(window.location.href.indexOf("?") > -1){
var str = window.location.href.substr(window.location.href.indexOf("?")+1).split(/#/);
var ary  = str[0].split(/&/);
for(var i=0; i<ary.length; i++){
var split = ary[i].split(/=/),
key = split[0],
value = split[1];
switch(key){
case "locale":
// locale string | null
dojo.config.locale = locale = value;
break;
case "dir":
// rtl | null
document.getElementsByTagName("html")[0].dir = value;
break;
case "theme":
// tundra | soria | noir | squid | nihilo | null
theme = value;
break;
case "a11y":
if(value){ testMode = "dijit_a11y"; }
}
}
}

// always include the default theme files:
if(theme || testMode){

if(theme){
var themeCss = d.moduleUrl("dijit.themes",theme+"/"+theme+".css");
var themeCssRtl = d.moduleUrl("dijit.themes",theme+"/"+theme+"_rtl.css");
document.write('<link rel="stylesheet"type="text/css"href="'+themeCss+'">');
document.write('<link rel="stylesheet"type="text/css"href="'+themeCssRtl+'">');
}

if(dojo.config.parseOnLoad){
dojo.config.parseOnLoad = false;
dojo.config._deferParsing = true;
}

d.addOnLoad(function(){

// set the classes
var b = dojo.body();
if(theme){
dojo.removeClass(b, defTheme);
if(!d.hasClass(b, theme)){ d.addClass(b, theme); }
var n = d.byId("themeStyles");
if(n){ d.destroy(n); }
}
if(testMode){ d.addClass(b, testMode); }
if(dojo.config._deferParsing){
// attempt to elimiate race condition introduced by this
// test helper file.  120ms to allow CSS to finish/process?
setTimeout(dojo.hitch(d.parser, "parse", b), 120);
}

});
}

})();

if(window.location.href.indexOf(“?”) >-1){

var str = window.location.href.substr(window.location.href.indexOf(“?”)+1).split(/#/);

var ary = str[0].split(/&/);

for(var i=0;i<ary.length;i++){

var split = ary[i].split(/=/),

key = split[0],

value = split[1];

switch(key){

case “locale”:

// locale string | null

dojo.config.locale = locale = value;

break;

case “dir”:

// rtl | null

document.getElementsByTagName(“html”)[0].dir = value;

break;

case “theme”:

// tundra | soria | noir | squid | nihilo | null

theme = value;

break;

case “a11y”:

if(value){testMode = “dijit_a11y”;}

}

}

}

// always include the default theme files:

if(theme || testMode){

if(theme){

var themeCss = d.moduleUrl(“dijit.themes”,theme+”/”+theme+”.css”);

var themeCssRtl = d.moduleUrl(“dijit.themes”,theme+”/”+theme+”_rtl.css”);

document.write(‘<link rel=”stylesheet”type=”text/css”href=”‘+themeCss+’”>’);

document.write(‘<link rel=”stylesheet”type=”text/css”href=”‘+themeCssRtl+’”>’);

}

if(dojo.config.parseOnLoad){

dojo.config.parseOnLoad = false;

dojo.config._deferParsing = true;

}

d.addOnLoad(function(){

// set the classes

var b = dojo.body();

if(theme){

dojo.removeClass(b,defTheme);

if(!d.hasClass(b,theme)){d.addClass(b,theme);}

var n = d.byId(“themeStyles”);

if(n){d.destroy(n);}

}

if(testMode){d.addClass(b,testMode);}

if(dojo.config._deferParsing){

// attempt to elimiate race condition introduced by this

// test helper file. 120ms to allow CSS to finish/process?

setTimeout(dojo.hitch(d.parser,“parse”,b),120);

}

});

}

})();

Everything – Cross Site Scripting

Details

Affected Software:Dojo Toolkit SDK

Fixed in Version: 1.4.2

Issue Type:Cross Site Scripting (XSS)

Original Code: Found Here

Description

This was a bug reported by the Gotham Digital Science against the Dojo toolkit SDK.  The Dojo toolkit is a popular toolkit used by numerous websites… so in essence this bug provided attackers an opportunity to XSS a large number of websites across the Internet.

The bug begins by the capturing of untrusted parameter values from the querystring.  This is done by the following JavaScript:

1
var qstr = window.location.search.substr(1);

qstr is then split based on the “&” character,proving values for various JavaScript variables including DoJoURL and TestURL.   The attacker is free to provide arbitrary values for DoJoURL and TestURL by simply providing the proper querystring values.  For example:

runner.html?dojoUrl=attacker-controlled&testUrl=attackercontrolled

the attacker supplied values are then used in a document.write() statement,giving the attacker the opprotuntiy to inject arbitrary client side script into any website that happens to include the Dojo library.  The vulnerable document.write() statements are provided below:

document.write(“<scr”+”ipt type=’text/javascript’djConfig=’isDebug:true’src=’”+dojoUrl+”‘></scr”+”ipt>”);

document.write(“<scr”+”ipt type=’text/javascript’src=’”+testUrl+”.js’></scr”+”ipt>”);

The Dojo developers addressed this vulnerability by replacing characters from the attacker controlled input.  The specific regular expression used is provided below:

value=tp[1].replace(/[<>"']/g,“”);

I see a major issue with this code fix… can you spot it as well?

Developers Solution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
                <script type="text/javascript">
                        // workaround for bug in Safari 3.  See #7189
                        if (/3[\.0-9]+ Safari/.test(navigator.appVersion))
                        {
                                window.console = {
                                    origConsole:window.console,
                                    log:function(s){
                                                this.origConsole.log(s);
                                        },
                                        info:function(s){
                                                this.origConsole.info(s);
                                        },
                                        error:function(s){
                                                this.origConsole.error(s);
                                        },
                                        warn:function(s){
                                                this.origConsole.warn(s);
                                        }
                               };
                        }
                </script>
 
                <script type="text/javascript">
                        window.dojoUrl = "../../dojo/dojo.js";
                        window.testUrl = "";
                        window.testModule = "";
 
                        // parse out our test URL and our Dojo URL from the query string
                        var qstr = window.location.search.substr(1);
                        if(qstr.length){
                                var qparts = qstr.split("&");
                                for(var x=0;x<qparts.length;x++){
-                                       var tp = qparts[x].split("=");
-                                       if(tp[0] == "dojoUrl"){
-                                               window.dojoUrl = tp[1];
-                                       }
-                                       if(tp[0] == "testUrl"){
-                                               window.testUrl = tp[1];
-                                       }
-                                       if(tp[0] == "testModule"){
-                                               window.testModule = tp[1];
-                                       }
-                                       if(tp[0] == "registerModulePath"){
-                                               var modules = tp[1].split(";");
-                                               window.registerModulePath=[];
-                                               for (var i=0;i<modules.length;i++){
-                                                        window.registerModulePath.push(modules[i].split(","));
-                                               }
-                                       }
+                                       var tp = qparts[x].split("="),name=tp[0],value=tp[1].replace(/[<>"']/g,"");  // replace() to avoid XSS attack 
+                                       switch(name){ 
+                                               case "dojoUrl": 
+                                               case "testUrl": 
+                                               case "testModule": 
+                                                       window[name] = value; 
+                                                       break; 
+                                               case "registerModulePath": 
+                                                       var modules = value.split(";")
+                                                       window.registerModulePath=[]
+                                                       for (var i=0;i<modules.length;i++){ 
+                                                               window.registerModulePath.push(modules[i].split(","))
+                                                       } 
+                                               break; 
                                }
                        }
 
                        document.write("<scr"+"ipt type='text/javascript' djConfig='isDebug:true' src='"+dojoUrl+"'></scr"+"ipt>");
                </script>
                <script type="text/javascript">
                        try{
                                dojo.require("doh.runner");
                        }catch(e){
                                document.write("<scr"+"ipt type='text/javascript' src='runner.js'></scr"+"ipt>");
                        }
                        if(testUrl.length){
                                document.write("<scr"+"ipt type='text/javascript' src='"+testUrl+".js'></scr"+"ipt>");
                        }
                </script>
                <style type="text/css">
                        @import "../../dojo/resources/dojo.css";
                        var SHRSB_Globals ={"src":"http:\/\/spotthevuln.com\/wordpress\/wp-content\/plugins\/sexybookmarks\/spritegen_default","perfoption":null};