diff --git a/scripts/http-phpself-xss.nse b/scripts/http-phpself-xss.nse new file mode 100644 index 000000000..96f1f13b4 --- /dev/null +++ b/scripts/http-phpself-xss.nse @@ -0,0 +1,157 @@ +description=[[ +Crawls a web server and attempts to find PHP files vulnerable to reflected cross site scripting via the variable $_SERVER["PHP_SELF"]. + +This script crawls the webserver to create a list of PHP files and then sends an attack vector/probe to identify PHP_SELF cross site scripting vulnerabilities. +PHP_SELF XSS refers to reflected cross site scripting vulnerabilities caused by the lack of sanitation of the variable $_SERVER["PHP_SELF"] in PHP scripts. This variable is +commonly used in php scripts that display forms and when the script file name is needed. + +Examples of Cross Site Scripting vulnerabilities in the variable $_SERVER[PHP_SELF]: +*http://www.securityfocus.com/bid/37351 +*http://software-security.sans.org/blog/2011/05/02/spot-vuln-percentage +*http://websec.ca/advisories/view/xss-vulnerabilities-mantisbt-1.2.x + +The attack vector/probe used is: /'"/> +]] +--- +-- @usage +-- nmap --script=http-phpself-xss -p80 +-- nmap -sV --script http-self-xss +-- @output +-- PORT STATE SERVICE REASON +-- 80/tcp open http syn-ack +-- | http-phpself-xss: +-- | VULNERABLE: +-- | Unsafe use of $_SERVER["PHP_SELF"] in PHP files +-- | State: VULNERABLE (Exploitable) +-- | Description: +-- | PHP files are not handling safely the variable $_SERVER["PHP_SELF"] causing Reflected Cross Site Scripting vulnerabilities. +-- | +-- | Extra information: +-- | +-- | Vulnerable files with proof of concept: +-- | http://calder0n.com/sillyapp/three.php/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E +-- | http://calder0n.com/sillyapp/secret/2.php/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E +-- | http://calder0n.com/sillyapp/1.php/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E +-- | http://calder0n.com/sillyapp/secret/1.php/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E +-- | Spidering limited to: maxdepth=3; maxpagecount=20; withinhost=calder0n.com +-- | References: +-- | https://www.owasp.org/index.php/Cross-site_Scripting_(XSS) +-- |_ http://php.net/manual/en/reserved.variables.server.php +-- @args http-phpself-xss.uri URI. Default: / +-- @args http-phpself-xss.timeout Spidering timeout. Default:10000 +author = "Paulino Calderon" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"fuzzer", "intrusive", "vuln"} + +local http = require 'http' +local httpspider = require 'httpspider' +local shortport = require 'shortport' +local url = require 'url' +local stdnse = require 'stdnse' +local vulns = require 'vulns' + +portrule = shortport.http + +-- PHP_SELF Attack vector +local PHP_SELF_PROBE = '/%27%22/%3E%3Cscript%3Ealert(1)%3C/script%3E' +local probes = {} + +--Checks if attack vector is in the response's body +--@param response Response table +--@return True if attack vector is found in response's body +local function check_probe_response(response) + stdnse.print_debug(3, "Probe response:\n%s", response.body) + if string.find(response.body, "'\"/>", 1, true) ~= nil then + return true + end + return false +end + +--Launches probe request +--@param host Hostname +--@param port Port number +--@param uri URL String +--@return True if page is vulnerable/attack vector was found in body +local function launch_probe(host, port, uri) + local probe_response + + --We avoid repeating probes. + --This is a temp fix since httpspider do not keep track of previously parsed links at the moment. + if probes[uri] then + return false + end + + stdnse.print_debug(1, "%s:HTTP GET %s%s", SCRIPT_NAME, uri, PHP_SELF_PROBE) + probe_response = http.get(host, port, uri .. PHP_SELF_PROBE) + + --save probe in list to avoid repeating it + probes[uri] = true + + if check_probe_response(probe_response) then + return true + end + return false +end + +--- +--main +--- +action = function(host, port) + local uri = stdnse.get_script_args(SCRIPT_NAME..".uri") or "/" + local timeout = stdnse.get_script_args(SCRIPT_NAME..'.timeout') or 10000 + local crawler = httpspider.Crawler:new(host, port, uri, { scriptname = SCRIPT_NAME } ) + crawler:set_timeout(timeout) + + local vuln = { + title = 'Unsafe use of $_SERVER["PHP_SELF"] in PHP files', + state = vulns.STATE.NOT_VULN, + description = [[ +PHP files are not handling safely the variable $_SERVER["PHP_SELF"] causing Reflected Cross Site Scripting vulnerabilities. + ]], + references = { + 'http://php.net/manual/en/reserved.variables.server.php', + 'https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)' + } + } + local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port) + + local vulnpages = {} + local probed_pages= {} + + while(true) do + local status, r = crawler:crawl() + if ( not(status) ) then + if ( r.err ) then + return stdnse.format_output(true, "ERROR: %s", r.reason) + else + break + end + end + + local parsed = url.parse(tostring(r.url)) + + --Only work with .php files + if ( parsed.path and parsed.path:match(".*.php") ) then + --The following port/scheme code was seen in http-backup-finder and its neat =) + local host, port = parsed.host, parsed.port + if ( not(port) ) then + port = (parsed.scheme == 'https') and 443 + port = port or ((parsed.scheme == 'http') and 80) + end + local escaped_link = parsed.path:gsub(" ", "%%20") + if launch_probe(host,port,escaped_link) then + table.insert(vulnpages, parsed.scheme..'://'..host..escaped_link..PHP_SELF_PROBE) + end + end + end + + if ( #vulnpages > 0 ) then + vuln.state = vulns.STATE.EXPLOIT + vulnpages.name = "Vulnerable files with proof of concept:" + vuln.extra_info = stdnse.format_output(true, vulnpages)..crawler:getLimitations() + end + + return vuln_report:make_output(vuln) + +end + diff --git a/scripts/script.db b/scripts/script.db index d3cd80f0d..6f5dc7d5d 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -163,6 +163,7 @@ Entry { filename = "http-open-proxy.nse", categories = { "default", "discovery", Entry { filename = "http-open-redirect.nse", categories = { "discovery", "intrusive", } } Entry { filename = "http-passwd.nse", categories = { "intrusive", "vuln", } } Entry { filename = "http-php-version.nse", categories = { "discovery", "safe", } } +Entry { filename = "http-phpself-xss.nse", categories = { "fuzzer", "intrusive", "vuln", } } Entry { filename = "http-proxy-brute.nse", categories = { "brute", "external", "intrusive", } } Entry { filename = "http-put.nse", categories = { "discovery", "intrusive", } } Entry { filename = "http-qnap-nas-info.nse", categories = { "discovery", "safe", } }