mirror of
https://github.com/nmap/nmap.git
synced 2025-12-06 04:31:29 +00:00
165 lines
5.1 KiB
Lua
165 lines
5.1 KiB
Lua
description = [[
|
|
Connects to an XMPP server (port 5222) and collects 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 = "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' xml:lang='ru-RU' to='" .. server_name .. "' version='1.0'>"
|
|
|
|
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
|