diff --git a/CHANGELOG b/CHANGELOG index 1e992c832..e681a3b31 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,8 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added the script icap-info, which tries to identify common ICAP + service names and list service and tag information. [Patrik Karlsson] + o [NSE] Added the script http-traceroute, which exploits the Max-Forwards HTTP header to detect reverse proxies. [Hani Benhabiles] diff --git a/scripts/icap-info.nse b/scripts/icap-info.nse new file mode 100644 index 000000000..b64f740a0 --- /dev/null +++ b/scripts/icap-info.nse @@ -0,0 +1,113 @@ +description = [[ +Tries a list of known ICAP service names and prints information about the ones +it detects. The Internet Content Adaptation Protocol (ICAP) is used to extend +transparent proxy server and is generally used for content filtering and +antivirus scanning. +]] + +--- +-- @usage +-- nmap -p 1344 --script icap-info +-- +-- @output +-- PORT STATE SERVICE +-- 1344/tcp open unknown +-- | icap-info: +-- | /avscan +-- | Service: C-ICAP/0.1.6 server - Clamav/Antivirus service +-- | ISTag: CI0001-000-0973-6314940 +-- | /echo +-- | Service: C-ICAP/0.1.6 server - Echo demo service +-- | ISTag: CI0001-XXXXXXXXX +-- | /srv_clamav +-- | Service: C-ICAP/0.1.6 server - Clamav/Antivirus service +-- | ISTag: CI0001-000-0973-6314940 +-- | /url_check +-- | Service: C-ICAP/0.1.6 server - Url_Check demo service +-- |_ ISTag: CI0001-XXXXXXXXX +-- +-- + +author = "Patrik Karlsson" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"safe", "discovery"} + +local shortport = require('shortport') + +portrule = shortport.port_or_service(1344, "icap") + +local function fail(err) return ("\n ERROR: %s"):format(err or "") end + +local function parseResponse(resp) + if ( not(resp) ) then + return + end + + local resp_p = { header = {}, rawheader = {} } + local resp_tbl = stdnse.strsplit("\r?\n", resp) + + if ( not(resp_tbl) or #resp_tbl == 0 ) then + stdnse.print_debug(2, "Received an invalid response from server") + return + end + + resp_p.status = tonumber(resp_tbl[1]:match("^ICAP/1%.0 (%d*) .*$")) + resp_p['status-line'] = resp_tbl[1] + + for i=2, #resp_tbl do + local key, val = resp_tbl[i]:match("^([^:]*):%s*(.*)$") + if ( not(key) or not(val) ) then + stdnse.print_debug(2, "Failed to parse header: %s", resp_tbl[i]) + else + resp_p.header[key:lower()] = val + end + table.insert(resp_p.rawheader, resp_tbl[i]) + end + return resp_p +end + +action = function(host, port) + + local services = {"/avscan", "/echo", "/srv_clamav", "/url_check", "/nmap" } + local headers = {"Service", "ISTag"} + local probe = { + "OPTIONS icap://%s%s ICAP/1.0", + "Host: %s", + "User-Agent: nmap icap-client/0.01", + "Encapsulated: null-body=0" + } + local hostname = stdnse.get_hostname(host) + local result = {} + + for _, service in ipairs(services) do + local socket = nmap.new_socket() + socket:set_timeout(5000) + if ( not(socket:connect(host, port)) ) then + return fail("Failed to connect to server") + end + + local request = (stdnse.strjoin("\r\n", probe) .. "\r\n\r\n"):format(hostname, service, hostname) + + if ( not(socket:send(request)) ) then + socket:close() + return fail("Failed to send request to server") + end + + local status, resp = socket:receive_buf("\r\n\r\n") + if ( not(status) ) then + return fail("Failed to receive response from server") + end + + local resp_p = parseResponse(resp) + if ( resp_p and resp_p.status == 200 ) then + local result_part = { name = service } + for _, h in ipairs(headers) do + if ( resp_p.header[h:lower()] ) then + table.insert(result_part, ("%s: %s"):format(h, resp_p.header[h:lower()])) + end + end + table.insert(result, result_part) + end + end + return stdnse.format_output(true, result) +end \ No newline at end of file diff --git a/scripts/script.db b/scripts/script.db index c09e624a0..c8cca500a 100644 --- a/scripts/script.db +++ b/scripts/script.db @@ -183,6 +183,7 @@ Entry { filename = "http-wordpress-enum.nse", categories = { "auth", "intrusive" Entry { filename = "http-wordpress-plugins.nse", categories = { "discovery", "intrusive", } } Entry { filename = "iax2-brute.nse", categories = { "brute", "intrusive", } } Entry { filename = "iax2-version.nse", categories = { "version", } } +Entry { filename = "icap-info.nse", categories = { "discovery", "safe", } } Entry { filename = "imap-brute.nse", categories = { "auth", "intrusive", } } Entry { filename = "imap-capabilities.nse", categories = { "default", "safe", } } Entry { filename = "informix-brute.nse", categories = { "brute", "intrusive", } }