summaryrefslogtreecommitdiffstats
path: root/scripts/wdb-version.nse
blob: 32380640099ba52bf022d1b80bda7d13fdd9d865 (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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
local nmap = require "nmap"
local rpc = require "rpc"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"

description = [[
Detects vulnerabilities and gathers information (such as version
numbers and hardware support) from VxWorks Wind DeBug agents.

Wind DeBug is a SunRPC-type service that is enabled by default on many devices
that use the popular VxWorks real-time embedded operating system. H.D. Moore
of Metasploit has identified several security vulnerabilities and design flaws
with the service, including weakly-hashed passwords and raw memory dumping.

See also:
http://www.kb.cert.org/vuls/id/362332
]]

---
-- @usage
-- nmap -sU -p 17185 --script wdb-version <target>
-- @output
-- 17185/udp open  wdb  Wind DeBug Agent 2.0
-- | wdb-version:
-- |   VULNERABLE: Wind River Systems VxWorks debug service enabled. See http://www.kb.cert.org/vuls/id/362332
-- |   Agent version: 2.0
-- |   VxWorks version: VxWorks5.4.2
-- |   Board Support Package: PCD ARM940T REV 1
-- |   Boot line: host:vxWorks.z
--@xmloutput
-- <elem>VULNERABLE: Wind River Systems VxWorks debug service enabled. See http://www.kb.cert.org/vuls/id/362332</elem>
-- <elem key="Agent version">2.0</elem>
-- <elem key="VxWorks version">5.4</elem>
-- <elem key="Board Support Package">Alcatel CMM MPC8245/100</elem>
-- <elem key="Boot line">lanswitchCmm:</elem>

author = "Daniel Miller"
license = "Same as Nmap--See https://nmap.org/book/man-legal.html"
categories = {"default", "safe", "version", "discovery", "vuln"}


-- WDB protocol information
-- http://www.vxdev.com/docs/vx55man/tornado-api/wdbpcl/wdb.html
-- http://www.verysource.com/code/2817990_1/wdb.h.html
-- Metasploit scanner module
-- https://github.com/rapid7/metasploit-framework/blob/master/lib/msf/core/exploit/wdbrpc.rb

portrule = shortport.version_port_or_service(17185, "wdbrpc", {"udp"} )

rpc.RPC_version["wdb"] = { min=1, max=1 }

local WDB_Procedure = {
  ["WDB_TARGET_PING"] = 0,
  ["WDB_TARGET_CONNECT"] = 1,
  ["WDB_TARGET_DISCONNECT"] = 2,
  ["WDB_TARGET_MODE_SET"] = 3,
  ["WDB_TARGET_MODE_GET"] = 4,
}

local function checksum(data)
  local sum = 0
  local p = 5 -- skip first 4 bytes
  while p < #data do
    local c
    c, p = (">I2"):unpack(data, p)
    sum = sum + c
  end
  sum = (sum & 0xffff) + (sum >> 16)
  return ~sum & 0xffff
end

local seqnum = 0
local function seqno()
  seqnum = seqnum + 1
  return seqnum
end

local function request(comm, procedure, data)
  local packet = comm:EncodePacket( nil, procedure, {type = rpc.Portmap.AuthType.NULL}, nil )
  local wdbwrapper = (">I4I4"):pack(#data + #packet + 8, seqno())
  local sum = checksum(packet .. "\0\0\0\0" .. wdbwrapper .. data)
  return packet .. (">I2I2"):pack(0xffff, sum) .. wdbwrapper .. data
end

local function stripnull(str)
  return (str:gsub("\0*$",""))
end

local function decode_reply(data, pos)
  local wdberr, len
  local done = data:len()
  local info = {}
  local _
  pos, _ = rpc.Util.unmarshall_uint32(data, pos)
  pos, _ = rpc.Util.unmarshall_uint32(data, pos)
  pos, wdberr = rpc.Util.unmarshall_uint32(data, pos)
  info["error"] = wdberr & 0xc0000000
  if info["error"] ~= 0x00000000 then
    stdnse.debug1("Error from decode_reply: %x", info["error"])
    return nil, info
  end
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  if len ~= 0 then
    pos, info["agent_ver"] = rpc.Util.unmarshall_vopaque(len, data, pos)
  end
  pos, info["agent_mtu"] = rpc.Util.unmarshall_uint32(data, pos)
  pos, info["agent_mod"] = rpc.Util.unmarshall_uint32(data, pos)
  pos, info["rt_type"] = rpc.Util.unmarshall_uint32(data, pos)
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  if pos == done then return pos, info end
  if len ~= 0 then
    pos, info["rt_vers"] = rpc.Util.unmarshall_vopaque(len, data, pos)
  end
  pos, info["rt_cpu_type"] = rpc.Util.unmarshall_uint32(data, pos)
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  info["rt_has_fpp"] = ( len ~= 0 )
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  info["rt_has_wp"] = ( len ~= 0 )
  pos, info["rt_page_size"] = rpc.Util.unmarshall_uint32(data, pos)
  pos, info["rt_endian"] = rpc.Util.unmarshall_uint32(data, pos)
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  if len ~= 0 then
    pos, info["rt_bsp_name"] = rpc.Util.unmarshall_vopaque(len, data, pos)
  end
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  if len ~= 0 then
    pos, info["rt_bootline"] = rpc.Util.unmarshall_vopaque(len, data, pos)
  end
  if pos == done then return pos, info end
  pos, info["rt_membase"] = rpc.Util.unmarshall_uint32(data, pos)
  if pos == done then return pos, info end
  pos, info["rt_memsize"] = rpc.Util.unmarshall_uint32(data, pos)
  if pos == done then return pos, info end
  pos, info["rt_region_count"] = rpc.Util.unmarshall_uint32(data, pos)
  if pos == done then return pos, info end
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  if len ~= 0 then
    info["rt_regions"] = {}
    for i = 1, len do
      pos, info["rt_regions"][i] = rpc.Util.unmarshall_uint32(data, pos)
    end
  end
  if pos == done then return pos, info end
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  if len == nil then return pos, info end
  if len ~= 0 then
    pos, info["rt_hostpool_base"] = rpc.Util.unmarshall_vopaque(len, data, pos)
  end
  if pos == done then return pos, info end
  pos, len = rpc.Util.unmarshall_uint32(data, pos)
  if len ~= 0 then
    pos, info["rt_hostpool_size"] = rpc.Util.unmarshall_vopaque(len, data, pos)
  end
  return pos, info
end

action = function(host, port)
  local comm = rpc.Comm:new("wdb", 1)
  local status, err = comm:Connect(host, port)
  if not status then
    return stdnse.format_output(false, err)
  end
  local packet = request(comm, WDB_Procedure["WDB_TARGET_CONNECT"], (">I4I4I4"):pack(2, 0, 0))
  if not comm:SendPacket(packet) then
    return stdnse.format_output(false, "Failed to send request")
  end

  local status, data = comm:ReceivePacket()
  if not status then
    --return stdnse.format_output(false, "Failed to read data")
    return nil
  end
  nmap.set_port_state(host, port, "open")

  local pos, header = comm:DecodeHeader(data, 1)
  if not header then
    return stdnse.format_output(false, "Failed to decode header")
  end

  if pos == #data then
    return stdnse.format_output(false, "No WDB data in reply")
  end

  local pos, info = decode_reply(data, pos)
  if not pos then
    return stdnse.format_output(false, "WDB error: "..info.error)
  end
  port.version.name = "wdb"
  port.version.name_confidence = 10
  port.version.product = "Wind DeBug Agent"
  port.version.version = stripnull(info["agent_ver"])
  if port.version.ostype ~= nil then
    port.version.ostype = "VxWorks " .. stripnull(info["rt_vers"])
  end
  nmap.set_port_version(host, port)
  -- Clean up (some agents will continue to send data until we disconnect)
  packet = request(comm, WDB_Procedure["WDB_TARGET_DISCONNECT"], (">I4I4I4"):pack(2, 0, 0))
  if not comm:SendPacket(packet) then
    return stdnse.format_output(false, "Failed to send request")
  end

  local o = stdnse.output_table()
  table.insert(o, "VULNERABLE: Wind River Systems VxWorks debug service enabled. See http://www.kb.cert.org/vuls/id/362332")
  if info.agent_ver then
    o["Agent version"] = stripnull(info.agent_ver)
  end
  --table.insert(o, "Agent MTU: " .. info.agent_mtu)
  if info.rt_vers then
    o["VxWorks version"] = stripnull(info.rt_vers)
  end
  -- rt_cpu_type is an enum type, but I don't have access to
  -- cputypes.h, where it is defined
  --table.insert(o, "CPU Type: " .. info.rt_cpu_type)
  if info.rt_bsp_name then
    o["Board Support Package"] = stripnull(info.rt_bsp_name)
  end
  if info.rt_bootline then
    o["Boot line"] = stripnull(info.rt_bootline)
  end
  return o
end