mirror of
https://github.com/nmap/nmap.git
synced 2025-12-15 12:19:02 +00:00
VNC revamp and extension
This commit is contained in:
@@ -1,5 +1,9 @@
|
|||||||
# Nmap Changelog ($Id$); -*-text-*-
|
# Nmap Changelog ($Id$); -*-text-*-
|
||||||
|
|
||||||
|
o [NSE] More VNC updates: Support for VeNCrypt auth type, output of
|
||||||
|
authentication sub-types in vnc-info, and all zero-authentication types are
|
||||||
|
recognized and reported. [Daniel Miller]
|
||||||
|
|
||||||
o [NSE] Update to enable smb-os-discovery to augment version detection
|
o [NSE] Update to enable smb-os-discovery to augment version detection
|
||||||
for certain SMB related services using data that the script discovers.
|
for certain SMB related services using data that the script discovers.
|
||||||
[Tom Sellers]
|
[Tom Sellers]
|
||||||
|
|||||||
@@ -568,51 +568,36 @@ StartTLS = {
|
|||||||
local sock = v.socket
|
local sock = v.socket
|
||||||
if v:supportsSecType(vnc.VNC.sectypes.VENCRYPT) then
|
if v:supportsSecType(vnc.VNC.sectypes.VENCRYPT) then
|
||||||
|
|
||||||
status = sock:send( bin.pack("C", vnc.VNC.sectypes.VENCRYPT) )
|
status, data = v:handshake_vencrypt()
|
||||||
if not status then
|
if not status then
|
||||||
return false, "Failed to select VeNCrypt authentication type"
|
return false, string.format("Failed VeNCrypt handshake: %s", data)
|
||||||
end
|
end
|
||||||
|
local auth_order = {
|
||||||
local status, buf = sock:receive_buf(match.numbytes(2), true)
|
-- X509 types are not anonymous, have real certs
|
||||||
local pos, maj, min = bin.unpack("CC", buf)
|
vnc.VENCRYPT_SUBTYPES.X509VNC,
|
||||||
if maj ~= 0 or min ~= 2 then
|
vnc.VENCRYPT_SUBTYPES.X509SASL,
|
||||||
return false, string.format("Unknown VeNCrypt version: %d.%d", maj, min)
|
vnc.VENCRYPT_SUBTYPES.X509NONE,
|
||||||
end
|
vnc.VENCRYPT_SUBTYPES.X509PLAIN,
|
||||||
sock:send(bin.pack("CC", maj, min))
|
-- TLS types use anonymous DH handshakes
|
||||||
status, buf = sock:receive_buf(match.numbytes(1), true)
|
vnc.VENCRYPT_SUBTYPES.TLSVNC,
|
||||||
pos, status = bin.unpack("C", buf)
|
vnc.VENCRYPT_SUBTYPES.TLSSASL,
|
||||||
if status ~= 0 then
|
vnc.VENCRYPT_SUBTYPES.TLSNONE,
|
||||||
return false, string.format("Server refused VeNCrypt version %d.%d", maj, min)
|
vnc.VENCRYPT_SUBTYPES.TLSPLAIN,
|
||||||
end
|
-- PLAIN type doesn't use TLS
|
||||||
|
}
|
||||||
status, buf = sock:receive_buf(match.numbytes(1), true)
|
|
||||||
local pos, nauth = bin.unpack("C", buf)
|
|
||||||
if nauth == 0 then
|
|
||||||
return false, "No VeNCrypt auth subtypes received"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- vencrypt auth types are u32
|
|
||||||
status, buf = sock:receive_buf(match.numbytes(nauth * 4), true)
|
|
||||||
local best
|
local best
|
||||||
pos = 1
|
for i=1, #auth_order do
|
||||||
for i=1, nauth do
|
if stdnse.contains(v.vencrypt.types, auth_order[i]) then
|
||||||
local auth
|
best = auth_order[i]
|
||||||
pos, auth = bin.unpack(">I", buf, pos)
|
|
||||||
if auth >= 260 and auth <= 263 then
|
|
||||||
-- X509 auth subtype
|
|
||||||
best = auth
|
|
||||||
break
|
break
|
||||||
elseif auth >= 257 then
|
|
||||||
-- other TLS auth subtype (Plain is 256)
|
|
||||||
-- These are anon types, so no cert available
|
|
||||||
best = auth
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if not best then
|
if not best then
|
||||||
return false, "No TLS VeNCrypt auth subtype received"
|
return false, "No TLS VeNCrypt auth subtype received"
|
||||||
end
|
end
|
||||||
sock:send(bin.pack(">I", best))
|
sock:send(bin.pack(">I", best))
|
||||||
status, buf = sock:receive_buf(match.numbytes(1), true)
|
local status, buf = sock:receive_buf(match.numbytes(1), true)
|
||||||
if not status or string.byte(buf, 1) ~= 1 then
|
if not status or string.byte(buf, 1) ~= 1 then
|
||||||
return false, "VeNCrypt auth subtype refused"
|
return false, "VeNCrypt auth subtype refused"
|
||||||
end
|
end
|
||||||
|
|||||||
302
nselib/vnc.lua
302
nselib/vnc.lua
@@ -34,6 +34,29 @@ _ENV = stdnse.module("vnc", stdnse.seeall)
|
|||||||
|
|
||||||
local HAVE_SSL, openssl = pcall(require,'openssl')
|
local HAVE_SSL, openssl = pcall(require,'openssl')
|
||||||
|
|
||||||
|
VENCRYPT_SUBTYPES = {
|
||||||
|
PLAIN = 256,
|
||||||
|
TLSNONE = 257,
|
||||||
|
TLSVNC = 258,
|
||||||
|
TLSPLAIN = 259,
|
||||||
|
X509NONE = 260,
|
||||||
|
X509VNC = 261,
|
||||||
|
X509PLAIN = 262,
|
||||||
|
X509SASL = 263,
|
||||||
|
TLSSASL = 264,
|
||||||
|
}
|
||||||
|
VENCRYPT_SUBTYPES_STR = {
|
||||||
|
[256] = "Plain",
|
||||||
|
[257] = "None, Anonymous TLS",
|
||||||
|
[258] = "VNC auth, Anonymous TLS",
|
||||||
|
[259] = "Plain, Anonymous TLS",
|
||||||
|
[260] = "None, Server-authenticated TLS",
|
||||||
|
[261] = "VNC auth, Server-authenticated TLS",
|
||||||
|
[262] = "Plain, Server-authenticated TLS",
|
||||||
|
[263] = "SASL, Server-authenticated TLS",
|
||||||
|
[264] = "SASL, Anonymous TLS",
|
||||||
|
}
|
||||||
|
|
||||||
local function process_error(socket)
|
local function process_error(socket)
|
||||||
local status, tmp = socket:receive_buf(match.numbytes(4), true)
|
local status, tmp = socket:receive_buf(match.numbytes(4), true)
|
||||||
if( not(status) ) then
|
if( not(status) ) then
|
||||||
@@ -47,15 +70,39 @@ local function process_error(socket)
|
|||||||
return false, err
|
return false, err
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function first_of (list, lookup)
|
||||||
|
for i=1, #list do
|
||||||
|
if stdnse.contains(lookup, list[i]) then
|
||||||
|
return list[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- generalized output formatter for security types and subtypes
|
||||||
|
local function get_types_as_table (types, lookup)
|
||||||
|
local tmp = {}
|
||||||
|
local typemt = {
|
||||||
|
__tostring = function(me)
|
||||||
|
return ("%s (%s)"):format(me.name, me.type)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
for i=1, types.count do
|
||||||
|
local t = {name = lookup[types.types[i]] or "Unknown security type", type=types.types[i]}
|
||||||
|
setmetatable(t, typemt)
|
||||||
|
table.insert( tmp, t )
|
||||||
|
end
|
||||||
|
return tmp
|
||||||
|
end
|
||||||
|
|
||||||
VNC = {
|
VNC = {
|
||||||
|
|
||||||
versions = {
|
versions = {
|
||||||
["RFB 003.003\n"] = "3.3",
|
["RFB 003.003"] = "3.3",
|
||||||
["RFB 003.007\n"] = "3.7",
|
["RFB 003.007"] = "3.7",
|
||||||
["RFB 003.008\n"] = "3.8",
|
["RFB 003.008"] = "3.8",
|
||||||
|
|
||||||
-- Mac Screen Sharing, could probably be used to fingerprint OS
|
-- Mac Screen Sharing, could probably be used to fingerprint OS
|
||||||
["RFB 003.889\n"] = "3.889",
|
["RFB 003.889"] = "3.889",
|
||||||
},
|
},
|
||||||
|
|
||||||
sectypes = {
|
sectypes = {
|
||||||
@@ -127,11 +174,12 @@ VNC = {
|
|||||||
-- @return status, true on success, false on failure
|
-- @return status, true on success, false on failure
|
||||||
-- @return error string containing error message if status is false
|
-- @return error string containing error message if status is false
|
||||||
handshake = function(self)
|
handshake = function(self)
|
||||||
local status, data = self.socket:receive_buf(match.numbytes(12), true)
|
local status, data = self.socket:receive_buf("[\r\n]+", true)
|
||||||
if not string.match(data, "^RFB %d%d%d%.%d%d%d[\r\n]") then
|
if not status or not string.match(data, "^RFB %d%d%d%.%d%d%d[\r\n]") then
|
||||||
stdnse.debug1("ERROR: Not a VNC port. Banner: %s", data)
|
stdnse.debug1("ERROR: Not a VNC port. Banner: %s", data)
|
||||||
return false, "Not a VNC port."
|
return false, "Not a VNC port."
|
||||||
end
|
end
|
||||||
|
data = data:sub(1,11)
|
||||||
local vncsec = {
|
local vncsec = {
|
||||||
count = 1,
|
count = 1,
|
||||||
types = {}
|
types = {}
|
||||||
@@ -144,14 +192,14 @@ VNC = {
|
|||||||
self.protover = VNC.versions[data]
|
self.protover = VNC.versions[data]
|
||||||
local cli_version = data
|
local cli_version = data
|
||||||
if ( not(self.protover) ) then
|
if ( not(self.protover) ) then
|
||||||
stdnse.debug1("ERROR: VNC:handshake unsupported version (%s)", data:sub(1,11))
|
stdnse.debug1("ERROR: VNC:handshake unsupported version (%s)", data)
|
||||||
self.protover = string.match(data, "^RFB (%d+%.%d+)")
|
self.protover = string.match(data, "^RFB (%d+%.%d+)")
|
||||||
--return false, ("Unsupported version (%s)"):format(data:sub(1,11))
|
--return false, ("Unsupported version (%s)"):format(data:sub(1,11))
|
||||||
local versions = {
|
local versions = {
|
||||||
"RFB 003.003\n",
|
"RFB 003.003",
|
||||||
"RFB 003.007\n",
|
"RFB 003.007",
|
||||||
"RFB 003.008\n",
|
"RFB 003.008",
|
||||||
"RFB 003.889\n",
|
"RFB 003.889",
|
||||||
}
|
}
|
||||||
for i=1, #versions do
|
for i=1, #versions do
|
||||||
if versions[i] >= data then
|
if versions[i] >= data then
|
||||||
@@ -161,13 +209,14 @@ VNC = {
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
status = self.socket:send( cli_version or "RFB 003.889\n" )
|
self.client_version = VNC.versions[cli_version or "RFB 003.889"]
|
||||||
|
status = self.socket:send( (cli_version or "RFB 003.889") .. "\n" )
|
||||||
if ( not(status) ) then
|
if ( not(status) ) then
|
||||||
stdnse.debug1("ERROR: VNC:handshake failed to send client version")
|
stdnse.debug1("ERROR: VNC:handshake failed to send client version")
|
||||||
return false, "ERROR: VNC:handshake failed"
|
return false, "ERROR: VNC:handshake failed"
|
||||||
end
|
end
|
||||||
|
|
||||||
if ( cli_version == "RFB 003.003\n" ) then
|
if ( self.client_version == "3.3" ) then
|
||||||
local status, tmp = self.socket:receive_buf(match.numbytes(4), true)
|
local status, tmp = self.socket:receive_buf(match.numbytes(4), true)
|
||||||
if( not(status) ) then
|
if( not(status) ) then
|
||||||
return false, "VNC:handshake failed to receive security data"
|
return false, "VNC:handshake failed to receive security data"
|
||||||
@@ -231,18 +280,43 @@ VNC = {
|
|||||||
-- @return status true on success, false on failure
|
-- @return status true on success, false on failure
|
||||||
-- @return err string containing error message when status is false
|
-- @return err string containing error message when status is false
|
||||||
login = function( self, username, password, authtype )
|
login = function( self, username, password, authtype )
|
||||||
if not authtype then
|
if ( not(password) ) then
|
||||||
if self:supportsSecType( VNC.sectypes.VNCAUTH ) then
|
return false, "No password was supplied"
|
||||||
return self:login_vncauth(username, password)
|
|
||||||
elseif self:supportsSecType( VNC.sectypes.TLS ) then
|
|
||||||
return self:login_tls(username, password)
|
|
||||||
else
|
|
||||||
return false, "vnc.lua does not support that security type"
|
|
||||||
end
|
|
||||||
elseif ( not( self:supportsSecType( authtype ) ) ) then
|
|
||||||
return false, "The server does not support the \"VNC Authentication\" security type."
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if not authtype then
|
||||||
|
if self:supportsSecType( VNC.sectypes.NONE ) then
|
||||||
|
return self:login_none()
|
||||||
|
|
||||||
|
elseif self:supportsSecType( VNC.sectypes.VNCAUTH ) then
|
||||||
|
return self:login_vncauth(username, password)
|
||||||
|
|
||||||
|
elseif self:supportsSecType( VNC.sectypes.TLS ) then
|
||||||
|
return self:login_tls(username, password)
|
||||||
|
|
||||||
|
elseif self:supportsSecType( VNC.sectypes.VENCRYPT ) then
|
||||||
|
return self:login_vencrypt(username, password)
|
||||||
|
|
||||||
|
else
|
||||||
|
return false, "The server does not support any matching security type"
|
||||||
|
end
|
||||||
|
elseif ( not( self:supportsSecType( authtype ) ) ) then
|
||||||
|
return false, string.format(
|
||||||
|
'The server does not support the "%s" security type.', VNC.sectypes_str[authtype])
|
||||||
|
end
|
||||||
|
|
||||||
|
end,
|
||||||
|
|
||||||
|
login_none = function (self)
|
||||||
|
local status = self.socket:send( bin.pack("C", VNC.sectypes.NONE) )
|
||||||
|
if not status then
|
||||||
|
return false, "Failed to select None authentication type"
|
||||||
|
end
|
||||||
|
if self.client_version == "3.8" then
|
||||||
|
return self:check_auth_result()
|
||||||
|
end
|
||||||
|
-- nothing to do here!
|
||||||
|
return true
|
||||||
end,
|
end,
|
||||||
|
|
||||||
--- Attempts to login to the VNC service using VNC Authentication
|
--- Attempts to login to the VNC service using VNC Authentication
|
||||||
@@ -252,14 +326,9 @@ VNC = {
|
|||||||
-- @return status true on success, false on failure
|
-- @return status true on success, false on failure
|
||||||
-- @return err string containing error message when status is false
|
-- @return err string containing error message when status is false
|
||||||
login_vncauth = function( self, username, password )
|
login_vncauth = function( self, username, password )
|
||||||
if ( not(password) ) then
|
|
||||||
return false, "No password was supplied"
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Announce that we support VNC Authentication
|
|
||||||
local status = self.socket:send( bin.pack("C", VNC.sectypes.VNCAUTH) )
|
local status = self.socket:send( bin.pack("C", VNC.sectypes.VNCAUTH) )
|
||||||
if ( not(status) ) then
|
if not status then
|
||||||
return false, "Failed to select authentication type"
|
return false, "Failed to send authentication type"
|
||||||
end
|
end
|
||||||
|
|
||||||
local status, chall = self.socket:receive_buf(match.numbytes(16), true)
|
local status, chall = self.socket:receive_buf(match.numbytes(16), true)
|
||||||
@@ -274,23 +343,22 @@ VNC = {
|
|||||||
if ( not(status) ) then
|
if ( not(status) ) then
|
||||||
return false, "Failed to send authentication response to server"
|
return false, "Failed to send authentication response to server"
|
||||||
end
|
end
|
||||||
|
return self:check_auth_result()
|
||||||
|
end,
|
||||||
|
|
||||||
|
check_auth_result = function(self)
|
||||||
local status, result = self.socket:receive_buf(match.numbytes(4), true)
|
local status, result = self.socket:receive_buf(match.numbytes(4), true)
|
||||||
if ( not(status) ) then
|
if ( not(status) ) then
|
||||||
return false, "Failed to retrieve authentication status from server"
|
return false, "Failed to retrieve authentication status from server"
|
||||||
end
|
end
|
||||||
|
|
||||||
if ( select(2, bin.unpack("I", result) ) ~= 0 ) then
|
if ( select(2, bin.unpack("I", result) ) ~= 0 ) then
|
||||||
return false, ("Authentication failed with password %s"):format(password)
|
return false, "Authentication failed"
|
||||||
end
|
end
|
||||||
return true, ""
|
return true
|
||||||
end,
|
end,
|
||||||
|
|
||||||
login_tls = function( self, username, password )
|
handshake_tls = function(self)
|
||||||
if ( not(password) ) then
|
|
||||||
return false, "No password was supplied"
|
|
||||||
end
|
|
||||||
|
|
||||||
local status = self.socket:send( bin.pack("C", VNC.sectypes.TLS) )
|
local status = self.socket:send( bin.pack("C", VNC.sectypes.TLS) )
|
||||||
if not status then
|
if not status then
|
||||||
return false, "Failed to select TLS authentication type"
|
return false, "Failed to select TLS authentication type"
|
||||||
@@ -325,26 +393,129 @@ VNC = {
|
|||||||
table.insert( vncsec.types, select(2, bin.unpack("C", tmp, i) ) )
|
table.insert( vncsec.types, select(2, bin.unpack("C", tmp, i) ) )
|
||||||
end
|
end
|
||||||
self.vncsec = vncsec
|
self.vncsec = vncsec
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
login_tls = function( self, username, password )
|
||||||
|
local status, err = self:handshake_tls()
|
||||||
|
if not status then
|
||||||
|
return status, err
|
||||||
|
end
|
||||||
return self:login(username, password)
|
return self:login(username, password)
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
handshake_vencrypt = function(self)
|
||||||
|
local status = self.socket:send( bin.pack("C", VNC.sectypes.VENCRYPT) )
|
||||||
|
if not status then
|
||||||
|
return false, "Failed to select VeNCrypt authentication type"
|
||||||
|
end
|
||||||
|
|
||||||
|
local status, buf = self.socket:receive_buf(match.numbytes(2), true)
|
||||||
|
local pos, maj, min = bin.unpack("CC", buf)
|
||||||
|
if maj ~= 0 or min ~= 2 then
|
||||||
|
return false, string.format("Unknown VeNCrypt version: %d.%d", maj, min)
|
||||||
|
end
|
||||||
|
self.socket:send(bin.pack("CC", maj, min))
|
||||||
|
status, buf = self.socket:receive_buf(match.numbytes(1), true)
|
||||||
|
pos, status = bin.unpack("C", buf)
|
||||||
|
if status ~= 0 then
|
||||||
|
return false, string.format("Server refused VeNCrypt version %d.%d", maj, min)
|
||||||
|
end
|
||||||
|
|
||||||
|
status, buf = self.socket:receive_buf(match.numbytes(1), true)
|
||||||
|
local pos, nauth = bin.unpack("C", buf)
|
||||||
|
if nauth == 0 then
|
||||||
|
return false, "No VeNCrypt auth subtypes received"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- vencrypt auth types are u32
|
||||||
|
status, buf = self.socket:receive_buf(match.numbytes(nauth * 4), true)
|
||||||
|
pos = 1
|
||||||
|
local vencrypt = {
|
||||||
|
count = nauth,
|
||||||
|
types = {}
|
||||||
|
}
|
||||||
|
for i=1, nauth do
|
||||||
|
local auth
|
||||||
|
pos, auth = bin.unpack(">I", buf, pos)
|
||||||
|
table.insert(vencrypt.types, auth)
|
||||||
|
end
|
||||||
|
self.vencrypt = vencrypt
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
|
||||||
|
login_vencrypt = function(self, username, password)
|
||||||
|
local status, err = self:handshake_vencrypt()
|
||||||
|
if not status then
|
||||||
|
return status, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local subauth = first_of({
|
||||||
|
VENCRYPT_SUBTYPES.TLSNONE,
|
||||||
|
VENCRYPT_SUBTYPES.X509NONE,
|
||||||
|
VENCRYPT_SUBTYPES.PLAIN,
|
||||||
|
VENCRYPT_SUBTYPES.TLSPLAIN,
|
||||||
|
VENCRYPT_SUBTYPES.X509PLAIN,
|
||||||
|
VENCRYPT_SUBTYPES.TLSVNC,
|
||||||
|
VENCRYPT_SUBTYPES.X509VNC,
|
||||||
|
-- These not supported yet
|
||||||
|
--VENCRYPT_SUBTYPES.TLSSASL,
|
||||||
|
--VENCRYPT_SUBTYPES.X509SASL,
|
||||||
|
}, self.vencrypt.types)
|
||||||
|
|
||||||
|
if not subauth then
|
||||||
|
return false, "The server does not support any supported security type"
|
||||||
|
end
|
||||||
|
|
||||||
|
self.socket:send(bin.pack(">I", subauth))
|
||||||
|
local status, buf = self.socket:receive_buf(match.numbytes(1), true)
|
||||||
|
if not status or string.byte(buf, 1) ~= 1 then
|
||||||
|
return false, "VeNCrypt auth subtype refused"
|
||||||
|
end
|
||||||
|
|
||||||
|
if subauth == VENCRYPT_SUBTYPES.PLAIN then
|
||||||
|
return self:login_plain(username, password)
|
||||||
|
end
|
||||||
|
|
||||||
|
status, err = self.socket:reconnect_ssl()
|
||||||
|
if not status then
|
||||||
|
return false, "Failed to reconnect SSL to VNC server"
|
||||||
|
end
|
||||||
|
|
||||||
|
if subauth == VENCRYPT_SUBTYPES.TLSNONE or subauth == VENCRYPT_SUBTYPES.X509NONE then
|
||||||
|
return self:check_auth_result()
|
||||||
|
elseif subauth == VENCRYPT_SUBTYPES.TLSVNC or subauth == VENCRYPT_SUBTYPES.X509VNC then
|
||||||
|
return self:login_vncauth(username, password)
|
||||||
|
elseif subauth == VENCRYPT_SUBTYPES.TLSPLAIN or subauth == VENCRYPT_SUBTYPES.X509PLAIN then
|
||||||
|
return self:login_plain(username, password)
|
||||||
|
elseif subauth == VENCRYPT_SUBTYPES.TLSSASL or subauth == VENCRYPT_SUBTYPES.X509SASL then
|
||||||
|
return self:login_sasl(username, password)
|
||||||
|
end
|
||||||
|
|
||||||
|
end,
|
||||||
|
|
||||||
|
login_plain = function(self, username, password)
|
||||||
|
local status = self.socket:send(bin.pack(">IIAA", #username, #password, username, password))
|
||||||
|
if not status then
|
||||||
|
return false, "Failed to send plain auth"
|
||||||
|
end
|
||||||
|
|
||||||
|
return self:check_auth_result()
|
||||||
|
end,
|
||||||
|
|
||||||
|
login_sasl = function(self, username, password)
|
||||||
|
-- TODO: support this!
|
||||||
|
return false, "Unsupported"
|
||||||
|
end,
|
||||||
|
|
||||||
--- Returns all supported security types as a table
|
--- Returns all supported security types as a table
|
||||||
--
|
--
|
||||||
-- @return table containing a entry for each security type
|
-- @return table containing a entry for each security type
|
||||||
getSecTypesAsTable = function( self )
|
getSecTypesAsTable = function( self )
|
||||||
local tmp = {}
|
return get_types_as_table(self.vncsec, VNC.sectypes_str)
|
||||||
local typemt = {
|
end,
|
||||||
__tostring = function(me)
|
getVencryptTypesAsTable = function (self)
|
||||||
return ("%s (%s)"):format(me.name, me.type)
|
return get_types_as_table(self.vencrypt, VENCRYPT_SUBTYPES_STR)
|
||||||
end
|
|
||||||
}
|
|
||||||
for i=1, self.vncsec.count do
|
|
||||||
local t = {name=VNC.sectypes_str[self.vncsec.types[i]] or "Unknown security type", type=self.vncsec.types[i]}
|
|
||||||
setmetatable(t, typemt)
|
|
||||||
table.insert( tmp, t )
|
|
||||||
end
|
|
||||||
return true, tmp
|
|
||||||
end,
|
end,
|
||||||
|
|
||||||
--- Checks if the supplied security type is supported or not
|
--- Checks if the supplied security type is supported or not
|
||||||
@@ -367,6 +538,39 @@ VNC = {
|
|||||||
return self.protover
|
return self.protover
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
--- Send a ClientInit message.
|
||||||
|
--@param shared boolean determining whether the screen should be shared, or whether other logged-on users should be booted.
|
||||||
|
--@return status true if message was successful, false otherwise
|
||||||
|
--@return table containing contents of ServerInit message, or error message.
|
||||||
|
client_init = function (self, shared)
|
||||||
|
self.socket:send(shared and "\x01" or "\x00")
|
||||||
|
local status, buf = self.socket:receive_buf(match.numbytes(24), true)
|
||||||
|
if not status then
|
||||||
|
return false, "Did not receive ServerInit message"
|
||||||
|
end
|
||||||
|
local pos, width, height, bpp, depth, bigendian, truecolor, rmax, gmax, bmax, rshift, gshift, bshift, pad1, pad2, namelen = bin.unpack(">SSCCCCSSSCCCSCI", buf)
|
||||||
|
local status, buf = self.socket:receive_buf(match.numbytes(namelen), true)
|
||||||
|
if not status then
|
||||||
|
return false, "Did not receive ServerInit desktop name"
|
||||||
|
end
|
||||||
|
local pos, name = bin.unpack("A" .. namelen, buf)
|
||||||
|
return true, {
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
bpp = bpp,
|
||||||
|
depth = depth,
|
||||||
|
bigendian = bigendian,
|
||||||
|
truecolor = truecolor,
|
||||||
|
rmax = rmax,
|
||||||
|
gmax = gmax,
|
||||||
|
bmax = bmax,
|
||||||
|
rshift = rshift,
|
||||||
|
gshift = gshift,
|
||||||
|
bshift = bshift,
|
||||||
|
name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
end
|
||||||
}
|
}
|
||||||
|
|
||||||
return _ENV;
|
return _ENV;
|
||||||
|
|||||||
@@ -122,8 +122,9 @@ Driver =
|
|||||||
end
|
end
|
||||||
|
|
||||||
status, data = vnc:login( nil, "is_sec_mec_supported?" )
|
status, data = vnc:login( nil, "is_sec_mec_supported?" )
|
||||||
-- Check secondary auth type after potential TLS handshake that happened during login
|
-- Check whether auth succeeded. This is most likely because one of the
|
||||||
if ( vnc:supportsSecType(vnc.sectypes.NONE) ) then
|
-- NONE auth types was supported, since vnc.lua will just return true in that case.
|
||||||
|
if status then
|
||||||
return false, "No authentication required"
|
return false, "No authentication required"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -45,26 +45,67 @@ local function fail(err) return stdnse.format_output(false, err) end
|
|||||||
|
|
||||||
action = function(host, port)
|
action = function(host, port)
|
||||||
|
|
||||||
local vnc = vnc.VNC:new( host, port )
|
local v = vnc.VNC:new( host, port )
|
||||||
local status, data
|
local status, data
|
||||||
local result = stdnse.output_table()
|
local result = stdnse.output_table()
|
||||||
|
|
||||||
status, data = vnc:connect()
|
status, data = v:connect()
|
||||||
if ( not(status) ) then return fail(data) end
|
if ( not(status) ) then return fail(data) end
|
||||||
|
|
||||||
status, data = vnc:handshake()
|
status, data = v:handshake()
|
||||||
if ( not(status) ) then return fail(data) end
|
if ( not(status) ) then return fail(data) end
|
||||||
|
|
||||||
status, data = vnc:getSecTypesAsTable()
|
data = v:getSecTypesAsTable()
|
||||||
if ( not(status) ) then return fail(data) end
|
|
||||||
|
|
||||||
result["Protocol version"] = vnc:getProtocolVersion()
|
result["Protocol version"] = v:getProtocolVersion()
|
||||||
|
|
||||||
if ( data and #data ~= 0 ) then
|
if ( data and #data ~= 0 ) then
|
||||||
result["Security types"] = data
|
result["Security types"] = data
|
||||||
end
|
end
|
||||||
|
|
||||||
if ( vnc:supportsSecType(vnc.sectypes.NONE) ) then
|
local none_auth = false
|
||||||
|
if ( v:supportsSecType(v.sectypes.NONE) ) then
|
||||||
|
none_auth = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if v:supportsSecType(v.sectypes.VENCRYPT) then
|
||||||
|
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.TLS) then
|
||||||
|
if not v.socket:get_info() then
|
||||||
|
-- reconnect if necessary
|
||||||
|
v:connect()
|
||||||
|
v:handshake()
|
||||||
|
end
|
||||||
|
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"
|
result["WARNING"] = "Server does not require authentication"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user