diff --git a/scripts/http-cross-domain-policy.nse b/scripts/http-cross-domain-policy.nse index 91fea0e75..0dcc723cf 100644 --- a/scripts/http-cross-domain-policy.nse +++ b/scripts/http-cross-domain-policy.nse @@ -5,12 +5,13 @@ local nmap = require "nmap" local shortport = require "shortport" local table = require "table" local string = require "string" +local slaxml = require "slaxml" description = [[ -Checks the cross-domain policy file (/crossdomain.xml) in web applications and lists the trusted -domains. Overly permissive settings enable Cross Site Request Forgery attacks and may allow attackers - to access sensitive data. This script is useful to detect permissive configurations and possible -domain names available for purchase to exploit the application. +Checks the cross-domain policy file (/crossdomain.xml) and the client-acces-policy file (/clientaccesspolicy.xml) +in web applications and lists the trusted domains. Overly permissive settings enable Cross Site Request Forgery +attacks and may allow attackers to access sensitive data. This script is useful to detect permissive +configurations and possible domain names available for purchase to exploit the application. The script queries instantdomainsearch.com to lookup the domains. This functionality is turned off by default, to enable it set the script argument http-crossdomainxml.domain-lookup. @@ -21,44 +22,118 @@ References: * https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html * https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/CrossDomain_PolicyFile_Specification.pdf * https://www.owasp.org/index.php/Test_RIA_cross_domain_policy_%28OTG-CONFIG-008%29 +* http://acunetix.com/vulnerabilities/web/insecure-clientaccesspolicy-xml-file ]] --- -- @usage nmap --script http-crossdomainxml --- @usage nmap -p80 --script http-crossdomainxml --script-args domain-lookup=true +-- @usage nmap -p 80 --script http-crossdomainxml --script-args http.domain-lookup=true -- -- @output -- PORT STATE SERVICE REASON --- 80/tcp open http syn-ack ttl 40 --- | http-crossdomainxml: +-- 8080/tcp open http-proxy syn-ack +-- | http-crossdomainxml-slaxml: -- | VULNERABLE: -- | Cross-domain policy file (crossdomain.xml) --- | State: VULNERABLE (Exploitable) +-- | State: VULNERABLE -- | A cross-domain policy file specifies the permissions that a web client such as Java, Adobe Flash, Adobe Reader, --- | etc. use to access data across different domains. Overly permissive configurations enables Cross-site Request +-- | etc. use to access data across different domains. A client acces policy file is similar to cross-domain policy +-- | but is used for M$ Silverlight applications. Overly permissive configurations enables Cross-site Request -- | Forgery attacks, and may allow third parties to access sensitive data meant for the user. -- | Check results: --- | --- | --- | --- | --- | --- | +-- | /crossdomain.xml: +-- | +-- | +-- | +-- | ' +-- | +-- | /clientaccesspolicy.xml: +-- | +-- | +-- | +-- | +-- | +-- | +-- | +-- | +-- | +-- | +-- | +-- | +-- | +-- | +-- | -- | Extra information: --- | Trusted domains:0xdeadbeefcafe2.com, 0xdeadbeefcafe.com --- | --- | [!]Trusted domains available for purchase:0xdeadbeefcafe2.com +-- | Trusted domains:example.com, exampleobjects.com, example.co.in, *, example.me, exampleobjects.me +-- | Use the script argument 'domain-lookup' to find trusted domains available for purchase -- | References: -- | http://gursevkalra.blogspot.com/2013/08/bypassing-same-origin-policy-with-flash.html --- | https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html +-- | http://sethsec.blogspot.com/2014/03/exploiting-misconfigured-crossdomainxml.html -- | https://www.owasp.org/index.php/Test_RIA_cross_domain_policy_%28OTG-CONFIG-008%29 +-- | http://acunetix.com/vulnerabilities/web/insecure-clientaccesspolicy-xml-file -- | https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/CrossDomain_PolicyFile_Specification.pdf --- |_ http://sethsec.blogspot.com/2014/03/exploiting-misconfigured-crossdomainxml.html +-- |_ https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html +-- -- -- @args http-crossdomainxml.domain-lookup Boolean to check domain availability. Default:false +-- +-- @xmloutput +-- Cross-domain and Client Access policies. +-- VULNERABLE +-- +-- A cross-domain policy file specifies the permissions that a +-- web client such as Java, Adobe Flash, Adobe Reader, etc. use to +-- access data across different domains. A client acces policy file +-- is similar to cross-domain policy but is used for M$ Silverlight +-- applications. Overly permissive configurations enables Cross-site +-- Request Forgery attacks, and may allow third parties to access +-- sensitive data meant for the user. +--
+-- +--
+-- /crossdomain.xml +-- <cross-domain-policy> +-- <allow-access-from domain="*.example.com"/> +-- <allow-access-from domain="*.exampleobjects.com"/> +-- <allow-access-from domain="*.example.co.in"/>' +-- </cross-domain-policy> +--
+-- +-- /clientaccesspolicy.xml +-- <?xml version="1.0" encoding="utf8"?> +-- </accesspolicy> <crossdomainaccess> <policy> +-- <allowfrom httprequestheaders="SOAPAction"> <domain +-- uri="*"/> <domain uri="*.example.me"/> <domain +-- uri="*.exampleobjects.me"/> </allowfrom> <granto> +-- <resource path="/" includesubpaths="true"/> +-- </granto> </policy> </crossdomainaccess> +-- </accesspolicy> +--
+-- +-- +-- Trusted domains:example.com, exampleobjects.com, +-- example.co.in, *, example.me, exampleobjects.me Use the script argument +-- 'domain-lookup' to find trusted domains available for +-- purchase +--
+-- +-- +-- https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html +-- +-- https://www.owasp.org/index.php/Test_RIA_cross_domain_policy_%28OTG-CONFIG-008%29 +-- +-- http://sethsec.blogspot.com/2014/03/exploiting-misconfigured-crossdomainxml.html +-- +-- https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/CrossDomain_PolicyFile_Specification.pdf +-- +-- http://acunetix.com/vulnerabilities/web/insecure-clientaccesspolicy-xml-file +-- +-- http://gursevkalra.blogspot.com/2013/08/bypassing-same-origin-policy-with-flash.html +--
+-- --- -author = {"Seth Art ", "Paulino Calderon "} +author = {"Seth Art ", "Paulino Calderon ", "Gyanendra Mishra"} license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"safe", "external", "vuln"} @@ -79,7 +154,7 @@ local tlds_instantdomainsearch = {".com", ".net", ".org", ".co", ".info", ".biz" -- {"label":"snmap","tld":"com","isBid":false,"price":2994,"aftermarketProvider":"afternic.com", -- "rank":9.352656364440918,"search":"ngram"} --- -function check_domain (domain) +local function check_domain (domain) local name, tld = domain:match("(%w*)%.*(%w*%.%w+)$") if not(stdnse.contains(tlds_instantdomainsearch, tld)) then stdnse.debug(1, "TLD '%s' is not supported by instantdomainsearch.com. Check manually.", tld) @@ -102,55 +177,82 @@ end function check_crossdomain(host, port, lookup) local trusted_domains = {} local trusted_domains_available = {} + local content = {} local req_opt = {redirect_ok=function(host,port) local c = 3 - return function(url) + return function(uri) if ( c==0 ) then return false end c = c - 1 return true end end} - local req = http.get(host, port, "/crossdomain.xml", req_opt) - if req.status and req.status == 200 then - for line in req.body:gmatch("") do - line = line:gsub("^%s*(.-)%s*$", "%1") - --Matches wildcard, which means vulnerable as any host can comunicate with app - if line:match("domain%=\"%*\"") then - stdnse.debug(1, "Wildcard detected!") - table.insert(trusted_domains, "*") - else - --Parse domains - line = line:match("domain%=\"(.-)\""):gsub("%*%.", "") - stdnse.debug(1, "Extracted line: %s", line) + local domain_table = {} + local CROSSDOMAIN = { + uri = '/crossdomain.xml', + attribute = function(name, value) + if name == 'domain' then + table.insert(domain_table, value) + end + end, + } - local domain = line:match("(%w*%.*%w+%.%w+)$") - if domain ~= nil then - --Deals with tlds with double extension - local tld = domain:match("%w*(%.%w*)%.%w+$") - if tld ~= nil and not(stdnse.contains(tlds_instantdomainsearch, tld)) then - domain = domain:match("%w*%.(.*)$") - end - --We add domains only once as they can appear multiple times - if not(stdnse.contains(trusted_domains, domain)) then - stdnse.debug(1, "Added trusted domain:%s", domain) - table.insert(trusted_domains, domain) - --Lookup domains if script argument is set - if ( lookup ) then - if check_domain(domain) == "false" then - stdnse.debug(1, "Domain '%s' is available for purchase!", domain) - table.insert(trusted_domains_available, domain) + local CLIENTACCESS = { + uri = '/clientaccesspolicy.xml', + attribute = function(name, value) + if name == 'uri' then + table.insert(domain_table, value) + end + end, + } + local lists = {} + table.insert(lists, CROSSDOMAIN) + table.insert(lists, CLIENTACCESS) + for _, list in pairs(lists) do + local req = http.get(host, port, list.uri, req_opt) + if req.status and req.status == 200 then + domain_table = {} + local parser = slaxml.parser:new({attribute = list.attribute}) + parser:parseSAX (req.body) + table.insert(content, {name = list.uri, body = req.body}) + for _, domain in pairs(domain_table) do + --Matches wildcard, which means vulnerable as any host can comunicate with app + if domain == '*' or domain == 'http://' or domain == 'https://' then + stdnse.debug(1, "Wildcard detected!") + table.insert(trusted_domains, domain) + else + --Parse domains + local line = domain:gsub("%*%.", "") + stdnse.debug(1, "Extracted line: %s", line) + local domain = line:match("(%w*%.*%w+%.%w+)$") + if domain ~= nil then + --Deals with tlds with double extension + local tld = domain:match("%w*(%.%w*)%.%w+$") + if tld ~= nil and not(stdnse.contains(tlds_instantdomainsearch, tld)) then + domain = domain:match("%w*%.(.*)$") + end + --We add domains only once as they can appear multiple times + if not(stdnse.contains(trusted_domains, domain)) then + stdnse.debug(1, "Added trusted domain:%s", domain) + table.insert(trusted_domains, domain) + --Lookup domains if script argument is set + if ( lookup ) then + if check_domain(domain) == "false" then + stdnse.debug(1, "Domain '%s' is available for purchase!", domain) + table.insert(trusted_domains_available, domain) + end end end - end + stdnse.debug(1, "Extracted domain: %s", domain) end - stdnse.debug(1, "Extracted domain: %s", domain) end end - - return true, trusted_domains, trusted_domains_available, req.body end - return nil + if (#trusted_domains> 0) then + return true, trusted_domains, trusted_domains_available, content + else + return nil + end end @@ -159,26 +261,31 @@ action = function(host, port) local vuln_report = vulns.Report:new(SCRIPT_NAME, host, port) local vuln = { - title = 'Cross-domain policy file (crossdomain.xml)', + title = 'Cross-domain and Client Access policies.', state = vulns.STATE.NOT_VULN, description = [[ A cross-domain policy file specifies the permissions that a web client such as Java, Adobe Flash, Adobe Reader, -etc. use to access data across different domains. Overly permissive configurations enables Cross-site Request +etc. use to access data across different domains. A client acces policy file is similar to cross-domain policy +but is used for M$ Silverlight applications. Overly permissive configurations enables Cross-site Request Forgery attacks, and may allow third parties to access sensitive data meant for the user.]], references = { 'http://sethsec.blogspot.com/2014/03/exploiting-misconfigured-crossdomainxml.html', 'http://gursevkalra.blogspot.com/2013/08/bypassing-same-origin-policy-with-flash.html', 'https://www.adobe.com/devnet/articles/crossdomain_policy_file_spec.html', 'https://www.adobe.com/devnet-docs/acrobatetk/tools/AppSec/CrossDomain_PolicyFile_Specification.pdf', - 'https://www.owasp.org/index.php/Test_RIA_cross_domain_policy_%28OTG-CONFIG-008%29' + 'https://www.owasp.org/index.php/Test_RIA_cross_domain_policy_%28OTG-CONFIG-008%29', + 'http://acunetix.com/vulnerabilities/web/insecure-clientaccesspolicy-xml-file' }, } - local check, domains, domains_available, content = check_crossdomain(host, port, lookup) - + local mt = {__tostring=function(p) return ("%s:\n %s"):format(p.name, p.body:gsub("\n", "\n ")) end} + for i, _ in pairs(content) do + setmetatable(content[i], mt) + tostring(content[i]) + end if check then - if stdnse.contains(domains, "*") then - vuln.state = vulns.STATE.EXPLOIT + if stdnse.contains(domains, "*") or stdnse.contains(domains, "https://") or stdnse.contains(domains, "http://") then + vuln.state = vulns.STATE.VULN else vuln.state = vulns.STATE.LIKELY_VULN end @@ -189,8 +296,7 @@ Forgery attacks, and may allow third parties to access sensitive data meant for end if lookup ~= nil and #domains_available>0 then vuln.state = vulns.STATE.EXPLOIT - vuln.extra_info = vuln.extra_info .. string.format("\n[!]Trusted domains available for purchase:%s", - stdnse.strjoin(', ', domains_available)) + vuln.extra_info = vuln.extra_info .. string.format("[!]Trusted domains available for purchase:%s", stdnse.strjoin(', ', domains_available)) end end