rapid7 / ruby_smb

A native Ruby implementation of the SMB Protocol Family
Other
79 stars 82 forks source link

Support a custom thread factory #216

Closed zeroSteiner closed 2 years ago

zeroSteiner commented 2 years ago

This adds support to the RubySMB server to use a custom thread factory. This allows Metasploit to use its preferred Rex::ThreadFactory method to allow framework users to identify and kill threads as desired. The thread factory block is passed the ServerClient instance. At this point, it's not set up yet, but it does expose the connection information.

Testing is probably most easily done with PR 16481 from Metasploit Framework. The example server should continue to work as intended. See https://github.com/rapid7/metasploit-framework/pull/16481#discussion_r854657538 for context.

gwillcox-r7 commented 2 years ago

Alright so looks like this is working. For reference since no code uses this currently this is what I used to test it out. This is just a copy of the examples\file_server.rb code however I added in a thread_factory variable that mimicks the expected behavior, but also prints out the recieved client_server's details r.e the connecting clients host and port number they are connecting from.

Here is the code looks:

Code snippet ``` #!/usr/bin/ruby require 'bundler/setup' require 'optparse' require 'ruby_smb' require 'ruby_smb/gss/provider/ntlm' # we just need *a* default encoding to handle the strings from the NTLM messages Encoding.default_internal = 'UTF-8' if Encoding.default_internal.nil? options = { allow_anonymous: true, domain: nil, username: 'RubySMB', password: 'password', share_name: 'home', share_path: '.', smbv1: true, smbv2: true, smbv3: true } OptionParser.new do |opts| opts.banner = "Usage: #{File.basename(__FILE__)} [options]" opts.on("--path PATH", "The path to share (default: #{options[:share_path]})") do |path| options[:share_path] = path end opts.on("--share SHARE", "The share name (default: #{options[:share_name]})") do |share| options[:share_name] = share end opts.on("--[no-]anonymous", "Allow anonymous access (default: #{options[:allow_anonymous]})") do |allow_anonymous| options[:allow_anonymous] = allow_anonymous end opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1| options[:smbv1] = smbv1 end opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2| options[:smbv2] = smbv2 end opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3| options[:smbv3] = smbv3 end opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username| if username.include?('\\') options[:domain], options[:username] = username.split('\\', 2) else options[:username] = username end end opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password| options[:password] = password end end.parse! ntlm_provider = RubySMB::Gss::Provider::NTLM.new(allow_anonymous: options[:allow_anonymous]) ntlm_provider.put_account(options[:username], options[:password], domain: options[:domain]) # password can also be an NTLM hash thread_factory = Proc.new do |server_client, &block| peer_host = ::Socket::unpack_sockaddr_in(server_client.getpeername)[1] peer_port = ::Socket::unpack_sockaddr_in(server_client.getpeername)[0] print "Accepting new connection from #{peer_host}:#{peer_port}\r\n" Thread.new(&block) end server = RubySMB::Server.new( gss_provider: ntlm_provider, logger: :stdout, thread_factory: thread_factory ) server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB1 } unless options[:smbv1] server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB2 } unless options[:smbv2] server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB3 } unless options[:smbv3] if server.dialects.empty? puts "at least one version must be enabled" exit false end server.add_share(RubySMB::Server::Share::Provider::Disk.new(options[:share_name], options[:share_path])) puts "server is running" server.run do puts "received connection" true end ```

And here is the resulting output from my tests:

SMB Server Output Showing Client Connection Details and Successful Connection Still ``` ~/git/ruby_smb/examples │ land-pr216:pr/216 !1 sudo ruby file_server.rb --path /var/public --share public --username TESTINGDOMAIN\\normal --password normal1 D, [2022-04-22T17:41:12.175342 #78324] DEBUG -- : Adding disk share: public server is running Accepting new connection from 172.23.126.176:51746 received connection I, [2022-04-22T17:41:26.637925 #78324] INFO -- : Negotiated dialect: SMB v3.1.1 D, [2022-04-22T17:41:26.640340 #78324] DEBUG -- : Dispatching request to do_session_setup_smb2 (session: nil) D, [2022-04-22T17:41:26.644660 #78324] DEBUG -- : Dispatching request to do_session_setup_smb2 (session: #) D, [2022-04-22T17:41:26.645175 #78324] DEBUG -- : NTLM authentication request received for TESTINGDOMAIN\normal I, [2022-04-22T17:41:26.645370 #78324] INFO -- : NTLM authentication request succeeded for TESTINGDOMAIN\normal D, [2022-04-22T17:41:26.654045 #78324] DEBUG -- : Dispatching request to do_tree_connect_smb2 (session: #) D, [2022-04-22T17:41:26.654831 #78324] DEBUG -- : Received TREE_CONNECT request for share: IPC$ D, [2022-04-22T17:41:26.663697 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:26.663806 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:26.663872 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:26.666540 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:26.673842 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:26.673928 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:26.673976 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:26.677245 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:26.684549 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:26.684699 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:26.684779 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:26.689248 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.048933 #78324] DEBUG -- : Dispatching request to do_ioctl_smb2 (session: #) D, [2022-04-22T17:41:29.049055 #78324] DEBUG -- : Received IOCTL request for share: IPC$ D, [2022-04-22T17:41:29.052238 #78324] DEBUG -- : Dispatching request to do_tree_connect_smb2 (session: #) D, [2022-04-22T17:41:29.052444 #78324] DEBUG -- : Received TREE_CONNECT request for share: public D, [2022-04-22T17:41:29.056146 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.056225 #78324] DEBUG -- : Received CREATE request for share: public D, [2022-04-22T17:41:29.066854 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.066951 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:29.067036 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:29.069510 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.074777 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.074885 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:29.074935 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:29.077270 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.194971 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.195079 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:29.195132 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:29.197782 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.202129 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.202225 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:29.202278 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:29.204991 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.260339 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.260462 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:29.260518 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:29.263380 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.270983 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.271094 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:29.271151 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:29.274159 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.330463 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.330549 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:29.330599 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:29.333423 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.338155 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.338230 #78324] DEBUG -- : Received CREATE request for share: IPC$ E, [2022-04-22T17:41:29.338423 #78324] ERROR -- : Caught a NotImplementedError while handling a CREATE request I, [2022-04-22T17:41:29.341070 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.424579 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.424709 #78324] DEBUG -- : Received CREATE request for share: public W, [2022-04-22T17:41:29.426589 #78324] WARN -- : Requested path does not exist: /var/public/desktop.ini I, [2022-04-22T17:41:29.429736 #78324] INFO -- : Sending an error packet for SMB2 command: CREATE, status: 0xc0000034 (STATUS_OBJECT_NAME_NOT_FOUND) D, [2022-04-22T17:41:29.433917 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.434032 #78324] DEBUG -- : Received CREATE request for share: public D, [2022-04-22T17:41:29.492016 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.492129 #78324] DEBUG -- : Received CREATE request for share: public D, [2022-04-22T17:41:29.498547 #78324] DEBUG -- : Dispatching request to do_query_directory_smb2 (session: #) D, [2022-04-22T17:41:29.498665 #78324] DEBUG -- : Received QUERY_DIRECTORY request for share: public I, [2022-04-22T17:41:29.501383 #78324] INFO -- : Sending an error packet for SMB2 command: QUERY_DIRECTORY, status: 0xc0000128 (STATUS_FILE_CLOSED) D, [2022-04-22T17:41:29.503242 #78324] DEBUG -- : Dispatching request to do_query_directory_smb2 (session: #) D, [2022-04-22T17:41:29.503312 #78324] DEBUG -- : Received QUERY_DIRECTORY request for share: public I, [2022-04-22T17:41:29.506238 #78324] INFO -- : Sending an error packet for SMB2 command: QUERY_DIRECTORY, status: 0xc0000128 (STATUS_FILE_CLOSED) D, [2022-04-22T17:41:29.545812 #78324] DEBUG -- : Dispatching request to do_query_directory_smb2 (session: #) D, [2022-04-22T17:41:29.545931 #78324] DEBUG -- : Received QUERY_DIRECTORY request for share: public D, [2022-04-22T17:41:29.566494 #78324] DEBUG -- : Dispatching request to do_query_directory_smb2 (session: #) D, [2022-04-22T17:41:29.566587 #78324] DEBUG -- : Received QUERY_DIRECTORY request for share: public D, [2022-04-22T17:41:29.571624 #78324] DEBUG -- : Dispatching request to do_close_smb2 (session: #) D, [2022-04-22T17:41:29.571784 #78324] DEBUG -- : Received CLOSE request for share: public D, [2022-04-22T17:41:29.576308 #78324] DEBUG -- : Dispatching request to do_close_smb2 (session: #) D, [2022-04-22T17:41:29.576423 #78324] DEBUG -- : Received CLOSE request for share: public W, [2022-04-22T17:41:29.585900 #78324] WARN -- : The SMB2 CHANGE_NOTIFY command is not supported E, [2022-04-22T17:41:29.586005 #78324] ERROR -- : Caught a NotImplementedError while handling a CHANGE_NOTIFY request I, [2022-04-22T17:41:29.588792 #78324] INFO -- : Sending an error packet for SMB2 command: CHANGE_NOTIFY, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.593227 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.593403 #78324] DEBUG -- : Received CREATE request for share: public W, [2022-04-22T17:41:29.599145 #78324] WARN -- : The SMB2 CHANGE_NOTIFY command is not supported E, [2022-04-22T17:41:29.599250 #78324] ERROR -- : Caught a NotImplementedError while handling a CHANGE_NOTIFY request I, [2022-04-22T17:41:29.602196 #78324] INFO -- : Sending an error packet for SMB2 command: CHANGE_NOTIFY, status: 0xc00000bb (STATUS_NOT_SUPPORTED) D, [2022-04-22T17:41:29.604864 #78324] DEBUG -- : Dispatching request to do_close_smb2 (session: #) D, [2022-04-22T17:41:29.604934 #78324] DEBUG -- : Received CLOSE request for share: public D, [2022-04-22T17:41:29.658893 #78324] DEBUG -- : Dispatching request to do_close_smb2 (session: #) D, [2022-04-22T17:41:29.659014 #78324] DEBUG -- : Received CLOSE request for share: public D, [2022-04-22T17:41:29.819755 #78324] DEBUG -- : Dispatching request to do_create_smb2 (session: #) D, [2022-04-22T17:41:29.819877 #78324] DEBUG -- : Received CREATE request for share: public D, [2022-04-22T17:41:29.833474 #78324] DEBUG -- : Dispatching request to do_close_smb2 (session: #) D, [2022-04-22T17:41:29.833589 #78324] DEBUG -- : Received CLOSE request for share: public ```

And finally we can see this worked successfully on the Windows 11 target:

image