class Rex::Proto::RFB::Client

Attributes

auth_types[R]
error[R]
majver[R]
minver[R]
view_only[R]

Public Class Methods

new(sock, opts = {}) click to toggle source
# File lib/rex/proto/rfb/client.rb, line 21
def initialize(sock, opts = {})
  @sock = sock
  @opts = opts

  @banner = nil
  @majver = MajorVersion
  @minver = -1
  @auth_types = []
end

Public Instance Methods

authenticate(password = nil) click to toggle source
# File lib/rex/proto/rfb/client.rb, line 84
def authenticate(password = nil)
  type = negotiate_authentication
  return false if not type

  # Authenticate.
  case type
  when AuthType::None
    # Nothing here.

  when AuthType::VNC
    return false if not negotiate_vnc_auth(password)

  end

  # Handle reading the security result message
  result = @sock.get_once(4)
  if not result
    @error = "Unable to read auth result"
    return false
  end

  result = result.unpack('N').first
  case result
  when 0
    return true

  when 1
    if @minver >= 8
      msg = read_error_message
      @error = "Authentication failed: #{msg}"
    else
      @error = "Authentication failed"
    end
  when 2
    @error = "Too many authentication attempts"
  else
    @error = "Unknown authentication result: #{result}"
  end

  false
end
connect(password = nil) click to toggle source
# File lib/rex/proto/rfb/client.rb, line 69
def connect(password = nil)
  return false if not handshake
  return false if not authenticate(password)
  return false if not send_client_init
  true
end
handshake() click to toggle source
# File lib/rex/proto/rfb/client.rb, line 39
def handshake
  @banner = @sock.get_once(12)
  if not @banner
    @error = "Unable to obtain banner from server"
    return false
  end

  # RFB Protocol Version 3.3 (1998-01)
  # RFB Protocol Version 3.7 (2003-08)
  # RFB Protocol Version 3.8 (2007-06)

  if @banner =~ /RFB ([0-9]{3})\.([0-9]{3})/
    maj = $1.to_i
    if maj != MajorVersion
      @error = "Invalid major version number: #{maj}"
      return false
    end
  else
    @error = "Invalid RFB banner: #{@banner}"
    return false
  end

  @minver = $2.to_i

  our_ver = "RFB %03d.%03d\n" % [MajorVersion, @minver]
  @sock.put(our_ver)

  true
end
negotiate_authentication() click to toggle source
# File lib/rex/proto/rfb/client.rb, line 126
def negotiate_authentication
  # Authentication type negotiation is protocol version specific.
  if @minver < 7
    buf = @sock.get_once(4)
    if not buf
      @error = "Unable to obtain requested authentication method"
      return nil
    end
    @auth_types = buf.unpack('N')
    if not @auth_types or @auth_types.first == 0
      msg = read_error_message
      @error = "No authentication types available: #{msg}"
      return nil
    end
  else
    buf = @sock.get_once(1)
    if not buf
      @error = "Unable to obtain supported authentication method count"
      return nil
    end

    # first byte is number of security types
    num_types = buf.unpack("C").first
    if (num_types == 0)
      msg = read_error_message
      @error = "No authentication types available: #{msg}"
      return nil
    end

    buf = @sock.get_once(num_types)
    if not buf or buf.length != num_types
      @error = "Unable to read authentication types"
      return nil
    end

    @auth_types = buf.unpack("C*")
  end

  if not @auth_types or @auth_types.length < 1
    @error = "No authentication types found"
    return nil
  end

  # Select the one we prefer
  selected = nil
  selected ||= AuthType::None if @opts[:allow_none] and @auth_types.include? AuthType::None
  selected ||= AuthType::VNC if @auth_types.include? AuthType::VNC

  if not selected
    @error = "No supported authentication method found."
    return nil
  end

  # For 3.7 and later, clients must state which security-type to use
  @sock.put([selected].pack('C')) if @minver >= 7

  selected
end
negotiate_vnc_auth(password = nil) click to toggle source
# File lib/rex/proto/rfb/client.rb, line 185
def negotiate_vnc_auth(password = nil)
  challenge = @sock.get_once(16)
  if not challenge or challenge.length != 16
    @error = "Unable to obtain VNC challenge"
    return false
  end

  response = Cipher.encrypt(challenge, password)
  @sock.put(response)

  true
end
read_error_message() click to toggle source
# File lib/rex/proto/rfb/client.rb, line 31
def read_error_message
  len = @sock.get_once(4)
  return 'Unknown error' if not len or len.length != 4

  len = len.unpack("N").first
  @sock.get_once(len)
end
send_client_init() click to toggle source
# File lib/rex/proto/rfb/client.rb, line 76
def send_client_init
  if @opts[:exclusive]
    @sock.put("\x00") # do share.
  else
    @sock.put("\x01") # do share.
  end
end