File: wdb-version.nse

package info (click to toggle)
nmap 6.47-3%2Bdeb8u2
  • links: PTS, VCS
  • area: main
  • in suites: jessie
  • size: 44,788 kB
  • ctags: 25,108
  • sloc: ansic: 89,741; cpp: 62,412; sh: 19,492; python: 17,323; xml: 11,413; perl: 2,529; makefile: 2,503; yacc: 608; lex: 469; asm: 372; java: 45
file content (235 lines) | stat: -rw-r--r-- 8,308 bytes parent folder | download | duplicates (2)
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
223
224
225
226
227
228
229
230
231
232
233
234
235
local bin = require "bin"
local bit = require "bit"
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 http://nmap.org/book/man-legal.html"
-- may also be "safe", but need testing to determine
categories = {"default", "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
-- http://www.metasploit.com/redmine/projects/framework/repository/entry/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 = 0
  local _
  p, _ = bin.unpack(">I", data)
  while p < data:len() do
    local c
    p, c = bin.unpack(">S", data, p)
    sum = sum + c
  end
  sum = bit.band(sum, 0xffff) + bit.rshift(sum, 16)
  return bit.bnot( sum )
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 = bin.pack( ">I2", data:len() + packet:len() + 8, seqno() )
  local sum = checksum(packet..bin.pack(">I", 0x00000000)..wdbwrapper..data)
  return packet .. bin.pack(">S2", 0xffff, sum) .. wdbwrapper .. data
end

local function stripnull(str)
  local e = -1
  while str:byte(e) == 0 do
    e = e - 1
  end
  return str:sub(1,e)
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"] = bit.band(wdberr, 0xc0000000)
  if (info["error"] ~= 0x00000000 ) then
    stdnse.print_debug(1,"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, data, pos, header
  local info = {}
  status, err = comm:Connect(host, port)
  if (not(status)) then
    return stdnse.format_output(false, err)
  end
  comm.socket:set_timeout(3000)
  local packet = request(comm, WDB_Procedure["WDB_TARGET_CONNECT"], bin.pack(">I3", 0x00000002, 0x00000000, 0x00000000))
  if (not(comm:SendPacket(packet))) then
    return stdnse.format_output(false, "Failed to send request")
  end

  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")

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

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

  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"], bin.pack(">I3", 0x00000002, 0x00000000, 0x00000000))
  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