diff --git a/examples/anonymous_auth.rb b/examples/anonymous_auth.rb index 2c8a4a2b..e6ed147a 100644 --- a/examples/anonymous_auth.rb +++ b/examples/anonymous_auth.rb @@ -45,6 +45,11 @@ def run_authentication(address, smb1, smb2, smb3) end optparser.parse!(args) +if options[:target] == '-h' || options[:target] == '--help' + puts optparser.help + exit +end + if options[:target].nil? abort(optparser.help) end diff --git a/examples/append_file.rb b/examples/append_file.rb index da91c06c..e94a1de2 100644 --- a/examples/append_file.rb +++ b/examples/append_file.rb @@ -2,27 +2,70 @@ # This example script is used for testing the appending to a file. # It will attempt to connect to a specific share and then append to a specified file. -# Example usage: ruby append_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE test.txt "data to write" +# Example usage: ruby append_file.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE test.txt "data to write" # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials -# and write "data to write" the end of the file test.txt +# and append "data to write" to the end of the file test.txt require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -share = ARGV[3] -file = ARGV[4] -data = ARGV[5] -smb_versions = ARGV[6]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + share: nil, + file: nil, + data: nil +} +options[:data] = args.pop +options[:file] = args.pop +options[:share] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file data" + 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 +optparser.parse!(args) + +if [options[:target], options[:share], options[:file], options[:data]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:share].nil? || options[:file].nil? || options[:data].nil? + abort(optparser.help) +end -path = "\\\\#{address}\\#{share}" +path = "\\\\#{options[:target]}\\#{options[:share]}" -sock = TCPSocket.new address, 445 +sock = TCPSocket.new options[:target], 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -35,8 +78,8 @@ puts "Failed to connect to #{path}: #{e.message}" end -file = tree.open_file(filename: file, write: true, disposition: RubySMB::Dispositions::FILE_OPEN_IF) +file = tree.open_file(filename: options[:file], write: true, disposition: RubySMB::Dispositions::FILE_OPEN_IF) -result = file.append(data: data) +result = file.append(data: options[:data]) puts result.to_s file.close diff --git a/examples/authenticate.rb b/examples/authenticate.rb index 912d5fba..aff6d9ea 100644 --- a/examples/authenticate.rb +++ b/examples/authenticate.rb @@ -4,14 +4,15 @@ # including protocol negotiation and authentication. require 'bundler/setup' +require 'optparse' require 'ruby_smb' -def run_authentication(address, smb1, smb2, smb3, username, password) +def run_authentication(address, smb1, smb2, smb3, username, password, domain) # Create our socket and add it to the dispatcher sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock) - client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, smb3: smb3, username: username, password: password) + client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, smb3: smb3, username: username, password: password, domain: domain) protocol = client.negotiate status = client.authenticate puts "#{protocol} : #{status}" @@ -28,17 +29,64 @@ def run_authentication(address, smb1, smb2, smb3, username, password) puts "OS Version: #{client.os_version}" end -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] - -# Negotiate with SMB1, SMB2 and SMB3 enabled on the client -run_authentication(address, true, true, true, username, password) -# Negotiate with both SMB1 and SMB2 enabled on the client -run_authentication(address, true, true, false, username, password) -# Negotiate with only SMB1 enabled -run_authentication(address, true, false, false, username, password) -# Negotiate with only SMB2 enabled -run_authentication(address, false, true, false, username, password) -# Negotiate with only SMB3 enabled -run_authentication(address, false, false, true, username, password) +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil +} +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target" + 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 +optparser.parse!(args) + +if options[:target] == '-h' || options[:target] == '--help' + puts optparser.help + exit +end + +if options[:target].nil? + abort(optparser.help) +end + +# (smb1, smb2, smb3) combinations to exercise — filtered by the user's +# --[no-]smbv{1,2,3} flags so that any combo requiring a disabled version +# is skipped. +combinations = [ + [true, true, true], # SMB1, SMB2 and SMB3 enabled + [true, true, false], # SMB1 and SMB2 enabled + [true, false, false], # only SMB1 enabled + [false, true, false], # only SMB2 enabled + [false, false, true] # only SMB3 enabled +] + +combinations.each do |smb1, smb2, smb3| + next if smb1 && !options[:smbv1] + next if smb2 && !options[:smbv2] + next if smb3 && !options[:smbv3] + run_authentication(options[:target], smb1, smb2, smb3, options[:username], options[:password], options[:domain]) +end diff --git a/examples/delete_file.rb b/examples/delete_file.rb index 8b313aa8..b5210fce 100644 --- a/examples/delete_file.rb +++ b/examples/delete_file.rb @@ -2,26 +2,68 @@ # This example script is used for testing the deleting of a file. # It will attempt to connect to a specific share and then delete a specified file. -# Example usage: ruby delete_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE short.txt +# Example usage: ruby delete_file.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE short.txt # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials # and delete the file short.txt require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -share = ARGV[3] -file = ARGV[4] -smb_versions = ARGV[5]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + share: nil, + file: nil +} +options[:file] = args.pop +options[:share] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file" + 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 +optparser.parse!(args) + +if [options[:target], options[:share], options[:file]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:share].nil? || options[:file].nil? + abort(optparser.help) +end -path = "\\\\#{address}\\#{share}" +path = "\\\\#{options[:target]}\\#{options[:share]}" -sock = TCPSocket.new address, 445 +sock = TCPSocket.new options[:target], 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -35,7 +77,7 @@ puts "Failed to connect to #{path}: #{e.message}" end -file = tree.open_file(filename: file, delete: true) +file = tree.open_file(filename: options[:file], delete: true) data = file.delete puts data diff --git a/examples/dump_secrets_from_sid.rb b/examples/dump_secrets_from_sid.rb index f88f5a5c..4b953392 100644 --- a/examples/dump_secrets_from_sid.rb +++ b/examples/dump_secrets_from_sid.rb @@ -2,26 +2,61 @@ # This example script is used for testing DCERPC client and DRSR structures. # It will attempt to connect to a host and enumerate user secrets. -# Example usage: ruby dump_secrets_from_sid.rb 192.168.172.138 msfadmin msfadmin MYDOMAIN S-1-5-21-419547006-9448028-4223375872-500 +# Example usage: ruby dump_secrets_from_sid.rb --username msfadmin --password msfadmin 192.168.172.138 MYDOMAIN S-1-5-21-419547006-9448028-4223375872-500 # This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin # credentials and enumerate secrets of domain user with SID # S-1-5-21-419547006-9448028-4223375872-500 require 'bundler/setup' +require 'optparse' +require 'ruby_smb' require 'ruby_smb/dcerpc/client' +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + target: nil, + lookup_domain: nil, + sid: nil +} +options[:sid] = args.pop +options[:lookup_domain] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target domain sid" + 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 +optparser.parse!(args) + +if [options[:target], options[:lookup_domain], options[:sid]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:lookup_domain].nil? || options[:sid].nil? + abort(optparser.help) +end -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -domain = ARGV[3] -sid = ARGV[4] +address = options[:target] +domain = options[:lookup_domain] +sid = options[:sid] client = RubySMB::Dcerpc::Client.new( address, RubySMB::Dcerpc::Drsr, - username: username, - password: password, + username: options[:username], + password: options[:password], ) client.connect puts('Binding to DRSR...') diff --git a/examples/enum_domain_users.rb b/examples/enum_domain_users.rb index 12a21c77..c2179fd6 100644 --- a/examples/enum_domain_users.rb +++ b/examples/enum_domain_users.rb @@ -2,21 +2,65 @@ # This example script is used for testing DCERPC SAMR requests. # It will attempt to connect to a server object and enumerate domain users. -# Example usage: ruby enum_domain_users.rb 192.168.172.138 msfadmin msfadmin MyDomain +# Example usage: ruby enum_domain_users.rb --username msfadmin --password msfadmin 192.168.172.138 MyDomain require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -domain = ARGV[3] -smb_versions = ARGV[4]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + lookup_domain: nil +} +options[:lookup_domain] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target domain" + 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 +optparser.parse!(args) + +if [options[:target], options[:lookup_domain]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:lookup_domain].nil? + abort(optparser.help) +end + +address = options[:target] +domain = options[:lookup_domain] sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -72,4 +116,3 @@ samr.close_handle(server_handle) client.disconnect! - diff --git a/examples/enum_registry_key.rb b/examples/enum_registry_key.rb index 17201347..7afefea2 100644 --- a/examples/enum_registry_key.rb +++ b/examples/enum_registry_key.rb @@ -2,22 +2,66 @@ # This example script is used for testing Winreg registry key enumeration functionality # It will attempt to connect to a host and enumerate registry subkeys of a specified registry key. -# Example usage: ruby enum_registry_key.rb 192.168.172.138 msfadmin msfadmin HKLM\\My\\Key +# Example usage: ruby enum_registry_key.rb --username msfadmin --password msfadmin 192.168.172.138 HKLM\\My\\Key # This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentialas and enumerate HKLM\\My\\Key subkeys. require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -registry_key = ARGV[3] -smb_versions = ARGV[4]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + registry_key: nil +} +options[:registry_key] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target registry_key" + 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 +optparser.parse!(args) + +if [options[:target], options[:registry_key]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:registry_key].nil? + abort(optparser.help) +end + +address = options[:target] +registry_key = options[:registry_key] sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate diff --git a/examples/enum_registry_values.rb b/examples/enum_registry_values.rb index bd09f24b..a4edec7c 100644 --- a/examples/enum_registry_values.rb +++ b/examples/enum_registry_values.rb @@ -2,22 +2,66 @@ # This example script is used for testing values enumeration of a specific Winreg registry. # It will attempt to connect to a host and enumerate values of a specified registry key. -# Example usage: ruby enum_registry_values.rb 192.168.172.138 msfadmin msfadmin HKLM\\My\\Key +# Example usage: ruby enum_registry_values.rb --username msfadmin --password msfadmin 192.168.172.138 HKLM\\My\\Key # This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentialas and enumerate HKLM\\My\\Key values. require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -registry_key = ARGV[3] -smb_versions = ARGV[4]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + registry_key: nil +} +options[:registry_key] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target registry_key" + 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 +optparser.parse!(args) + +if [options[:target], options[:registry_key]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:registry_key].nil? + abort(optparser.help) +end + +address = options[:target] +registry_key = options[:registry_key] sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -27,5 +71,3 @@ puts enum_result client.disconnect! - - diff --git a/examples/get_computer_info.rb b/examples/get_computer_info.rb index 55ee17f3..3788ba76 100644 --- a/examples/get_computer_info.rb +++ b/examples/get_computer_info.rb @@ -2,20 +2,62 @@ # This example script is used for testing DCERPC WKST requests. # It will attempt to retrieve configuration information of a remote computer/server. -# Example usage: ruby enum_domain_users.rb 192.168.172.138 msfadmin msfadmin MyDomain +# Example usage: ruby get_computer_info.rb --username msfadmin --password msfadmin 192.168.172.138 require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -smb_versions = ARGV[3]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil +} +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target" + 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 +optparser.parse!(args) + +if options[:target] == '-h' || options[:target] == '--help' + puts optparser.help + exit +end + +if options[:target].nil? + abort(optparser.help) +end + +address = options[:target] sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -38,5 +80,3 @@ puts "OS Version: #{info.wki100_ver_major}.#{info.wki100_ver_minor}" client.disconnect! - - diff --git a/examples/list_directory.rb b/examples/list_directory.rb index 02790f14..ee387fa4 100644 --- a/examples/list_directory.rb +++ b/examples/list_directory.rb @@ -2,27 +2,69 @@ # This example script is used for testing directory listing functionality # It will attempt to connect to a specific share and then list all files in a -# specified directory.. -# Example usage: ruby list_directory.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE subdir1 +# specified directory. +# Example usage: ruby list_directory.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE subdir1 # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials, # and then list the contents of the directory 'subdir1' require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -share = ARGV[3] -dir = ARGV[4] -smb_versions = ARGV[5]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + share: nil, + directory: nil +} +options[:directory] = args.pop +options[:share] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share directory" + 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 +optparser.parse!(args) + +if [options[:target], options[:share], options[:directory]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:share].nil? || options[:directory].nil? + abort(optparser.help) +end -path = "\\\\#{address}\\#{share}" +path = "\\\\#{options[:target]}\\#{options[:share]}" -sock = TCPSocket.new address, 445 +sock = TCPSocket.new options[:target], 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -35,7 +77,7 @@ puts "Failed to connect to #{path}: #{e.message}" end -files = tree.list(directory: dir) +files = tree.list(directory: options[:directory]) files.each do |file| create_time = file.create_time.to_datetime.to_s diff --git a/examples/negotiate.rb b/examples/negotiate.rb index b150f293..61d735d8 100644 --- a/examples/negotiate.rb +++ b/examples/negotiate.rb @@ -5,63 +5,75 @@ # without any other parts. require 'bundler/setup' +require 'optparse' require 'ruby_smb' -def run_negotiation(address, smb1, smb2, smb3, opts = {}) +def run_negotiation(address, smb1, smb2, smb3) # Create our socket and add it to the dispatcher sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock) - client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, smb3: smb3, username: 'msfadmin', password: 'msfadmin') + client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, smb3: smb3, username: '', password: '') client.negotiate end -begin - puts "Negotiate with only SMB1 enabled..." - puts " Negotiated version: #{run_negotiation(ARGV[0], true, false, false)}" -rescue RubySMB::Error::RubySMBError => e - puts "Error: #{e.message}" +args = ARGV.dup +options = { + smbv1: true, + smbv2: true, + smbv3: true, + target: nil +} +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target" + 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 end +optparser.parse!(args) -begin - puts "Negotiate with only SMB2 enabled..." - puts " Negotiated version: #{run_negotiation(ARGV[0], false, true, false)}" -rescue RubySMB::Error::RubySMBError => e - puts "Error: #{e.message}" +if options[:target] == '-h' || options[:target] == '--help' + puts optparser.help + exit end -begin - puts "Negotiate with only SMB3 enabled..." - puts " Negotiated version: #{run_negotiation(ARGV[0], false, false, true)}" -rescue RubySMB::Error::RubySMBError => e - puts "Error: #{e.message}" +if options[:target].nil? + abort(optparser.help) end -begin - puts "Negotiate with both SMB1 and SMB2 enabled on the client..." - puts " Negotiated version: #{run_negotiation(ARGV[0], true, true, false)}" -rescue RubySMB::Error::RubySMBError => e - puts "Error: #{e.message}" -end +# (smb1, smb2, smb3) combinations to exercise — filtered by the user's +# --[no-]smbv{1,2,3} flags so any combo requiring a disabled version +# is skipped. +combinations = [ + [true, false, false], # only SMB1 + [false, true, false], # only SMB2 + [false, false, true], # only SMB3 + [true, true, false], # SMB1 and SMB2 + [false, true, true], # SMB2 and SMB3 + [true, false, true], # SMB1 and SMB3 + [true, true, true] # SMB1, SMB2 and SMB3 +] -begin - puts "Negotiate with both SMB2 and SMB3 enabled on the client..." - puts " Negotiated version: #{run_negotiation(ARGV[0], false, true, true)}" -rescue RubySMB::Error::RubySMBError => e - puts "Error: #{e.message}" -end +combinations.each do |smb1, smb2, smb3| + next if smb1 && !options[:smbv1] + next if smb2 && !options[:smbv2] + next if smb3 && !options[:smbv3] -begin - puts "Negotiate with both SMB1 and SMB3 enabled on the client..." - puts " Negotiated version: #{run_negotiation(ARGV[0], true, false, true)}" -rescue RubySMB::Error::RubySMBError => e - puts "Error: #{e.message}" + enabled = [] + enabled << 'SMB1' if smb1 + enabled << 'SMB2' if smb2 + enabled << 'SMB3' if smb3 + puts "Negotiate with #{enabled.join(', ')} enabled..." + begin + puts " Negotiated version: #{run_negotiation(options[:target], smb1, smb2, smb3)}" + rescue RubySMB::Error::RubySMBError => e + puts "Error: #{e.message}" + end end - -begin - puts "Negotiate with SMB1, SMB2 and SMB3 enabled on the client..." - puts " Negotiated version: #{run_negotiation(ARGV[0], true, true, true)}" -rescue RubySMB::Error::RubySMBError => e - puts "Error: #{e.message}" -end - diff --git a/examples/negotiate_with_netbios_service.rb b/examples/negotiate_with_netbios_service.rb index ed398d7b..c01db3b8 100644 --- a/examples/negotiate_with_netbios_service.rb +++ b/examples/negotiate_with_netbios_service.rb @@ -1,19 +1,19 @@ #!/usr/bin/ruby # This script is for testing the NetBIOS Session Service Request on port 139/tcp. -# Example usage: ruby negotiate.rb 192.168.172.138 NBNAME -# This will connect to 192.168.172.138 (139/TCP) and request a NetBIOS session with NBNAME as the called name. +# This will connect to 192.168.172.138 (139/TCP) and request a NetBIOS session with NBNAME as the called name. # If successful, a SMB negotiation is performed using this NetBIOS session. # The default *SMBSERVER name is used if the NetBIOS name is not provided. require 'bundler/setup' +require 'optparse' require 'ruby_smb' def run_negotiation(address, smb1, smb2, smb3, netbios_name) sock = TCPSocket.new address, 139 dispatcher = RubySMB::Dispatcher::Socket.new(sock) - client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, smb3: smb3, username: 'msfadmin', password: 'msfadmin') + client = RubySMB::Client.new(dispatcher, smb1: smb1, smb2: smb2, smb3: smb3, username: '', password: '') begin client.session_request(netbios_name) rescue RubySMB::Error::NetBiosSessionService => e @@ -25,16 +25,55 @@ def run_negotiation(address, smb1, smb2, smb3, netbios_name) puts "#{smb_version} successfully negotiated." end -address = ARGV[0] -netbios_name = ARGV[1] || '*SMBSERVER' - -# Negotiate with SMB1, SMB2 and SMB3 enabled on the client -run_negotiation(ARGV[0], true, true, true, netbios_name) -# Negotiate with both SMB1 and SMB2 enabled on the client -run_negotiation(ARGV[0], true, true, false, netbios_name) -# Negotiate with only SMB1 enabled -run_negotiation(ARGV[0], true, false, false, netbios_name) -# Negotiate with only SMB2 enabled -run_negotiation(ARGV[0], false, true, false, netbios_name) -# Negotiate with only SMB3 enabled -run_negotiation(ARGV[0], false, false, true, netbios_name) +args = ARGV.dup +options = { + smbv1: true, + smbv2: true, + smbv3: true, + netbios_name: '*SMBSERVER', + target: nil +} +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target" + 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("--netbios-name NAME", "The NetBIOS called name (default: #{options[:netbios_name]})") do |name| + options[:netbios_name] = name + end +end +optparser.parse!(args) + +if options[:target] == '-h' || options[:target] == '--help' + puts optparser.help + exit +end + +if options[:target].nil? + abort(optparser.help) +end + +# (smb1, smb2, smb3) combinations to exercise — filtered by the user's +# --[no-]smbv{1,2,3} flags so any combo requiring a disabled version +# is skipped. +combinations = [ + [true, true, true], # SMB1, SMB2 and SMB3 enabled + [true, true, false], # SMB1 and SMB2 enabled + [true, false, false], # only SMB1 enabled + [false, true, false], # only SMB2 enabled + [false, false, true] # only SMB3 enabled +] + +combinations.each do |smb1, smb2, smb3| + next if smb1 && !options[:smbv1] + next if smb2 && !options[:smbv2] + next if smb3 && !options[:smbv3] + run_negotiation(options[:target], smb1, smb2, smb3, options[:netbios_name]) +end diff --git a/examples/net_share_enum_all.rb b/examples/net_share_enum_all.rb index 89a991a1..839fc33a 100644 --- a/examples/net_share_enum_all.rb +++ b/examples/net_share_enum_all.rb @@ -2,23 +2,63 @@ # This example script is used for testing NetShareEnumAll functionality # It will attempt to connect to a host and enumerate shares. -# Example usage: ruby net_share_enum_all.rb 192.168.172.138 msfadmin msfadmin +# Example usage: ruby net_share_enum_all.rb --username msfadmin --password msfadmin 192.168.172.138 # This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentials require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -smb_versions = ARGV[3]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil +} +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target" + 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 +optparser.parse!(args) + +if options[:target] == '-h' || options[:target] == '--help' + puts optparser.help + exit +end -path = "\\\\#{address}\\IPC$" +if options[:target].nil? + abort(optparser.help) +end + +address = options[:target] sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -32,4 +72,3 @@ end client.disconnect! - diff --git a/examples/pipes.rb b/examples/pipes.rb index e200feed..b0653a0a 100644 --- a/examples/pipes.rb +++ b/examples/pipes.rb @@ -4,22 +4,66 @@ # Example script for connecting to a named pipe and performing a peek operation. # This is used to demonstrate pipe operations. # -# Usage: ruby pipes.rb ADDRESS PIPENAME USER PASS 1|2 +# Usage: ruby pipes.rb --username USER --password PASS ADDRESS PIPENAME # require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -pipename = ARGV[1] -username = ARGV[2] -password = ARGV[3] -smb_versions = ARGV[4]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + pipename: nil +} +options[:pipename] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target pipename" + 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 +optparser.parse!(args) + +if [options[:target], options[:pipename]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:pipename].nil? + abort(optparser.help) +end + +address = options[:target] +pipename = options[:pipename] sock = TCPSocket.new(address, 445) dispatcher = RubySMB::Dispatcher::Socket.new(sock) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) smbver = client.negotiate if smbver == 'SMB1' diff --git a/examples/query_service_status.rb b/examples/query_service_status.rb index 5fcba03a..a00d05f3 100644 --- a/examples/query_service_status.rb +++ b/examples/query_service_status.rb @@ -2,22 +2,66 @@ # This example script is used for testing remote service status and start type query. # It will attempt to connect to a host and query the status and start type of the provided service. -# Example usage: ruby query_service_status.rb 192.168.172.138 msfadmin msfadmin "RemoteRegistry" +# Example usage: ruby query_service_status.rb --username msfadmin --password msfadmin 192.168.172.138 "RemoteRegistry" # This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentialas and get the status and start type of the "RemoteRegistry" service. require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -service = ARGV[3] -smb_versions = ARGV[4]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + service: nil +} +options[:service] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target service" + 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 +optparser.parse!(args) + +if [options[:target], options[:service]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:service].nil? + abort(optparser.help) +end + +address = options[:target] +service = options[:service] sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -99,4 +143,3 @@ svcctl.close end client.disconnect! - diff --git a/examples/read_file_encryption.rb b/examples/read_file_encryption.rb index 3cad641f..bbccb9b8 100644 --- a/examples/read_file_encryption.rb +++ b/examples/read_file_encryption.rb @@ -1,24 +1,11 @@ #!/usr/bin/ruby -# This example script is used for testing the reading of a file. +# This example script is used for testing the reading of a file with SMBv3 encryption. # It will attempt to connect to a specific share and then read a specified file. -# Example usage: ruby read_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE short.txt +# Example usage: ruby read_file_encryption.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE short.txt # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials # and read the file short.txt -require 'bundler/setup' -require 'ruby_smb' - -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -share = ARGV[3] -filename = ARGV[4] -path = "\\\\#{address}\\#{share}" - -sock = TCPSocket.new address, 445 -dispatcher = RubySMB::Dispatcher::Socket.new(sock) - # To require encryption on the server, run this in an elevated Powershell: # C:\> Set-SmbServerConfiguration -EncryptData $true @@ -26,20 +13,78 @@ # C:\ Set-SmbServerConfiguration -EncryptData $false # C:\ Set-SmbShare -Name -EncryptData 1 -# For this encryption to work, it has to be SMBv3. By only setting smb3 to true, -# we make sure the server will negotiate this version, if it supports it -opts = { - smb1: false, - smb2: false, - smb3: true, - username: username, - password: password, +# For this encryption to work, it has to be SMBv3. By default, SMBv1 and SMBv2 +# are disabled here so the server will negotiate SMBv3 if it supports it. + +require 'bundler/setup' +require 'optparse' +require 'ruby_smb' + +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: false, + smbv2: false, + smbv3: true, + target: nil, + share: nil, + file: nil } +options[:file] = args.pop +options[:share] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file" + 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 +optparser.parse!(args) + +if [options[:target], options[:share], options[:file]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:share].nil? || options[:file].nil? + abort(optparser.help) +end + +path = "\\\\#{options[:target]}\\#{options[:share]}" + +sock = TCPSocket.new options[:target], 445 +dispatcher = RubySMB::Dispatcher::Socket.new(sock) # By default, the client uses encryption even if it is not required by the server. Disable this by setting always_encrypt to false -#opts[:always_encrypt] = false +client_opts = { + smb1: options[:smbv1], + smb2: options[:smbv2], + smb3: options[:smbv3], + username: options[:username], + password: options[:password], + domain: options[:domain] +} +#client_opts[:always_encrypt] = false -client = RubySMB::Client.new(dispatcher, opts) +client = RubySMB::Client.new(dispatcher, **client_opts) protocol = client.negotiate status = client.authenticate @@ -49,7 +94,7 @@ puts "Failed to connect to #{path}: #{e.message}" end -file = tree.open_file(filename: filename) +file = tree.open_file(filename: options[:file]) data = file.read puts data diff --git a/examples/read_registry_key_value.rb b/examples/read_registry_key_value.rb index bf03395c..3dd9a305 100644 --- a/examples/read_registry_key_value.rb +++ b/examples/read_registry_key_value.rb @@ -2,23 +2,69 @@ # This example script is used for testing the Winreg registry key value read functionality. # It will attempt to connect to a host and reads the value of a specified registry key. -# Example usage: ruby enum_registry_key.rb 192.168.172.138 msfadmin msfadmin HKLM\\My\\Key ValueName +# Example usage: ruby read_registry_key_value.rb --username msfadmin --password msfadmin 192.168.172.138 HKLM\\My\\Key ValueName # This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentialas and reads the ValueName data corresponding to the HKLM\\My\\Key registry key. require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -registry_key = ARGV[3] -value_name = ARGV[4] -smb_versions = ARGV[5]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + registry_key: nil, + value_name: nil +} +options[:value_name] = args.pop +options[:registry_key] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target registry_key value_name" + 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 +optparser.parse!(args) + +if [options[:target], options[:registry_key], options[:value_name]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:registry_key].nil? || options[:value_name].nil? + abort(optparser.help) +end + +address = options[:target] +registry_key = options[:registry_key] +value_name = options[:value_name] sock = TCPSocket.new address, 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -30,4 +76,3 @@ puts key_value client.disconnect! - diff --git a/examples/rename_file.rb b/examples/rename_file.rb index c5d85929..048ae038 100644 --- a/examples/rename_file.rb +++ b/examples/rename_file.rb @@ -1,28 +1,71 @@ #!/usr/bin/ruby -# This example script is used for testing the deleting of a file. +# This example script is used for testing the renaming of a file. # It will attempt to connect to a specific share and then rename a specified file. -# Example usage: ruby rename_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE short.txt shortrenamed.txt +# Example usage: ruby rename_file.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE short.txt shortrenamed.txt # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials -# and rename the file short.txt +# and rename the file short.txt to shortrenamed.txt require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -share = ARGV[3] -file = ARGV[4] -new_name = ARGV[5] -smb_versions = ARGV[6]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + share: nil, + file: nil, + new_name: nil +} +options[:new_name] = args.pop +options[:file] = args.pop +options[:share] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file new_name" + 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 +optparser.parse!(args) + +if [options[:target], options[:share], options[:file], options[:new_name]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:share].nil? || options[:file].nil? || options[:new_name].nil? + abort(optparser.help) +end -path = "\\\\#{address}\\#{share}" +path = "\\\\#{options[:target]}\\#{options[:share]}" -sock = TCPSocket.new address, 445 +sock = TCPSocket.new options[:target], 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -36,8 +79,8 @@ puts "Failed to connect to #{path}: #{e.message}" end -file = tree.open_file(filename: file, write: true, delete: true) +file = tree.open_file(filename: options[:file], write: true, delete: true) -data = file.rename(new_name) +data = file.rename(options[:new_name]) puts data file.close diff --git a/examples/write_file.rb b/examples/write_file.rb index a15cc613..e7ead99b 100644 --- a/examples/write_file.rb +++ b/examples/write_file.rb @@ -2,27 +2,70 @@ # This example script is used for testing the writing to a file. # It will attempt to connect to a specific share and then write to a specified file. -# Example usage: ruby write_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE test.txt "data to write" +# Example usage: ruby write_file.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE test.txt "data to write" # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials -# and write "data to write" the file test.txt +# and write "data to write" to the file test.txt require 'bundler/setup' +require 'optparse' require 'ruby_smb' -address = ARGV[0] -username = ARGV[1] -password = ARGV[2] -share = ARGV[3] -file = ARGV[4] -data = ARGV[5] -smb_versions = ARGV[6]&.split(',') || ['1','2','3'] +args = ARGV.dup +options = { + domain: '.', + username: '', + password: '', + smbv1: true, + smbv2: true, + smbv3: true, + target: nil, + share: nil, + file: nil, + data: nil +} +options[:data] = args.pop +options[:file] = args.pop +options[:share] = args.pop +options[:target] = args.pop +optparser = OptionParser.new do |opts| + opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file data" + 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 +optparser.parse!(args) + +if [options[:target], options[:share], options[:file], options[:data]].any? { |a| a == '-h' || a == '--help' } + puts optparser.help + exit +end + +if options[:target].nil? || options[:share].nil? || options[:file].nil? || options[:data].nil? + abort(optparser.help) +end -path = "\\\\#{address}\\#{share}" +path = "\\\\#{options[:target]}\\#{options[:share]}" -sock = TCPSocket.new address, 445 +sock = TCPSocket.new options[:target], 445 dispatcher = RubySMB::Dispatcher::Socket.new(sock) -client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password) +client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain]) protocol = client.negotiate status = client.authenticate @@ -32,11 +75,11 @@ tree = client.tree_connect(path) puts "Connected to #{path} successfully!" rescue StandardError => e - puts "Failed to connect to #{path}: #{e.message}" + abort("Failed to connect to #{path}: #{e.message}") end -file = tree.open_file(filename: file, write: true, disposition: RubySMB::Dispositions::FILE_OVERWRITE_IF) +file = tree.open_file(filename: options[:file], write: true, disposition: RubySMB::Dispositions::FILE_OVERWRITE_IF) -result = file.write(data: data) +result = file.write(data: options[:data]) puts result.to_s file.close