summaryrefslogtreecommitdiffstats
path: root/scripts/broadcast-pc-duo.nse
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/broadcast-pc-duo.nse')
-rw-r--r--scripts/broadcast-pc-duo.nse132
1 files changed, 132 insertions, 0 deletions
diff --git a/scripts/broadcast-pc-duo.nse b/scripts/broadcast-pc-duo.nse
new file mode 100644
index 0000000..f8e9016
--- /dev/null
+++ b/scripts/broadcast-pc-duo.nse
@@ -0,0 +1,132 @@
+local coroutine = require "coroutine"
+local nmap = require "nmap"
+local os = require "os"
+local stdnse = require "stdnse"
+local table = require "table"
+
+description = [[
+Discovers PC-DUO remote control hosts and gateways running on a LAN by sending a special broadcast UDP probe.
+]]
+
+---
+-- @usage
+-- nmap --script broadcast-pc-duo
+--
+-- @output
+-- Pre-scan script results:
+-- | broadcast-pc-duo:
+-- | PC-Duo Gateway Server
+-- | 10.0.200.113 - WIN2K3SRV-1
+-- | PC-Duo Hosts
+-- |_ 10.0.200.113 - WIN2K3SRV-1
+--
+-- @args broadcast-pc-duo.timeout specifies the amount of seconds to sniff
+-- the network interface. (default varies according to timing. -T3 = 5s)
+
+author = "Patrik Karlsson"
+license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
+categories = { "broadcast", "safe" }
+
+local TIMEOUT = stdnse.parse_timespec(stdnse.get_script_args("broadcast-pc-duo.timeout"))
+
+prerule = function() return ( nmap.address_family() == "inet") end
+
+-- Sends a UDP probe to the server and processes the response
+-- @param probe table containing a pc-duo probe
+-- @param responses table containing the responses
+local function udpProbe(probe, responses)
+
+ local condvar = nmap.condvar(responses)
+ local socket = nmap.new_socket("udp")
+ socket:set_timeout(500)
+
+ for i=1,2 do
+ local status = socket:sendto(probe.host, probe.port, probe.data)
+ if ( not(status) ) then
+ return stdnse.format_output(false, "Failed to send broadcast request")
+ end
+ end
+
+ local timeout = TIMEOUT or ( 20 / ( nmap.timing_level() + 1 ) )
+ local stime = os.time()
+ local hosts = {}
+
+ repeat
+ local status, data = socket:receive()
+ if ( status ) then
+ local srvname = data:match(probe.match)
+ if ( srvname ) then
+ local status, _, _, rhost, _ = socket:get_info()
+ if ( not(status) ) then
+ socket:close()
+ return false, "Failed to get socket information"
+ end
+ -- avoid duplicates
+ hosts[rhost] = srvname
+ end
+ end
+ until( os.time() - stime > timeout )
+ socket:close()
+
+ local result = {}
+ for ip, name in pairs(hosts) do
+ table.insert(result, ("%s - %s"):format(ip,name))
+ end
+
+ if ( #result > 0 ) then
+ result.name = probe.topic
+ table.insert(responses, result)
+ end
+
+ condvar "signal"
+end
+
+action = function()
+
+ -- PC-Duo UDP probes
+ local probes = {
+ -- PC-Duo Host probe
+ {
+ host = { ip = "255.255.255.255" },
+ port = { number = 1505, protocol = "udp" },
+ data = stdnse.fromhex("00808008ff00"),
+ match= "^.........(%w*)\0",
+ topic= "PC-Duo Hosts"
+ },
+ -- PC-Duo Gateway Server probe
+ {
+ host = { ip = "255.255.255.255" },
+ port = { number = 2303, protocol = "udp" },
+ data = stdnse.fromhex("20908008ff00"),
+ match= "^.........(%w*)\0",
+ topic= "PC-Duo Gateway Server"
+ },
+ }
+
+ local threads, responses = {}, {}
+ local condvar = nmap.condvar(responses)
+
+ -- start a thread for each probe
+ for _, p in ipairs(probes) do
+ local th = stdnse.new_thread( udpProbe, p, responses )
+ threads[th] = true
+ end
+
+ -- wait until the probes are all done
+ repeat
+ for thread in pairs(threads) do
+ if coroutine.status(thread) == "dead" then
+ threads[thread] = nil
+ end
+ end
+ if ( next(threads) ) then
+ condvar "wait"
+ end
+ until next(threads) == nil
+
+ table.sort(responses, function(a,b) return a.name < b.name end)
+ -- did we get any responses
+ if ( #responses > 0 ) then
+ return stdnse.format_output(true, responses)
+ end
+end