summaryrefslogtreecommitdiffstats
path: root/scripts/vnc-info.nse
blob: 008ee6786c531e4a8e1bc3535fb94501ee3e49e1 (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
local shortport = require "shortport"
local stdnse = require "stdnse"
local string = require "string"
local vnc = require "vnc"

description = [[
Queries a VNC server for its protocol version and supported security types.
]]

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

---
-- @output
-- PORT    STATE SERVICE
-- 5900/tcp open  vnc
-- | vnc-info:
-- |   Protocol version: 3.889
-- |   Security types:
-- |     Mac OS X security type (30)
-- |_    Mac OS X security type (35)
--
-- @xmloutput
-- <elem key="Protocol version">3.8</elem>
-- <table key="Security types">
--   <table>
--     <elem key="name">Ultra</elem>
--     <elem key="type">17</elem>
--   </table>
--   <table>
--     <elem key="name">VNC Authentication</elem>
--     <elem key="type">2</elem>
--   </table>
-- </table>

-- Version 0.2

-- Created 07/07/2010 - v0.1 - created by Patrik Karlsson <patrik@cqure.net>
-- Revised 08/14/2010 - v0.2 - changed so that errors are reported even without debugging


portrule = shortport.port_or_service( {5900, 5901, 5902} , "vnc", "tcp", "open")

local function fail(err) return stdnse.format_output(false, err) end

action = function(host, port)

  local v = vnc.VNC:new( host, port )
  local status, data
  local result = stdnse.output_table()

  status, data = v:connect()
  if ( not(status) ) then return fail(data) end

  status, data = v:handshake()
  if ( not(status) ) then return fail(data) end

  data = v:getSecTypesAsTable()

  result["Protocol version"] = v:getProtocolVersion()

  if ( data and #data ~= 0 ) then
    result["Security types"] = data
  end

  local none_auth = false
  if ( v:supportsSecType(v.sectypes.NONE) ) then
    none_auth = true
  end

  if v:supportsSecType(v.sectypes.VENCRYPT) then
    v:sendSecType(v.sectypes.VENCRYPT)
    status, data = v:handshake_vencrypt()
    if not status then
      stdnse.debug1("Failed to handshake VeNCrypt: %s", data)
    else
      result["VeNCrypt auth subtypes"] = v:getVencryptTypesAsTable()
      if not none_auth then
        for i=1, v.vencrypt.count do
          if v.vencrypt.types[i] == vnc.VENCRYPT_SUBTYPES.TLSNONE or
            v.vencrypt.types[i] == vnc.VENCRYPT_SUBTYPES.TLSNONE then
            none_auth = true
            break
          end
        end
      end
    end
    -- Reset the connection for further tests
    v:disconnect()
  end

  if v:supportsSecType(v.sectypes.TIGHT) then
    if not v.socket:get_info() then
      -- reconnect if necessary
      v:connect()
      v:handshake()
    end
    v:sendSecType(v.sectypes.TIGHT)
    status, data = v:handshake_tight()
    if not status then
      stdnse.debug1("Failed to handshake Tight: %s", data)
    else
      if v.aten then
        result["Tight auth"] = "ATEN KVM VNC"
      else
        local mt = {
          __tostring = function(t)
            return string.format("%s %s (%d)", t.vendor, t.signature, t.code)
          end
        }
        local tunnels = {}
        for _, t in ipairs(v.tight.tunnels) do
          setmetatable(t, mt)
          tunnels[#tunnels+1] = t
        end
        if #tunnels > 0 then
          result["Tight auth tunnels"] = tunnels
        end
        if #v.tight.types == 0 then
          none_auth = true
          result["Tight auth subtypes"] = {"None"}
        else
          local subtypes = {}
          for _, t in ipairs(v.tight.types) do
            if t.code == 1 then
              none_auth = true
            end
            setmetatable(t, mt)
            subtypes[#subtypes+1] = t
          end
          result["Tight auth subtypes"] = subtypes
        end
      end
    end
    -- Reset the connection for further tests
    v:disconnect()
  end

  if v:supportsSecType(v.sectypes.TLS) then
    if not v.socket:get_info() then
      -- reconnect if necessary
      v:connect()
      v:handshake()
    end
    v:sendSecType(v.sectypes.TLS)
    status, data = v:handshake_tls()
    if not status then
      stdnse.debug1("Failed to handshake TLS: %s", data)
    else
      result["TLS auth subtypes"] = v:getSecTypesAsTable()
      if v:supportsSecType(v.sectypes.NONE) then
        none_auth = true
      end
    end
  end

  if none_auth then
    result["WARNING"] = "Server does not require authentication"
  end

  return result
end