ruby_smb 3.3.19 → 3.3.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/examples/anonymous_auth.rb +5 -0
- data/examples/append_file.rb +57 -14
- data/examples/authenticate.rb +64 -16
- data/examples/delete_file.rb +53 -11
- data/examples/dump_secrets_from_sid.rb +43 -8
- data/examples/enum_domain_users.rb +51 -8
- data/examples/enum_registry_key.rb +51 -7
- data/examples/enum_registry_values.rb +51 -9
- data/examples/get_computer_info.rb +48 -8
- data/examples/list_directory.rb +54 -12
- data/examples/negotiate.rb +54 -42
- data/examples/negotiate_with_netbios_service.rb +55 -16
- data/examples/net_share_enum_all.rb +47 -8
- data/examples/pipes.rb +51 -7
- data/examples/query_service_status.rb +51 -8
- data/examples/read_file_encryption.rb +71 -26
- data/examples/read_registry_key_value.rb +54 -9
- data/examples/rename_file.rb +58 -15
- data/examples/write_file.rb +58 -15
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_cifs_unix_info.rb +31 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb +4 -0
- data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb +12 -4
- data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_level.rb +28 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request.rb +90 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response.rb +56 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_information_level.rb +35 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_path_information_request.rb +75 -0
- data/lib/ruby_smb/smb1/packet/trans2/set_path_information_response.rb +51 -0
- data/lib/ruby_smb/smb1/packet/trans2.rb +8 -0
- data/lib/ruby_smb/smb1/tree.rb +124 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request_spec.rb +6 -1
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request_spec.rb +52 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response_spec.rb +29 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_request_spec.rb +114 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +124 -0
- metadata +17 -2
|
@@ -1,24 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/ruby
|
|
2
2
|
|
|
3
|
-
# This example script is used for testing the reading of a file.
|
|
3
|
+
# This example script is used for testing the reading of a file with SMBv3 encryption.
|
|
4
4
|
# It will attempt to connect to a specific share and then read a specified file.
|
|
5
|
-
# Example usage: ruby
|
|
5
|
+
# Example usage: ruby read_file_encryption.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE short.txt
|
|
6
6
|
# This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
|
|
7
7
|
# and read the file short.txt
|
|
8
8
|
|
|
9
|
-
require 'bundler/setup'
|
|
10
|
-
require 'ruby_smb'
|
|
11
|
-
|
|
12
|
-
address = ARGV[0]
|
|
13
|
-
username = ARGV[1]
|
|
14
|
-
password = ARGV[2]
|
|
15
|
-
share = ARGV[3]
|
|
16
|
-
filename = ARGV[4]
|
|
17
|
-
path = "\\\\#{address}\\#{share}"
|
|
18
|
-
|
|
19
|
-
sock = TCPSocket.new address, 445
|
|
20
|
-
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
21
|
-
|
|
22
9
|
# To require encryption on the server, run this in an elevated Powershell:
|
|
23
10
|
# C:\> Set-SmbServerConfiguration -EncryptData $true
|
|
24
11
|
|
|
@@ -26,20 +13,78 @@ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
|
26
13
|
# C:\ Set-SmbServerConfiguration -EncryptData $false
|
|
27
14
|
# C:\ Set-SmbShare -Name <share name> -EncryptData 1
|
|
28
15
|
|
|
29
|
-
# For this encryption to work, it has to be SMBv3. By
|
|
30
|
-
#
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
16
|
+
# For this encryption to work, it has to be SMBv3. By default, SMBv1 and SMBv2
|
|
17
|
+
# are disabled here so the server will negotiate SMBv3 if it supports it.
|
|
18
|
+
|
|
19
|
+
require 'bundler/setup'
|
|
20
|
+
require 'optparse'
|
|
21
|
+
require 'ruby_smb'
|
|
22
|
+
|
|
23
|
+
args = ARGV.dup
|
|
24
|
+
options = {
|
|
25
|
+
domain: '.',
|
|
26
|
+
username: '',
|
|
27
|
+
password: '',
|
|
28
|
+
smbv1: false,
|
|
29
|
+
smbv2: false,
|
|
30
|
+
smbv3: true,
|
|
31
|
+
target: nil,
|
|
32
|
+
share: nil,
|
|
33
|
+
file: nil
|
|
37
34
|
}
|
|
35
|
+
options[:file] = args.pop
|
|
36
|
+
options[:share] = args.pop
|
|
37
|
+
options[:target] = args.pop
|
|
38
|
+
optparser = OptionParser.new do |opts|
|
|
39
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file"
|
|
40
|
+
opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
|
|
41
|
+
options[:smbv1] = smbv1
|
|
42
|
+
end
|
|
43
|
+
opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
|
|
44
|
+
options[:smbv2] = smbv2
|
|
45
|
+
end
|
|
46
|
+
opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
|
|
47
|
+
options[:smbv3] = smbv3
|
|
48
|
+
end
|
|
49
|
+
opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
|
|
50
|
+
if username.include?('\\')
|
|
51
|
+
options[:domain], options[:username] = username.split('\\', 2)
|
|
52
|
+
else
|
|
53
|
+
options[:username] = username
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
|
|
57
|
+
options[:password] = password
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
optparser.parse!(args)
|
|
61
|
+
|
|
62
|
+
if [options[:target], options[:share], options[:file]].any? { |a| a == '-h' || a == '--help' }
|
|
63
|
+
puts optparser.help
|
|
64
|
+
exit
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if options[:target].nil? || options[:share].nil? || options[:file].nil?
|
|
68
|
+
abort(optparser.help)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
path = "\\\\#{options[:target]}\\#{options[:share]}"
|
|
72
|
+
|
|
73
|
+
sock = TCPSocket.new options[:target], 445
|
|
74
|
+
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
38
75
|
|
|
39
76
|
# By default, the client uses encryption even if it is not required by the server. Disable this by setting always_encrypt to false
|
|
40
|
-
|
|
77
|
+
client_opts = {
|
|
78
|
+
smb1: options[:smbv1],
|
|
79
|
+
smb2: options[:smbv2],
|
|
80
|
+
smb3: options[:smbv3],
|
|
81
|
+
username: options[:username],
|
|
82
|
+
password: options[:password],
|
|
83
|
+
domain: options[:domain]
|
|
84
|
+
}
|
|
85
|
+
#client_opts[:always_encrypt] = false
|
|
41
86
|
|
|
42
|
-
client = RubySMB::Client.new(dispatcher,
|
|
87
|
+
client = RubySMB::Client.new(dispatcher, **client_opts)
|
|
43
88
|
protocol = client.negotiate
|
|
44
89
|
status = client.authenticate
|
|
45
90
|
|
|
@@ -49,7 +94,7 @@ rescue StandardError => e
|
|
|
49
94
|
puts "Failed to connect to #{path}: #{e.message}"
|
|
50
95
|
end
|
|
51
96
|
|
|
52
|
-
file = tree.open_file(filename:
|
|
97
|
+
file = tree.open_file(filename: options[:file])
|
|
53
98
|
|
|
54
99
|
data = file.read
|
|
55
100
|
puts data
|
|
@@ -2,23 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
# This example script is used for testing the Winreg registry key value read functionality.
|
|
4
4
|
# It will attempt to connect to a host and reads the value of a specified registry key.
|
|
5
|
-
# Example usage: ruby
|
|
5
|
+
# Example usage: ruby read_registry_key_value.rb --username msfadmin --password msfadmin 192.168.172.138 HKLM\\My\\Key ValueName
|
|
6
6
|
# 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.
|
|
7
7
|
|
|
8
8
|
require 'bundler/setup'
|
|
9
|
+
require 'optparse'
|
|
9
10
|
require 'ruby_smb'
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
args = ARGV.dup
|
|
13
|
+
options = {
|
|
14
|
+
domain: '.',
|
|
15
|
+
username: '',
|
|
16
|
+
password: '',
|
|
17
|
+
smbv1: true,
|
|
18
|
+
smbv2: true,
|
|
19
|
+
smbv3: true,
|
|
20
|
+
target: nil,
|
|
21
|
+
registry_key: nil,
|
|
22
|
+
value_name: nil
|
|
23
|
+
}
|
|
24
|
+
options[:value_name] = args.pop
|
|
25
|
+
options[:registry_key] = args.pop
|
|
26
|
+
options[:target] = args.pop
|
|
27
|
+
optparser = OptionParser.new do |opts|
|
|
28
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] target registry_key value_name"
|
|
29
|
+
opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
|
|
30
|
+
options[:smbv1] = smbv1
|
|
31
|
+
end
|
|
32
|
+
opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
|
|
33
|
+
options[:smbv2] = smbv2
|
|
34
|
+
end
|
|
35
|
+
opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
|
|
36
|
+
options[:smbv3] = smbv3
|
|
37
|
+
end
|
|
38
|
+
opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
|
|
39
|
+
if username.include?('\\')
|
|
40
|
+
options[:domain], options[:username] = username.split('\\', 2)
|
|
41
|
+
else
|
|
42
|
+
options[:username] = username
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
|
|
46
|
+
options[:password] = password
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
optparser.parse!(args)
|
|
50
|
+
|
|
51
|
+
if [options[:target], options[:registry_key], options[:value_name]].any? { |a| a == '-h' || a == '--help' }
|
|
52
|
+
puts optparser.help
|
|
53
|
+
exit
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
if options[:target].nil? || options[:registry_key].nil? || options[:value_name].nil?
|
|
57
|
+
abort(optparser.help)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
address = options[:target]
|
|
61
|
+
registry_key = options[:registry_key]
|
|
62
|
+
value_name = options[:value_name]
|
|
17
63
|
|
|
18
64
|
sock = TCPSocket.new address, 445
|
|
19
65
|
dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60)
|
|
20
66
|
|
|
21
|
-
client = RubySMB::Client.new(dispatcher, smb1:
|
|
67
|
+
client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
|
|
22
68
|
protocol = client.negotiate
|
|
23
69
|
status = client.authenticate
|
|
24
70
|
|
|
@@ -30,4 +76,3 @@ key_value = client.read_registry_key_value(address, registry_key, value_name)
|
|
|
30
76
|
puts key_value
|
|
31
77
|
|
|
32
78
|
client.disconnect!
|
|
33
|
-
|
data/examples/rename_file.rb
CHANGED
|
@@ -1,28 +1,71 @@
|
|
|
1
1
|
#!/usr/bin/ruby
|
|
2
2
|
|
|
3
|
-
# This example script is used for testing the
|
|
3
|
+
# This example script is used for testing the renaming of a file.
|
|
4
4
|
# It will attempt to connect to a specific share and then rename a specified file.
|
|
5
|
-
# Example usage: ruby rename_file.rb 192.168.172.138
|
|
5
|
+
# Example usage: ruby rename_file.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE short.txt shortrenamed.txt
|
|
6
6
|
# This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
|
|
7
|
-
# and rename the file short.txt
|
|
7
|
+
# and rename the file short.txt to shortrenamed.txt
|
|
8
8
|
|
|
9
9
|
require 'bundler/setup'
|
|
10
|
+
require 'optparse'
|
|
10
11
|
require 'ruby_smb'
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
args = ARGV.dup
|
|
14
|
+
options = {
|
|
15
|
+
domain: '.',
|
|
16
|
+
username: '',
|
|
17
|
+
password: '',
|
|
18
|
+
smbv1: true,
|
|
19
|
+
smbv2: true,
|
|
20
|
+
smbv3: true,
|
|
21
|
+
target: nil,
|
|
22
|
+
share: nil,
|
|
23
|
+
file: nil,
|
|
24
|
+
new_name: nil
|
|
25
|
+
}
|
|
26
|
+
options[:new_name] = args.pop
|
|
27
|
+
options[:file] = args.pop
|
|
28
|
+
options[:share] = args.pop
|
|
29
|
+
options[:target] = args.pop
|
|
30
|
+
optparser = OptionParser.new do |opts|
|
|
31
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file new_name"
|
|
32
|
+
opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
|
|
33
|
+
options[:smbv1] = smbv1
|
|
34
|
+
end
|
|
35
|
+
opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
|
|
36
|
+
options[:smbv2] = smbv2
|
|
37
|
+
end
|
|
38
|
+
opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
|
|
39
|
+
options[:smbv3] = smbv3
|
|
40
|
+
end
|
|
41
|
+
opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
|
|
42
|
+
if username.include?('\\')
|
|
43
|
+
options[:domain], options[:username] = username.split('\\', 2)
|
|
44
|
+
else
|
|
45
|
+
options[:username] = username
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
|
|
49
|
+
options[:password] = password
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
optparser.parse!(args)
|
|
53
|
+
|
|
54
|
+
if [options[:target], options[:share], options[:file], options[:new_name]].any? { |a| a == '-h' || a == '--help' }
|
|
55
|
+
puts optparser.help
|
|
56
|
+
exit
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if options[:target].nil? || options[:share].nil? || options[:file].nil? || options[:new_name].nil?
|
|
60
|
+
abort(optparser.help)
|
|
61
|
+
end
|
|
19
62
|
|
|
20
|
-
path
|
|
63
|
+
path = "\\\\#{options[:target]}\\#{options[:share]}"
|
|
21
64
|
|
|
22
|
-
sock = TCPSocket.new
|
|
65
|
+
sock = TCPSocket.new options[:target], 445
|
|
23
66
|
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
24
67
|
|
|
25
|
-
client = RubySMB::Client.new(dispatcher, smb1:
|
|
68
|
+
client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
|
|
26
69
|
|
|
27
70
|
protocol = client.negotiate
|
|
28
71
|
status = client.authenticate
|
|
@@ -36,8 +79,8 @@ rescue StandardError => e
|
|
|
36
79
|
puts "Failed to connect to #{path}: #{e.message}"
|
|
37
80
|
end
|
|
38
81
|
|
|
39
|
-
file = tree.open_file(filename: file, write: true, delete: true)
|
|
82
|
+
file = tree.open_file(filename: options[:file], write: true, delete: true)
|
|
40
83
|
|
|
41
|
-
data = file.rename(new_name)
|
|
84
|
+
data = file.rename(options[:new_name])
|
|
42
85
|
puts data
|
|
43
86
|
file.close
|
data/examples/write_file.rb
CHANGED
|
@@ -2,27 +2,70 @@
|
|
|
2
2
|
|
|
3
3
|
# This example script is used for testing the writing to a file.
|
|
4
4
|
# It will attempt to connect to a specific share and then write to a specified file.
|
|
5
|
-
# Example usage: ruby write_file.rb 192.168.172.138
|
|
5
|
+
# Example usage: ruby write_file.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE test.txt "data to write"
|
|
6
6
|
# This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
|
|
7
|
-
# and write "data to write" the file test.txt
|
|
7
|
+
# and write "data to write" to the file test.txt
|
|
8
8
|
|
|
9
9
|
require 'bundler/setup'
|
|
10
|
+
require 'optparse'
|
|
10
11
|
require 'ruby_smb'
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
args = ARGV.dup
|
|
14
|
+
options = {
|
|
15
|
+
domain: '.',
|
|
16
|
+
username: '',
|
|
17
|
+
password: '',
|
|
18
|
+
smbv1: true,
|
|
19
|
+
smbv2: true,
|
|
20
|
+
smbv3: true,
|
|
21
|
+
target: nil,
|
|
22
|
+
share: nil,
|
|
23
|
+
file: nil,
|
|
24
|
+
data: nil
|
|
25
|
+
}
|
|
26
|
+
options[:data] = args.pop
|
|
27
|
+
options[:file] = args.pop
|
|
28
|
+
options[:share] = args.pop
|
|
29
|
+
options[:target] = args.pop
|
|
30
|
+
optparser = OptionParser.new do |opts|
|
|
31
|
+
opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file data"
|
|
32
|
+
opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
|
|
33
|
+
options[:smbv1] = smbv1
|
|
34
|
+
end
|
|
35
|
+
opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
|
|
36
|
+
options[:smbv2] = smbv2
|
|
37
|
+
end
|
|
38
|
+
opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
|
|
39
|
+
options[:smbv3] = smbv3
|
|
40
|
+
end
|
|
41
|
+
opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
|
|
42
|
+
if username.include?('\\')
|
|
43
|
+
options[:domain], options[:username] = username.split('\\', 2)
|
|
44
|
+
else
|
|
45
|
+
options[:username] = username
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
|
|
49
|
+
options[:password] = password
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
optparser.parse!(args)
|
|
53
|
+
|
|
54
|
+
if [options[:target], options[:share], options[:file], options[:data]].any? { |a| a == '-h' || a == '--help' }
|
|
55
|
+
puts optparser.help
|
|
56
|
+
exit
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if options[:target].nil? || options[:share].nil? || options[:file].nil? || options[:data].nil?
|
|
60
|
+
abort(optparser.help)
|
|
61
|
+
end
|
|
19
62
|
|
|
20
|
-
path
|
|
63
|
+
path = "\\\\#{options[:target]}\\#{options[:share]}"
|
|
21
64
|
|
|
22
|
-
sock = TCPSocket.new
|
|
65
|
+
sock = TCPSocket.new options[:target], 445
|
|
23
66
|
dispatcher = RubySMB::Dispatcher::Socket.new(sock)
|
|
24
67
|
|
|
25
|
-
client = RubySMB::Client.new(dispatcher, smb1:
|
|
68
|
+
client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
|
|
26
69
|
protocol = client.negotiate
|
|
27
70
|
status = client.authenticate
|
|
28
71
|
|
|
@@ -32,11 +75,11 @@ begin
|
|
|
32
75
|
tree = client.tree_connect(path)
|
|
33
76
|
puts "Connected to #{path} successfully!"
|
|
34
77
|
rescue StandardError => e
|
|
35
|
-
|
|
78
|
+
abort("Failed to connect to #{path}: #{e.message}")
|
|
36
79
|
end
|
|
37
80
|
|
|
38
|
-
file = tree.open_file(filename: file, write: true, disposition: RubySMB::Dispositions::FILE_OVERWRITE_IF)
|
|
81
|
+
file = tree.open_file(filename: options[:file], write: true, disposition: RubySMB::Dispositions::FILE_OVERWRITE_IF)
|
|
39
82
|
|
|
40
|
-
result = file.write(data: data)
|
|
83
|
+
result = file.write(data: options[:data])
|
|
41
84
|
puts result.to_s
|
|
42
85
|
file.close
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
module Trans2
|
|
5
|
+
module QueryFsInformationLevel
|
|
6
|
+
# Response data for SMB_QUERY_CIFS_UNIX_INFO (0x0200) from the
|
|
7
|
+
# CIFS UNIX Extensions. 12 bytes: major/minor version pair plus
|
|
8
|
+
# a 64-bit capability bitfield that the client echoes back in
|
|
9
|
+
# SMB_SET_CIFS_UNIX_INFO to enable UNIX extensions for the session.
|
|
10
|
+
#
|
|
11
|
+
# Outside of MS-CIFS; wire format defined by the CIFS UNIX
|
|
12
|
+
# Extensions draft maintained by the Samba team. The parent
|
|
13
|
+
# subcommand is documented at
|
|
14
|
+
# [MS-CIFS 2.2.6.4 TRANS2_QUERY_FS_INFORMATION (0x0003)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/a96c1c03-cade-4a4a-81a9-b00674d23d93).
|
|
15
|
+
# The on-disk layout matches Samba's server-side `unix_info`
|
|
16
|
+
# struct at
|
|
17
|
+
# [source3/smbd/globals.h:419-424](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/globals.h#L419-L424),
|
|
18
|
+
# populated by `call_trans2qfsinfo` at
|
|
19
|
+
# [source3/smbd/smb1_trans2.c:1633-1703](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1633-L1703).
|
|
20
|
+
class QueryFsCifsUnixInfo < BinData::Record
|
|
21
|
+
endian :little
|
|
22
|
+
|
|
23
|
+
uint16 :major_version, label: 'Major Version'
|
|
24
|
+
uint16 :minor_version, label: 'Minor Version'
|
|
25
|
+
uint64 :capabilities, label: 'Capabilities'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -28,11 +28,15 @@ module RubySMB
|
|
|
28
28
|
# [NT LANMAN] Query file system attributes.
|
|
29
29
|
SMB_QUERY_FS_ATTRIBUTE_INFO = 0x0105 # 261
|
|
30
30
|
|
|
31
|
+
# [CIFS UNIX Extensions] Query server UNIX extension capabilities.
|
|
32
|
+
SMB_QUERY_CIFS_UNIX_INFO = 0x0200 # 512
|
|
33
|
+
|
|
31
34
|
def self.name(value)
|
|
32
35
|
constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
require 'ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_attribute_info'
|
|
39
|
+
require 'ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_cifs_unix_info'
|
|
36
40
|
end
|
|
37
41
|
end
|
|
38
42
|
end
|
|
@@ -2,7 +2,9 @@ module RubySMB
|
|
|
2
2
|
module SMB1
|
|
3
3
|
module Packet
|
|
4
4
|
module Trans2
|
|
5
|
-
# The Trans2 Parameter Block for
|
|
5
|
+
# The Trans2 Parameter Block for a QUERY_FS_INFORMATION request as
|
|
6
|
+
# defined in
|
|
7
|
+
# [MS-CIFS 2.2.6.4.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cfa23a11-0e80-43bd-bbd4-e9cfb99b5dce).
|
|
6
8
|
class QueryFsInformationRequestTrans2Parameters < BinData::Record
|
|
7
9
|
endian :little
|
|
8
10
|
|
|
@@ -15,16 +17,22 @@ module RubySMB
|
|
|
15
17
|
end
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
# The {RubySMB::SMB1::DataBlock} specific to this packet type.
|
|
20
|
+
# The {RubySMB::SMB1::DataBlock} specific to this packet type. See
|
|
21
|
+
# [MS-CIFS 2.2.6.4.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cfa23a11-0e80-43bd-bbd4-e9cfb99b5dce).
|
|
22
|
+
# The request carries no Trans2 data payload, but the generic
|
|
23
|
+
# DataBlock padding helpers require a :trans2_data accessor, so
|
|
24
|
+
# we expose a zero-length string.
|
|
19
25
|
class QueryFsInformationRequestDataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
|
|
20
26
|
uint8 :name, label: 'Name', initial_value: 0x00
|
|
21
27
|
string :pad1, length: -> { pad1_length }
|
|
22
28
|
query_fs_information_request_trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
|
|
23
|
-
|
|
29
|
+
string :trans2_data, length: 0, label: 'Trans2 Data'
|
|
24
30
|
end
|
|
25
31
|
|
|
26
32
|
# A Trans2 QUERY_FS_INFORMATION Request Packet as defined in
|
|
27
|
-
# [2.2.6.4.1](https://
|
|
33
|
+
# [MS-CIFS 2.2.6.4.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cfa23a11-0e80-43bd-bbd4-e9cfb99b5dce).
|
|
34
|
+
# See also the subcommand overview at
|
|
35
|
+
# [MS-CIFS 2.2.6.4 TRANS2_QUERY_FS_INFORMATION (0x0003)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/a96c1c03-cade-4a4a-81a9-b00674d23d93).
|
|
28
36
|
class QueryFsInformationRequest < RubySMB::GenericPacket
|
|
29
37
|
COMMAND = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
30
38
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
module Trans2
|
|
5
|
+
# SET_FS Information Levels used in TRANS2_SET_FS_INFORMATION.
|
|
6
|
+
#
|
|
7
|
+
# MS-CIFS marks the parent subcommand
|
|
8
|
+
# [TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
|
|
9
|
+
# as "reserved but not implemented" — the info level codes below are
|
|
10
|
+
# defined by the CIFS UNIX Extensions draft maintained by the Samba
|
|
11
|
+
# team and implemented in
|
|
12
|
+
# [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
|
|
13
|
+
# They sit in the 0x0200–0x02FF range reserved by
|
|
14
|
+
# [MS-CIFS 2.2.2.3 Information Level Codes](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/03c10ab9-d723-4368-b9a6-c72de3244c77)
|
|
15
|
+
# for third-party extensions.
|
|
16
|
+
module SetFsInformationLevel
|
|
17
|
+
# Client advertises / negotiates CIFS UNIX Extensions support.
|
|
18
|
+
# Data block: major:u16, minor:u16, capabilities:u64.
|
|
19
|
+
SMB_SET_CIFS_UNIX_INFO = 0x0200
|
|
20
|
+
|
|
21
|
+
def self.name(value)
|
|
22
|
+
constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
module Trans2
|
|
5
|
+
# The Trans2 Parameter Block for TRANS2_SET_FS_INFORMATION.
|
|
6
|
+
# Observed on the wire (and required by Samba) as a 4-byte block
|
|
7
|
+
# containing a placeholder file handle plus the information level.
|
|
8
|
+
#
|
|
9
|
+
# The parent subcommand
|
|
10
|
+
# [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
|
|
11
|
+
# is marked "reserved but not implemented"; the on-the-wire format
|
|
12
|
+
# used here is defined by the CIFS UNIX Extensions draft and
|
|
13
|
+
# implemented in
|
|
14
|
+
# [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
|
|
15
|
+
class SetFsInformationRequestTrans2Parameters < BinData::Record
|
|
16
|
+
endian :little
|
|
17
|
+
|
|
18
|
+
uint16 :fid, label: 'File ID'
|
|
19
|
+
uint16 :information_level, label: 'Information Level'
|
|
20
|
+
|
|
21
|
+
# Returns the length of the Trans2Parameters struct
|
|
22
|
+
# in number of bytes
|
|
23
|
+
def length
|
|
24
|
+
do_num_bytes
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The Trans2 Data Block for TRANS2_SET_FS_INFORMATION.
|
|
29
|
+
#
|
|
30
|
+
# The data layout depends on the Information Level being set, so the
|
|
31
|
+
# block carries an opaque byte buffer that the caller fills in for
|
|
32
|
+
# the target info level. SMB_SET_CIFS_UNIX_INFO (0x0200) for example
|
|
33
|
+
# carries a QueryFsCifsUnixInfo-shaped record (major/minor/caps).
|
|
34
|
+
#
|
|
35
|
+
# Not documented in
|
|
36
|
+
# [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3);
|
|
37
|
+
# per-level layouts are defined by the CIFS UNIX Extensions draft
|
|
38
|
+
# and implemented in
|
|
39
|
+
# [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
|
|
40
|
+
class SetFsInformationRequestTrans2Data < BinData::Record
|
|
41
|
+
string :buffer, read_length: -> { parent.buffer_read_length }
|
|
42
|
+
|
|
43
|
+
# Returns the length of the Trans2Data struct
|
|
44
|
+
# in number of bytes
|
|
45
|
+
def length
|
|
46
|
+
do_num_bytes
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# The {RubySMB::SMB1::DataBlock} specific to this packet type. The
|
|
51
|
+
# parent subcommand
|
|
52
|
+
# [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
|
|
53
|
+
# is documented as "reserved but not implemented"; this data block
|
|
54
|
+
# is structured for the CIFS UNIX Extensions use in
|
|
55
|
+
# [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
|
|
56
|
+
class SetFsInformationRequestDataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
|
|
57
|
+
uint8 :name, label: 'Name', initial_value: 0x00
|
|
58
|
+
string :pad1, length: -> { pad1_length }
|
|
59
|
+
set_fs_information_request_trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
|
|
60
|
+
string :pad2, length: -> { pad2_length }
|
|
61
|
+
set_fs_information_request_trans2_data :trans2_data, label: 'Trans2 Data'
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# A Trans2 SET_FS_INFORMATION Request Packet. The on-disk layout
|
|
65
|
+
# described by
|
|
66
|
+
# [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
|
|
67
|
+
# is marked "reserved but not implemented" and does not document the
|
|
68
|
+
# CIFS UNIX Extensions info levels; their wire format is defined by
|
|
69
|
+
# the CIFS UNIX Extensions draft and matched by Samba's
|
|
70
|
+
# `call_trans2setfsinfo` in
|
|
71
|
+
# [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
|
|
72
|
+
class SetFsInformationRequest < RubySMB::GenericPacket
|
|
73
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
74
|
+
|
|
75
|
+
class ParameterBlock < RubySMB::SMB1::Packet::Trans2::Request::ParameterBlock
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
smb_header :smb_header
|
|
79
|
+
parameter_block :parameter_block
|
|
80
|
+
set_fs_information_request_data_block :data_block
|
|
81
|
+
|
|
82
|
+
def initialize_instance
|
|
83
|
+
super
|
|
84
|
+
parameter_block.setup << RubySMB::SMB1::Packet::Trans2::Subcommands::SET_FS_INFORMATION
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module SMB1
|
|
3
|
+
module Packet
|
|
4
|
+
module Trans2
|
|
5
|
+
# The Trans2 Parameter Block for a TRANS2_SET_FS_INFORMATION response.
|
|
6
|
+
# The field is intentionally empty — servers return only an NT status
|
|
7
|
+
# in the SMB header to acknowledge the SET.
|
|
8
|
+
#
|
|
9
|
+
# Parent subcommand:
|
|
10
|
+
# [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
|
|
11
|
+
# ("reserved but not implemented"). Response shape observed in the
|
|
12
|
+
# CIFS UNIX Extensions implementation in
|
|
13
|
+
# [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
|
|
14
|
+
class SetFsInformationResponseTrans2Parameters < BinData::Record
|
|
15
|
+
def length
|
|
16
|
+
do_num_bytes
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# The {RubySMB::SMB1::DataBlock} specific to this packet type.
|
|
21
|
+
# Parent subcommand:
|
|
22
|
+
# [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
|
|
23
|
+
# ("reserved but not implemented"); actual shape used by the CIFS
|
|
24
|
+
# UNIX Extensions implementation in
|
|
25
|
+
# [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
|
|
26
|
+
class SetFsInformationResponseDataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
|
|
27
|
+
uint8 :name, label: 'Name', initial_value: 0x00
|
|
28
|
+
string :pad1, length: -> { pad1_length }
|
|
29
|
+
set_fs_information_response_trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# A Trans2 SET_FS_INFORMATION Response Packet. Parent subcommand:
|
|
33
|
+
# [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
|
|
34
|
+
# ("reserved but not implemented"). Response shape is defined by the
|
|
35
|
+
# CIFS UNIX Extensions implementation in
|
|
36
|
+
# [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
|
|
37
|
+
class SetFsInformationResponse < RubySMB::GenericPacket
|
|
38
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
|
|
39
|
+
|
|
40
|
+
class ParameterBlock < RubySMB::SMB1::Packet::Trans2::Response::ParameterBlock
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
smb_header :smb_header
|
|
44
|
+
parameter_block :parameter_block
|
|
45
|
+
set_fs_information_response_data_block :data_block
|
|
46
|
+
|
|
47
|
+
def initialize_instance
|
|
48
|
+
super
|
|
49
|
+
parameter_block.setup << RubySMB::SMB1::Packet::Trans2::Subcommands::SET_FS_INFORMATION
|
|
50
|
+
smb_header.flags.reply = 1
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|