From f6e9e30be0e1e263408905b41dc8c4de327e4aeb Mon Sep 17 00:00:00 2001 From: henri Date: Sat, 7 May 2011 21:14:21 +0000 Subject: [PATCH] o [NSE] Added xmpp.nse, which collects XMPP server information [Vasiliy Kulikov] --- CHANGELOG | 2 + scripts/xmpp.nse | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 scripts/xmpp.nse diff --git a/CHANGELOG b/CHANGELOG index 6530fe982..a339431ab 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,7 @@ # Nmap Changelog ($Id$); -*-text-*- +o [NSE] Added xmpp.nse, which collects XMPP server information [Vasiliy Kulikov] + o [NSE] Added broadcast-avahi-dos.nse, which tries to detect if the hosts in the local network that are running Avahi are vulnerable to the NULL UDP packet denial of service (CVE-2011-1002). [Djalal] diff --git a/scripts/xmpp.nse b/scripts/xmpp.nse new file mode 100644 index 000000000..548aa2fc7 --- /dev/null +++ b/scripts/xmpp.nse @@ -0,0 +1,164 @@ +description = [[ +Connect to XMPP server (port 5222) and collect server information such as: +supported auth mechanisms, compression methods and whether TLS is supported +and mandatory. +]] + +--- +-- @output +-- PORT STATE SERVICE +-- 5222/tcp open xmpp-client +-- | xmpp: +-- | mechanism: CRAM-MD5 +-- | mechanism: LOGIN +-- | mechanism: PLAIN +-- | mechanism: DIGEST-MD5 +-- | mechanism: SCRAM-SHA-1 +-- | compression: zlib +-- | starttls +-- |_ Respects server name +-- +-- @args xmpp.server_name If set, overwrites hello name sent to the server. +-- It can be necessary if XMPP server's name differs from DNS name. +-- @args xmpp.alt_server_name If set, overwrites alternative hello name sent to the server. +-- This name should differ from the real DNS name. It is used to find out whether +-- the server refuses to talk if a wrong name is used. Default is ".". + + +author = "Vasiliy Kulikov" +license = "Same as Nmap--See http://nmap.org/book/man-legal.html" +categories = {"default", "safe", "discovery"} + +require 'shortport' +require 'stdnse' +require 'dns' + +-- This is a trivial XML processor. It doesn't fully support XML, but it should +-- be sufficient for the basic XMPP stream handshake. If you see stanzas with uncommon +-- symbols, feel free to enhance these regexps. +local parse_tag = function(s) + local _, _, contents, empty, name = string.find(s, "([^<]*)\<(/?)([?:%w-]+)") + local attrs = {} + if not name then + return + end + for k, v in string.gmatch(s, "%s([%w:]+)='([^']+)'") do + attrs[k] = v + end + for k, v in string.gmatch(s, "%s([%w:]+)=\"([^\"]+)\"") do + attrs[k] = v + end + + local finish = (empty ~= "") or (s:sub(#s-1) == '/>') + + return { name = name, + attrs = attrs, + start = (empty == ""), + contents = contents, + finish = finish } +end + +local log_tag = function(tag) + stdnse.print_debug(2, "%s: %s", SCRIPT_NAME, "name=" .. tag.name) + stdnse.print_debug(2, "%s: %s", SCRIPT_NAME, "finish=" .. tostring(tag.finish)) + stdnse.print_debug(2, "%s: %s", SCRIPT_NAME, "empty=" .. tostring(tag.empty)) + stdnse.print_debug(2, "%s: %s", SCRIPT_NAME, "contents=" .. tag.contents) +end + +local receive_tag = function(conn) + local status, data = conn:receive_buf(">", true) + if data then + stdnse.print_debug("%s %s", SCRIPT_NAME, data) + end + return status and parse_tag(data) +end + +local scan = function(host, port, server_name) + local client = nmap.new_socket() + local catch = function() + client:close() + end + local result = {} + + local try = nmap.new_try(catch) + + try(client:connect(host, port)) + local request = "" + + try(client:send(request)) + + local is_starttls, tls_required, in_error + while true do + local tag = receive_tag(client) + if not tag then break end + log_tag(tag) + if (tag.name == "stream:features" and tag.finish) then + break + end + + if tag.name == "starttls" then + is_starttls = true + elseif tag.name == "required" then + tls_required = true + elseif tag.name == "method" then + if tag.finish then + table.insert(result, "compression: " .. tag.contents) + end + elseif tag.name == "mechanism" then + if tag.finish then + table.insert(result, "mechanism: " .. tag.contents) + end + elseif tag.name == "c" then + if tag.attrs and tag.attrs.hash then + table.insert(result, "hash: " .. tag.attrs.hash) + end + end + + if tag.name == "stream:error" then + in_error = tag.start + if in_error then + table.insert(result, "Error:") + end + elseif in_error then + if tag.name == "text" then + if tag.finish then + table.insert(result, " text: " .. tag.contents) + end + else + table.insert(result, " " .. tag.name) + end + end + end + + if is_starttls then + if tls_required then + table.insert(result, "starttls (required)") + else + table.insert(result, "starttls") + end + end + return result +end + +local is_error = function(table) + for i,v in ipairs(table) do + if v == "Error:" then return true end + end +end + +portrule = shortport.port_or_service(5222, {"jabber", "xmpp-client"}) +action = function(host, port) + local server_name = stdnse.get_script_args("xmpp.server_name") or host.targetname + local alt_server_name = stdnse.get_script_args("xmpp.alt_server_name") or "." + stdnse.print_debug(2, "%s: %s", SCRIPT_NAME, "server = " .. server_name) + + local result = scan(host, port, server_name) + local alt_result = scan(host, port, alt_server_name) + if is_error(result) ~= is_error(alt_result) then + table.insert(result, "Respects server name") + else + table.insert(result, "Ignores server name") + end + + return stdnse.format_output(true, result) +end