mirror of
https://github.com/nmap/nmap.git
synced 2025-12-09 14:11:29 +00:00
o Added UPnP-info NSE script by Thomas Buchanan. It gathers
information from the UPnP service (UDP port 1900) which listens on many network devices such as routers, printers, and networked media players.
This commit is contained in:
@@ -1,6 +1,11 @@
|
|||||||
|
|
||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o Added UPnP-info NSE script by Thomas Buchanan. It gathers
|
||||||
|
information from the UPnP service (UDP port 1900) which listens on
|
||||||
|
many network devices such as routers, printers, and networked media
|
||||||
|
players.
|
||||||
|
|
||||||
o Improved rpcinfo.nse to better sort and display available RPC
|
o Improved rpcinfo.nse to better sort and display available RPC
|
||||||
services. [Sven Klemm]
|
services. [Sven Klemm]
|
||||||
|
|
||||||
|
|||||||
155
scripts/UPnP-info.nse
Normal file
155
scripts/UPnP-info.nse
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
-- UPnP network information script
|
||||||
|
-- rev 0.2 (1-9-2007)
|
||||||
|
|
||||||
|
id = "UPnP"
|
||||||
|
|
||||||
|
description = "Attempts to extract system information from UPnP service"
|
||||||
|
|
||||||
|
author = "Thomas Buchanan <tbuchanan@thecompassgrp.net>"
|
||||||
|
|
||||||
|
license = "See nmaps COPYING for licence"
|
||||||
|
|
||||||
|
categories = {"safe"}
|
||||||
|
|
||||||
|
require("stdnse")
|
||||||
|
require("shortport")
|
||||||
|
require("strbuf")
|
||||||
|
|
||||||
|
portrule = shortport.portnumber(1900, "udp", {"open", "open|filtered"})
|
||||||
|
|
||||||
|
action = function(host, port)
|
||||||
|
|
||||||
|
-- create the socket used for our connection
|
||||||
|
local socket = nmap.new_socket()
|
||||||
|
|
||||||
|
-- set a reasonable timeout value
|
||||||
|
socket:set_timeout(5000)
|
||||||
|
|
||||||
|
-- do some exception handling / cleanup
|
||||||
|
local catch = function()
|
||||||
|
socket:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
local try = nmap.new_try(catch)
|
||||||
|
|
||||||
|
-- connect to the potential UPnP system
|
||||||
|
try(socket:connect(host.ip, port.number, "udp"))
|
||||||
|
|
||||||
|
local payload = strbuf.new()
|
||||||
|
|
||||||
|
-- for details about the UPnP message format, see http://upnp.org/resources/documents.asp
|
||||||
|
payload = payload .. "M-SEARCH * HTTP/1.1\r\n"
|
||||||
|
payload = payload .. "Host:239.255.255.250:1900\r\n"
|
||||||
|
payload = payload .. "ST:upnp:rootdevice\r\n"
|
||||||
|
payload = payload .. "Man:\"ssdp:discover\"\r\n"
|
||||||
|
payload = payload .. "MX:3\r\n\r\n"
|
||||||
|
|
||||||
|
try(socket:send(strbuf.dump(payload)))
|
||||||
|
|
||||||
|
local status
|
||||||
|
local response
|
||||||
|
|
||||||
|
-- read in any response we might get
|
||||||
|
status, response = socket:receive_bytes(1)
|
||||||
|
|
||||||
|
if (not status) or (response == "TIMEOUT") then
|
||||||
|
socket:close()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- since we got something back, the port is definitely open
|
||||||
|
nmap.set_port_state(host, port, "open")
|
||||||
|
|
||||||
|
-- buffer to hold script output
|
||||||
|
local output
|
||||||
|
|
||||||
|
if response ~= nil then
|
||||||
|
-- We should get a response back that has contains one line for the server, and one line for the xml file location
|
||||||
|
-- these match any combination of upper and lower case responses
|
||||||
|
local server, location
|
||||||
|
server = string.match(response, "[Ss][Ee][Rr][Vv][Ee][Rr]:(.-)\010")
|
||||||
|
if server ~= nil then output = server .. "\n" end
|
||||||
|
location = string.match(response, "[Ll][Oo][Cc][Aa][Tt][Ii][Oo][Nn]:(.-)\010")
|
||||||
|
if location ~= nil then
|
||||||
|
output = output .. "Location: " .. location
|
||||||
|
|
||||||
|
local v = nmap.verbosity()
|
||||||
|
|
||||||
|
-- the following check can output quite a lot of information, so we require at least one -v flag
|
||||||
|
if v > 0 then
|
||||||
|
-- split the location into an IP address, port, and path name for the xml file
|
||||||
|
local xhost, xport, xfile
|
||||||
|
xhost = string.match(location, "http://(.-)/")
|
||||||
|
-- check to see if the host portionof the location specifies a port
|
||||||
|
-- if not, use port 80 as a standard web server port
|
||||||
|
if xhost ~= nil and string.match(xhost, ":") then
|
||||||
|
xport = string.match(xhost, ":(.*)")
|
||||||
|
xhost = string.match(xhost, "(.*):")
|
||||||
|
end
|
||||||
|
|
||||||
|
if xport == nil then
|
||||||
|
xport = 80
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if the IP address in the location matches the IP address we're scanning
|
||||||
|
-- if not, alert the user, but continue to scan the IP address we're interested in
|
||||||
|
if xhost ~= host.ip then
|
||||||
|
output = output .. "\n !! Location did not match target IP address !! "
|
||||||
|
-- return output
|
||||||
|
xhost = host.ip
|
||||||
|
end
|
||||||
|
|
||||||
|
-- extract the path name from the location field, but strip off the \r that HTTP servers return
|
||||||
|
xfile = string.match(location, "http://.-/(.-)\013")
|
||||||
|
if xfile ~= nil then
|
||||||
|
strbuf.clear(payload)
|
||||||
|
-- create an HTTP request for the file, using the host and port we extracted earlier
|
||||||
|
payload = payload .. "GET /" .. xfile .. " HTTP/1.1\r\n"
|
||||||
|
payload = payload .. "Accept: text/xml, application/xml, text/html\r\n"
|
||||||
|
payload = payload .. "User-Agent: Mozilla/4.0 (compatible; NMAP NSE)\r\n"
|
||||||
|
payload = payload .. "Host: " .. xhost .. ":" .. xport .. "\r\n"
|
||||||
|
payload = payload .. "Connection: Keep-Alive\r\n"
|
||||||
|
payload = payload .. "Cache-Control: no-cache\r\n"
|
||||||
|
payload = payload .. "Pragma: no-cache\r\n\r\n"
|
||||||
|
|
||||||
|
socket = nmap.new_socket()
|
||||||
|
socket:set_timeout(5000)
|
||||||
|
|
||||||
|
try(socket:connect(xhost, xport, "tcp"))
|
||||||
|
try(socket:send(strbuf.dump(payload)))
|
||||||
|
-- we're expecting an xml file, and for UPnP purposes it should end in </root>
|
||||||
|
status, response = socket:receive_buf("</root>", true)
|
||||||
|
|
||||||
|
if (status) and (response ~= "TIMEOUT") then
|
||||||
|
if string.match(response, "HTTP/1.%d 200") then
|
||||||
|
local webserver
|
||||||
|
-- extract information about the webserver that is handling responses for the UPnP system
|
||||||
|
webserver = string.match(response, "[Ss][Ee][Rr][Vv][Ee][Rr]:(.-)\010")
|
||||||
|
if webserver ~= nil then output = output .. "\nWebserver: " .. webserver end
|
||||||
|
|
||||||
|
-- the schema for UPnP includes a number of <device> entries, which can a number of interesting fields
|
||||||
|
for device in string.gmatch(response, "<deviceType>(.-)</UDN>") do
|
||||||
|
local fn, mnf, mdl, nm, ver
|
||||||
|
|
||||||
|
fn = string.match(device, "<friendlyName>(.-)</friendlyName>")
|
||||||
|
mnf = string.match(device, "<manufacturer>(.-)</manufacturer>")
|
||||||
|
mdl = string.match(device, "<modelDescription>(.-)</modelDescription>")
|
||||||
|
nm = string.match(device, "<modelName>(.-)</modelName>")
|
||||||
|
ver = string.match(device, "<modelNumber>(.-)</modelNumber>")
|
||||||
|
|
||||||
|
if fn ~= nil then output = output .. "\n Name: " .. fn end
|
||||||
|
if mnf ~= nil then output = output .. "\n Manufacturer: " .. mnf end
|
||||||
|
if mdl ~= nil then output = output .. "\n Model Descr: " .. mdl end
|
||||||
|
if nm ~= nil then output = output .. "\n Model Name: " .. nm end
|
||||||
|
if ver ~= nil then output = output .. "\n Model Version: " .. ver end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
socket:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -16,6 +16,7 @@ Entry{ category = "safe", filename = "SNMPsysdesr.nse" }
|
|||||||
Entry{ category = "vulnerability", filename = "SQLInject.nse" }
|
Entry{ category = "vulnerability", filename = "SQLInject.nse" }
|
||||||
Entry{ category = "intrusive", filename = "SSHv1-support.nse" }
|
Entry{ category = "intrusive", filename = "SSHv1-support.nse" }
|
||||||
Entry{ category = "intrusive", filename = "SSLv2-support.nse" }
|
Entry{ category = "intrusive", filename = "SSLv2-support.nse" }
|
||||||
|
Entry{ category = "safe", filename = "UPnP-info.nse" }
|
||||||
Entry{ category = "intrusive", filename = "anonFTP.nse" }
|
Entry{ category = "intrusive", filename = "anonFTP.nse" }
|
||||||
Entry{ category = "intrusive", filename = "bruteTelnet.nse" }
|
Entry{ category = "intrusive", filename = "bruteTelnet.nse" }
|
||||||
Entry{ category = "demo", filename = "chargenTest.nse" }
|
Entry{ category = "demo", filename = "chargenTest.nse" }
|
||||||
|
|||||||
Reference in New Issue
Block a user