summaryrefslogtreecommitdiffstats
path: root/scripts/rpcinfo.nse
blob: 87edfc7bc8e9576359c5485c95dcf20bb8d89fd2 (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
local nmap = require "nmap"
local rpc = require "rpc"
local shortport = require "shortport"
local stdnse = require "stdnse"
local table = require "table"

description = [[
Connects to portmapper and fetches a list of all registered programs.  It then
prints out a table including (for each program) the RPC program number,
supported version numbers, port number and protocol, and program name.
]]

---
-- @output
-- PORT    STATE SERVICE
-- 111/tcp open  rpcbind
-- | rpcinfo:
-- |   program version   port/proto  service
-- |   100000  2,3,4        111/tcp  rpcbind
-- |   100000  2,3,4        111/udp  rpcbind
-- |   100001  2,3,4      32774/udp  rstatd
-- |   100002  2,3        32776/udp  rusersd
-- |   100002  2,3        32780/tcp  rusersd
-- |   100011  1          32777/udp  rquotad
-- |   100021  1,2,3,4     4045/tcp  nlockmgr
-- |   100021  1,2,3,4     4045/udp  nlockmgr
-- |   100024  1          32771/tcp  status
-- |   100024  1          32773/udp  status
-- |   100068  2,3,4,5    32775/udp  cmsd
-- |   100083  1          32779/tcp  ttdbserverd
-- |   100133  1          32771/tcp  nsm_addrand
-- |   100133  1          32773/udp  nsm_addrand
-- |   100229  1,2        32775/tcp  metad
-- |   100230  1          32778/tcp  metamhd
-- |   100242  1          32777/tcp  rpc.metamedd
-- |   100249  1          32780/udp  snmpXdmid
-- |   100249  1          32781/tcp  snmpXdmid
-- |   100422  1          32776/tcp  mdcommd
-- |   1073741824 1          32772/tcp  fmproduct
-- |   300598  1          32782/tcp  dmispd
-- |   300598  1          32783/udp  dmispd
-- |   805306368 1          32782/tcp  dmispd
-- |_  805306368 1          32783/udp  dmispd
--@xmloutput
--<table>
--  <table key="100003">
--    <table key="tcp">
--      <elem key="port">2049</elem>
--      <table key="version">
--        <elem>2</elem> <elem>3</elem> <elem>4</elem>
--      </table>
--    </table>
--    <table key="udp">
--      <elem key="port">2049</elem>
--      <table key="version">
--        <elem>2</elem> <elem>3</elem> <elem>4</elem>
--      </table>
--    </table>
--  </table>
--  <table key="100000">
--    <table key="tcp">
--      <elem key="port">111</elem>
--      <table key="version">
--        <elem>2</elem> <elem>3</elem> <elem>4</elem>
--      </table>
--    </table>
--    <table key="udp">
--      <elem key="port">111</elem>
--      <table key="version">
--        <elem>2</elem> <elem>3</elem> <elem>4</elem>
--      </table>
--    </table>
--  </table>
--</table>
--
-- @see rpc-grind.nse

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


-- don't match "rpcbind" because that's what version scan labels any RPC service
portrule = function(host, port)
  return nmap.version_intensity() >= 7 and
  shortport.portnumber(111, {"tcp", "udp"})(host, port)
end

action = function(host, port)

  local result = {}
  local status, rpcinfo = rpc.Helper.RpcInfo( host, port )
  local xmlout = {}

  if ( not(status) ) then
    return stdnse.format_output(false, rpcinfo)
  end

  for progid, v in pairs(rpcinfo) do
    xmlout[tostring(progid)] = v
    for proto, v2 in pairs(v) do
      if proto == "tcp" or proto == "udp" then
        local nmapport = nmap.get_port_state(host, {number=v2.port, protocol=proto})
        if nmapport and (nmapport.state == "open" or nmapport.state == "open|filtered") then
          nmapport.version = nmapport.version or {}
          -- If we don't already know it, or we only know that it's "rpcbind"
          if nmapport.service == nil or nmapport.version.service_dtype == "table" or port.service == "rpcbind" then
            nmapport.version.name = rpc.Util.ProgNumberToName(progid)
            nmapport.version.extrainfo = "RPC #" .. progid
            if #v2.version > 1 then
              nmapport.version.version = ("%d-%d"):format(v2.version[1], v2.version[#v2.version])
            else
              nmapport.version.version = tostring(v2.version[1])
            end
            nmap.set_port_version(host, nmapport, "softmatched")
          end
        end
      end

      if v2.port then
        -- TODO: report other transports that don't have a port; e.g. "local"
        table.insert( result, ("%-7d %-10s %5d/%-4s  %s"):format(progid, table.concat(v2.version, ","), v2.port, proto, rpc.Util.ProgNumberToName(progid) or "") )
      end
    end
  end

  table.sort(result)

  if (#result > 0) then
    table.insert(result, 1, "program version    port/proto  service")
  end

  return xmlout, stdnse.format_output( true, result )
end