From 81bb435ad9819ddda66cad8f89f865bdb74e14ea Mon Sep 17 00:00:00 2001 From: dmiller Date: Mon, 28 Mar 2016 16:46:32 +0000 Subject: [PATCH] Add TLS auth support to vnc.lua and vnc-brute --- nselib/vnc.lua | 104 +++++++++++++++++++++++++++++++++--------- scripts/vnc-brute.nse | 5 ++ 2 files changed, 87 insertions(+), 22 deletions(-) diff --git a/nselib/vnc.lua b/nselib/vnc.lua index f52ab054c..c9d933ac6 100644 --- a/nselib/vnc.lua +++ b/nselib/vnc.lua @@ -34,6 +34,19 @@ _ENV = stdnse.module("vnc", stdnse.seeall) local HAVE_SSL, openssl = pcall(require,'openssl') +local function process_error(socket) + local status, tmp = socket:receive_buf(match.numbytes(4), true) + if( not(status) ) then + return false, "VNC:handshake failed to retrieve error message" + end + local len = select(2, bin.unpack(">I", tmp)) + local status, err = socket:receive_buf(match.numbytes(len), true) + if( not(status) ) then + return false, "VNC:handshake failed to retrieve error message" + end + return false, err +end + VNC = { versions = { @@ -154,19 +167,6 @@ VNC = { return false, "ERROR: VNC:handshake failed" end - local function process_error() - local status, tmp = self.socket:receive_buf(match.numbytes(4), true) - if( not(status) ) then - return false, "VNC:handshake failed to retrieve error message" - end - local len = select(2, bin.unpack(">I", tmp)) - local status, err = self.socket:receive_buf(match.numbytes(len), true) - if( not(status) ) then - return false, "VNC:handshake failed to retrieve error message" - end - return false, err - end - if ( cli_version == "RFB 003.003\n" ) then local status, tmp = self.socket:receive_buf(match.numbytes(4), true) if( not(status) ) then @@ -179,7 +179,7 @@ VNC = { -- do we have an invalid security type, if so we need to handle an -- error condition if ( vncsec.types[1] == 0 ) then - return process_error() + return process_error(self.socket) end else local status, tmp = self.socket:receive_buf(match.numbytes(1), true) @@ -190,7 +190,7 @@ VNC = { vncsec.count = select(2, bin.unpack("C", tmp)) if ( vncsec.count == 0 ) then - return process_error() + return process_error(self.socket) end status, tmp = self.socket:receive_buf(match.numbytes(vncsec.count), true) @@ -223,22 +223,39 @@ VNC = { return newpass end, - --- Attempts to login to the VNC service - -- Currently the only supported auth sectype is VNC Authentication + --- Attempts to login to the VNC service using any supported method + -- + -- @param username string, could be anything when VNCAuth is used + -- @param password string containing the password to use for authentication + -- @param authtype The VNC auth type from the VNC.sectypes table (default: best available method) + -- @return status true on success, false on failure + -- @return err string containing error message when status is false + login = function( self, username, password, authtype ) + if not authtype then + if 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) + 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, + + --- Attempts to login to the VNC service using VNC Authentication -- -- @param username string, could be anything when VNCAuth is used -- @param password string containing the password to use for authentication -- @return status true on success, false on failure -- @return err string containing error message when status is false - login = function( self, username, password ) + login_vncauth = function( self, username, password ) if ( not(password) ) then return false, "No password was supplied" end - if ( not( self:supportsSecType( VNC.sectypes.VNCAUTH ) ) ) then - return false, "The server does not support the \"VNC Authentication\" security type." - end - -- Announce that we support VNC Authentication local status = self.socket:send( bin.pack("C", VNC.sectypes.VNCAUTH) ) if ( not(status) ) then @@ -269,6 +286,49 @@ VNC = { return true, "" end, + login_tls = function( self, username, password ) + if ( not(password) ) then + return false, "No password was supplied" + end + + local status = self.socket:send( bin.pack("C", VNC.sectypes.TLS) ) + if not status then + return false, "Failed to select TLS authentication type" + end + + local status, err = self.socket:reconnect_ssl() + if not status then + return false, "Failed to reconnect SSL" + end + + local status, tmp = self.socket:receive_buf(match.numbytes(1), true) + if ( not(status) ) then + stdnse.debug1("ERROR: VNC:handshake failed to receive security data") + return false, "ERROR: VNC:handshake failed to receive security data" + end + + local vncsec = { + count = 1, + types = {} + } + vncsec.count = select(2, bin.unpack("C", tmp)) + if ( vncsec.count == 0 ) then + return process_error(self.socket) + end + status, tmp = self.socket:receive_buf(match.numbytes(vncsec.count), true) + + if ( not(status) ) then + stdnse.debug1("ERROR: VNC:handshake failed to receive security data") + return false, "ERROR: VNC:handshake failed to receive security data" + end + for i=1, vncsec.count do + table.insert( vncsec.types, select(2, bin.unpack("C", tmp, i) ) ) + end + self.vncsec = vncsec + + return self:login(username, password) + end, + --- Returns all supported security types as a table -- -- @return table containing a entry for each security type diff --git a/scripts/vnc-brute.nse b/scripts/vnc-brute.nse index 89c1ef560..d3bb06040 100644 --- a/scripts/vnc-brute.nse +++ b/scripts/vnc-brute.nse @@ -122,6 +122,11 @@ Driver = end status, data = vnc:login( nil, "is_sec_mec_supported?" ) + -- Check secondary auth type after potential TLS handshake that happened during login + if ( vnc:supportsSecType(vnc.sectypes.NONE) ) then + return false, "No authentication required" + end + if ( data:match("The server does not support.*security type") ) then return stdnse.format_output( false, " \n " .. data ) end