Enumerate potential DOM-based XSS vulnerable code
euronymous — 28 April, 2011 - 10:01
While waiting for Stefano di Paola release of DOMinator,
I've spent a little amount of time writing a Ruby script that uses Stefano regular expressions and list the potentially DOM-based XSS vulnerable
piece of code.
The output needs manual verification, but at least it's something.
Thanks .mario and Stefano for your research on the topic. And thanks Michal for the "bugfix" regarding regex :-)
A sample of the output is the following:
The output needs manual verification, but at least it's something.
Thanks .mario and Stefano for your research on the topic. And thanks Michal for the "bugfix" regarding regex :-)
# Given a set of JS/HTML/whatever files it search for potential DOM-based XSS
# injection points based on regular expressions from https://code.google.com/p/domxsswiki/wiki/FindingDOMXSS
#
# author: Michele "antisnatchor" Orru' (regex credit goes to Mario ".mario" Heiderich)
# v. 0.1
require "net/http"
require "net/https"
require "uri"
require "erb"
require "singleton"
require "rubygems"
MAIN_URL = 'http://compraonline.mediaworld.it'
MAIN_DOMAIN = 'compraonline.mediaworld.it'
PORT = 80
HTTP_PROXY_HOST = '172.31.229.10'
HTTP_PROXY_PORT = 8888
PATHS_TO_TEST = ['/resources/script/new_hp.js',
'/resources/script/commonTop.js',
'/resources/script/scripter.js'
]
puts "[+] starting requests to #{MAIN_URL}"
Net::HTTP::Proxy(HTTP_PROXY_HOST, HTTP_PROXY_PORT).start(MAIN_DOMAIN) {|http|
PATHS_TO_TEST.each{|path|
url = URI.parse(MAIN_URL + ':' + PORT.to_s + path)
req = Net::HTTP::Get.new(url.path)
http.request(req) do |res|
line = 1
response = res.body.to_s.split("\n")
response.each{|i|
# apply DOM-based xss regex to each HTTP response line, printing out lineNumber and lineContent
# that would potentially be vulnerable to DOM-based XSS (NEED MANUAL VERIFICATION!)
if(i.scan(/((src|href|data|location|code|value|action)\s*["'\]]*\s*\+?\s*=)|((replace|assign|navigate|getResponseHeader|open(Dialog)?|showModalDialog|eval|evaluate|execCommand|execScript|setTimeout|setInterval)\s*["'\]]*\s*\()/).size > 0 ||
i.scan(/(location\s*[\[.])|([.\[]\s*["']?\s*(arguments|dialogArguments|innerHTML|write(ln)?|open(Dialog)?|showModalDialog|cookie|URL|documentURI|baseURI|referrer|name|opener|parent|top|content|self|frames)\W)|(localStorage|sessionStorage|Database)/).size > 0)
puts "[#{path}]-#{line}: #{i}"
end
line += 1
}
end
}
}
A sample of the output is the following:
[/resources/script/commonTop.js]-104: top.location.href = apUrl;
[/resources/script/commonTop.js]-108: top.location.href = url;
[/resources/script/commonTop.js]-113: document.location.href = "http://" + server + "/webapp/wcs/stores/servlet/ListOrdersView?" +apDefUrl;
[/resources/script/commonTop.js]-117: top.location.href = "http://" + server + "/webapp/wcs/stores/servlet/BrandsView?" + apDefUrl;
[/resources/script/commonTop.js]-124: document.cookie = name + "=" + "; expires=Thu, 01-Jan-70 00:00:01 GMT";
[/resources/script/commonTop.js]-125: top.location.href = "http://" + serverMobi;
[/resources/script/commonTop.js]-127: top.location.href = "http://" + server + "/webapp/wcs/stores/servlet/PartnerVisit?onlyInsert
=Y&partnerId=7990000000000006500&storeId=20000&bannerId=home_mwcol&url=compraonline.mediaworld.it/html/LINKPROMO.html?content=/offerte/mobi/sez1.html";
[/resources/script/commonTop.js]-132: document.location.href = "http://" + server + "/webapp/wcs/stores/servlet/ContactUsView?storeId=20000";
[/resources/script/commonTop.js]-136: formObj.searchString.value = formObj.searchString.value.replace(/%/g,"");
[/resources/script/commonTop.js]-138: if( formObj.searchString.value.replace(/^\s+|\s+$/g,"").length < 2 )
[/resources/script/commonTop.js]-149: formObj.categoryId.value = document.getElementById('catGroupId').options[document.getElement
ById('catGroupId').selectedIndex].value;
[/resources/script/commonTop.js]-156: window.open("http://" + server +"/webapp/wcs/stores/servlet/NewsletterView?" + apDefUrl,"newsletter"
,"width=440,height=354,scrollbars=no,resizable=no");
[/resources/script/scripter.js]-75: this.layer.document.writeln(body[i]);
[/resources/script/scripter.js]-82: this.element.innerHTML = body;
[/resources/script/scripter.js]-88: this.element.innerHTML = body;
