summaryrefslogtreecommitdiffstats
path: root/scripts/broadcast-pc-duo.nse
blob: f8e90161390fb028264ee5e9c0b8a61e80912983 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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