Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New module to replicate xspy tool (and x11 library) #18877

Open
wants to merge 31 commits into
base: master
Choose a base branch
from

Conversation

h00die
Copy link
Contributor

@h00die h00die commented Feb 22, 2024

This PR implements a rudimentary pure ruby X11 library, and a module to bind to open x11 sessions to perform keylogging. This is a replica of the xspy tool from forever ago.

When this lands I'll circle back around on adding the screenshot capability.

Verification

  • Create an open x11, i recommend the socat method.
  • Start msfconsole
  • try out the scanner modules per the docs

lib/msf/core/exploit/remote/x11/window.rb Outdated Show resolved Hide resolved
modules/auxiliary/gather/x11_keyboard_spy.rb Outdated Show resolved Hide resolved
modules/auxiliary/gather/x11_keyboard_spy.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/x11/open_x11.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/x11/open_x11_screenshot.rb Outdated Show resolved Hide resolved
spec/lib/msf/core/exploit/remote/x11.rb Outdated Show resolved Hide resolved
@h00die h00die marked this pull request as ready for review April 14, 2024 23:51
@h00die
Copy link
Contributor Author

h00die commented Apr 14, 2024

I'll give this another check tomorrow, I know some of the reviews have some notes to touch up, but I think its ready for review.

I'm going to do an x11 screenshot taker as well, so some of the lib functions aren't used yet, but wanted to get this in framework first before it gets too out of hand.

@smcintyre-r7 smcintyre-r7 self-assigned this Apr 17, 2024
@h00die
Copy link
Contributor Author

h00die commented Apr 17, 2024

@smcintyre-r7 you can go ahead and start reviewing. I know I need to update the open_x11 scanner docs, and a few other minor things. figured this may take a little bit since its so large

Copy link
Contributor

@smcintyre-r7 smcintyre-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left quite a few comments, but overall things are looking pretty good. Thanks for this new protocol!

lib/msf/core/exploit/remote/x11.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/x11/extensions.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/x11/window.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/x11/window.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/x11/window.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/x11.rb Outdated Show resolved Hide resolved
modules/auxiliary/gather/x11_keyboard_spy.rb Outdated Show resolved Hide resolved
modules/auxiliary/gather/x11_keyboard_spy.rb Outdated Show resolved Hide resolved
modules/auxiliary/scanner/x11/open_x11.rb Outdated Show resolved Hide resolved
lib/msf/core/exploit/remote/x11.rb Show resolved Hide resolved
@h00die
Copy link
Contributor Author

h00die commented Apr 22, 2024

got through some, just an update that I'm working on it, its not abandoned :)

@h00die
Copy link
Contributor Author

h00die commented Jul 12, 2024

prob worth a squash when this is ready to merge, no one needs to see 31+ commits where I learn to code gooderer.

@h00die
Copy link
Contributor Author

h00die commented Jul 12, 2024

I believe this is ready to look at again. It's undergone a lot of changes, so may want to treat it as a fresh PR.


print_good('All setup, watching for keystrokes')
# loop mechanics stolen from exploit/multi/handler
stime = Time.now.to_f
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be great to use Process.clock_gettime(Process::CLOCK_MONOTONIC) instead of these Time.now calls 👍

https://blog.dnsimple.com/2018/03/elapsed-time-with-ruby-the-right-way/

Comment on lines +194 to +251
def create_overlay_map(screen_width, screen_height, windows)
# Initialize a 2D array to represent the screen
screen = Array.new(screen_height) { Array.new(screen_width, nil) }
windows.each_with_index do |window, i|
puts window.inspect
x, y, width, height = window
# Mark the visible region occupied by the window
(y...y + height).each do |row|
(x...x + width).each do |col|
screen[row][col] = i
end
end
end
screen.each do |row|
puts row.join('')
end
end

class X11Image
def initialize(width, height, image_data, color_data)
@width = width # integer, 1024 in 1024×768
@height = height # integer, 768 in 1024×768
@image_data = image_data # from X11GetImageResponse
@color_data = color_data # from X11GetColorsResponse
end

def self.from_replies(width, height, image_reply, color_reply)
new(width, height, image_reply.image_data, color_reply.colors)
end

def create_image
# Extract relevant data from @image_data and @color_data
width = @width
height = @height
pixel_data = @image_data
colors = @color_data

# Create an image object
image = ChunkyPNG::Image.new(width, height, ChunkyPNG::Color::TRANSPARENT)

# Populate image with pixel data and colors
pixel_data.each_with_index do |pixel, i|
color = colors[pixel]
# Set pixel color in the image
image[i % width, i / width] = ChunkyPNG::Color.rgb(color.red, color.green, color.blue)
end
# (0...height).each do |y|
# (0...width).each do |x|
# # Extract color information from the pixel data and set the corresponding pixel in the PNG image
# color = colors[y+x]
# # pixel_color = extract_color_from_z_data(z_data)
# image[x, y] = ChunkyPNG::Color.rgb(color.red, color.green, color.blue)
# end
# end

image
end
end
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see where either of these are referenced, so it may be safe to remove them unless I'm not seeing something. The reason I was looking into it, is that if we need to keep the definitions, we should move them so they're not defined globally. If I can see where they're referenced, I can make better recommendations on how to move them to someplace sensible.

rescue ::Rex::ConnectionError
rescue ::Errno::EPIPE
if connection.header.success == 1
print_connection_info(connection, ip, rport)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't report it as a service but as a note. The scanner here should definitely report it as a service since that's probably the context in which this module would be used. I'd either recommend updating #print_connection_info to report the service, or report it here.

@smcintyre-r7
Copy link
Contributor

I'm inconsistently getting the following stack trace. My target is an Ubuntu 22.04 x64 workstation where I installed socat. It seems like it's easier to reproduce the stack trace after rebooting. If I run the module a couple of times without rebooting the target, it'll work after 1 or 2 failures.

EOF Stack Trace
metasploit-framework.pr (S:0 J:0) auxiliary(gather/x11_keyboard_spy) > run
[*] Running module against 192.168.159.135

[*] 192.168.159.135:6000 - Establishing TCP Connection
[*] 192.168.159.135:6000 - [1/9] Establishing X11 connection
[+] 192.168.159.135:6000 - 192.168.159.135 - Successfully established X11 connection
[*] 192.168.159.135:6000 -   Vendor: The X.Org Foundation
[*] 192.168.159.135:6000 -   Version: 11.0
[*] 192.168.159.135:6000 -   Screen Resolution: 1918x920
[*] 192.168.159.135:6000 -   Resource ID: 20971520
[*] 192.168.159.135:6000 -   Screen root: 685
[*] 192.168.159.135:6000 - [2/9] Checking on BIG-REQUESTS extension
[+] 192.168.159.135:6000 -   Extension BIG-REQUESTS is present with id 133
[*] 192.168.159.135:6000 - [3/9] Enabling BIG-REQUESTS
[*] 192.168.159.135:6000 - [4/9] Creating new graphical context
[*] 192.168.159.135:6000 - [5/9] Checking on XKEYBOARD extension
[+] 192.168.159.135:6000 -   Extension XKEYBOARD is present with id 135
[*] 192.168.159.135:6000 - [6/9] Enabling XKEYBOARD
[*] 192.168.159.135:6000 - [7/9] Requesting XKEYBOARD map
[-] 192.168.159.135:6000 - Auxiliary failed: EOFError End of file reached
[-] 192.168.159.135:6000 - Call stack:
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/io.rb:316:in `read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/io.rb:278:in `readbytes'
[-] 192.168.159.135:6000 -   (eval):23:in `read_and_return_value'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/base_primitive.rb:129:in `do_read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/struct.rb:140:in `block in do_read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/struct.rb:140:in `each'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/struct.rb:140:in `do_read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/array.rb:330:in `block in do_read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/array.rb:330:in `each'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/array.rb:330:in `do_read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/struct.rb:140:in `block in do_read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/struct.rb:140:in `each'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/struct.rb:140:in `do_read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/base.rb:147:in `block in read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/base.rb:253:in `start_read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/base.rb:145:in `read'
[-] 192.168.159.135:6000 -   /home/smcintyre/.rvm/gems/ruby-3.2.3/gems/bindata-2.4.15/lib/bindata/base.rb:21:in `read'
[-] 192.168.159.135:6000 -   /home/smcintyre/Repositories/metasploit-framework.pr/modules/auxiliary/gather/x11_keyboard_spy.rb:211:in `run'
[*] Auxiliary module execution completed

PCap of the transaction when the stack trace occurred.
pr-18877-eof.zip

It may be simple enough to handle the EOF and carry on, I'm not entirely sure. I've definitely seen the module work, it's just this crash sometimes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

5 participants