ruby_smb 3.1.2 → 3.1.5
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
- checksums.yaml.gz.sig +0 -0
- data/examples/file_server.rb +6 -68
- data/examples/virtual_file_server.rb +10 -62
- data/lib/ruby_smb/client/authentication.rb +29 -4
- data/lib/ruby_smb/client/negotiation.rb +2 -0
- data/lib/ruby_smb/client.rb +18 -3
- data/lib/ruby_smb/dcerpc/error.rb +13 -0
- data/lib/ruby_smb/dcerpc/fault.rb +83 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +19 -8
- data/lib/ruby_smb/dcerpc/request.rb +15 -10
- data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +5 -0
- data/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response.rb +24 -0
- data/lib/ruby_smb/dcerpc/samr/samr_delete_user_request.rb +21 -0
- data/lib/ruby_smb/dcerpc/samr/samr_delete_user_response.rb +22 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb +0 -31
- data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb +1 -14
- data/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response.rb +21 -0
- data/lib/ruby_smb/dcerpc/samr.rb +453 -83
- data/lib/ruby_smb/dcerpc.rb +1 -0
- data/lib/ruby_smb/error.rb +4 -0
- data/lib/ruby_smb/gss.rb +1 -0
- data/lib/ruby_smb/ntlm/client.rb +74 -0
- data/lib/ruby_smb/ntlm.rb +1 -0
- data/lib/ruby_smb/server/cli.rb +121 -0
- data/lib/ruby_smb/server.rb +1 -0
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +11 -0
- data/lib/ruby_smb/smb1/pipe.rb +4 -1
- data/lib/ruby_smb/smb2/pipe.rb +4 -2
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +1 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_request_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_create_user2_in_domain_response_spec.rb +69 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_delete_user_request_spec.rb +42 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_delete_user_response_spec.rb +51 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_request_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_domains_in_sam_server_response_spec.rb +75 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response_spec.rb +0 -195
- data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_request_spec.rb +62 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_names_in_domain_response_spec.rb +54 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_request_spec.rb +67 -0
- data/spec/lib/ruby_smb/dcerpc/samr/samr_set_information_user2_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/samr_spec.rb +194 -0
- data/spec/lib/ruby_smb/ntlm/client/session_spec.rb +114 -0
- data/spec/lib/ruby_smb/ntlm/client_spec.rb +36 -0
- data.tar.gz.sig +0 -0
- metadata +39 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4749ae5185070d44e447593cd863ee5ac17a87468b16b14a251f68e0166b7663
|
4
|
+
data.tar.gz: b63378e4367136e0c6dffc35aa02b5c5ce1df450d5b64300eaee060e7938e9ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f09557d4ba6148796bb6adf2c1169ebad237f021527975fabb179e1eb2099cfb2c17e45d3b57629c7fc61106092317076e41c77d39f8cb3d4335d280a75e144c
|
7
|
+
data.tar.gz: e969cc9f474e64e4cf7ba9bcf39e1dfc30b9e365bf6c758abd1e7ff905a6e9a3a8f3c3b33fc88f3104b7998201406d8b78bca34e746c58cfa4c03353bd94f789
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/examples/file_server.rb
CHANGED
@@ -3,81 +3,19 @@
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'optparse'
|
5
5
|
require 'ruby_smb'
|
6
|
-
require 'ruby_smb/gss/provider/ntlm'
|
7
6
|
|
8
7
|
# we just need *a* default encoding to handle the strings from the NTLM messages
|
9
8
|
Encoding.default_internal = 'UTF-8' if Encoding.default_internal.nil?
|
10
9
|
|
11
|
-
options = {
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
username: 'RubySMB',
|
16
|
-
password: 'password',
|
17
|
-
share_name: 'home',
|
18
|
-
share_path: '.',
|
19
|
-
smbv1: true,
|
20
|
-
smbv2: true,
|
21
|
-
smbv3: true
|
22
|
-
}
|
23
|
-
OptionParser.new do |opts|
|
24
|
-
opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
|
25
|
-
opts.on("--path PATH", "The path to share (default: #{options[:share_path]})") do |path|
|
10
|
+
options = RubySMB::Server::Cli.parse(defaults: { share_path: '.' }) do |options, parser|
|
11
|
+
parser.banner = "Usage: #{File.basename(__FILE__)} [options]"
|
12
|
+
|
13
|
+
parser.on("--share-path SHARE_PATH", "The path to share (default: #{options[:share_path]})") do |path|
|
26
14
|
options[:share_path] = path
|
27
15
|
end
|
28
|
-
opts.on("--share SHARE", "The share name (default: #{options[:share_name]})") do |share|
|
29
|
-
options[:share_name] = share
|
30
|
-
end
|
31
|
-
opts.on("--[no-]anonymous", "Allow anonymous access (default: #{options[:allow_anonymous]})") do |allow_anonymous|
|
32
|
-
options[:allow_anonymous] = allow_anonymous
|
33
|
-
end
|
34
|
-
opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
|
35
|
-
options[:smbv1] = smbv1
|
36
|
-
end
|
37
|
-
opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
|
38
|
-
options[:smbv2] = smbv2
|
39
|
-
end
|
40
|
-
opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
|
41
|
-
options[:smbv3] = smbv3
|
42
|
-
end
|
43
|
-
opts.on("--[no-]guests", "Allow guest accounts (default: #{options[:allow_guests]})") do |allow_guests|
|
44
|
-
options[:allow_guests] = allow_guests
|
45
|
-
end
|
46
|
-
opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
|
47
|
-
if username.include?('\\')
|
48
|
-
options[:domain], options[:username] = username.split('\\', 2)
|
49
|
-
else
|
50
|
-
options[:username] = username
|
51
|
-
end
|
52
|
-
end
|
53
|
-
opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
|
54
|
-
options[:password] = password
|
55
|
-
end
|
56
|
-
end.parse!
|
57
|
-
|
58
|
-
ntlm_provider = RubySMB::Gss::Provider::NTLM.new(
|
59
|
-
allow_anonymous: options[:allow_anonymous],
|
60
|
-
allow_guests: options[:allow_guests]
|
61
|
-
)
|
62
|
-
ntlm_provider.put_account(options[:username], options[:password], domain: options[:domain]) # password can also be an NTLM hash
|
63
|
-
|
64
|
-
server = RubySMB::Server.new(
|
65
|
-
gss_provider: ntlm_provider,
|
66
|
-
logger: :stdout
|
67
|
-
)
|
68
|
-
server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB1 } unless options[:smbv1]
|
69
|
-
server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB2 } unless options[:smbv2]
|
70
|
-
server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB3 } unless options[:smbv3]
|
71
|
-
|
72
|
-
if server.dialects.empty?
|
73
|
-
puts "at least one version must be enabled"
|
74
|
-
exit false
|
75
16
|
end
|
76
17
|
|
18
|
+
server = RubySMB::Server::Cli.build(options)
|
77
19
|
server.add_share(RubySMB::Server::Share::Provider::Disk.new(options[:share_name], options[:share_path]))
|
78
|
-
puts "server is running"
|
79
|
-
server.run do
|
80
|
-
puts "received connection"
|
81
|
-
true
|
82
|
-
end
|
83
20
|
|
21
|
+
RubySMB::Server::Cli.run(server)
|
@@ -3,7 +3,6 @@
|
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'optparse'
|
5
5
|
require 'ruby_smb'
|
6
|
-
require 'ruby_smb/gss/provider/ntlm'
|
7
6
|
|
8
7
|
# we just need *a* default encoding to handle the strings from the NTLM messages
|
9
8
|
Encoding.default_internal = 'UTF-8' if Encoding.default_internal.nil?
|
@@ -32,70 +31,23 @@ MAGIC_8_BALL_ANSWERS = [
|
|
32
31
|
'Very doubtful'
|
33
32
|
]
|
34
33
|
|
35
|
-
options =
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
password: 'password',
|
40
|
-
share_name: 'home',
|
41
|
-
smbv1: true,
|
42
|
-
smbv2: true,
|
43
|
-
smbv3: true
|
44
|
-
}
|
45
|
-
OptionParser.new do |opts|
|
46
|
-
opts.banner = "Usage: #{File.basename(__FILE__)} [options]"
|
47
|
-
opts.on("--share SHARE", "The share name (default: #{options[:share_name]})") do |share|
|
48
|
-
options[:share_name] = share
|
49
|
-
end
|
50
|
-
opts.on("--[no-]anonymous", "Allow anonymous access (default: #{options[:allow_anonymous]})") do |allow_anonymous|
|
51
|
-
options[:allow_anonymous] = allow_anonymous
|
52
|
-
end
|
53
|
-
opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
|
54
|
-
options[:smbv1] = smbv1
|
55
|
-
end
|
56
|
-
opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
|
57
|
-
options[:smbv2] = smbv2
|
58
|
-
end
|
59
|
-
opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
|
60
|
-
options[:smbv3] = smbv3
|
61
|
-
end
|
62
|
-
opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
|
63
|
-
if username.include?('\\')
|
64
|
-
options[:domain], options[:username] = username.split('\\', 2)
|
65
|
-
else
|
66
|
-
options[:username] = username
|
67
|
-
end
|
68
|
-
end
|
69
|
-
opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
|
70
|
-
options[:password] = password
|
71
|
-
end
|
72
|
-
opts.on("--virtual-content CONTENT", "The virtual share contents") do |virtual_content|
|
34
|
+
options = RubySMB::Server::Cli.parse do |options, parser|
|
35
|
+
parser.banner = "Usage: #{File.basename(__FILE__)} [options]"
|
36
|
+
|
37
|
+
parser.on("--virtual-content CONTENT", "The virtual share contents") do |virtual_content|
|
73
38
|
options[:virtual_content] = virtual_content
|
74
39
|
end
|
75
|
-
|
40
|
+
|
41
|
+
parser.on("--virtual-name NAME", "The virtual share file name") do |virtual_name|
|
76
42
|
options[:virtual_name] = virtual_name
|
77
43
|
end
|
78
|
-
|
44
|
+
|
45
|
+
parser.on("--virtual-type TYPE", "The virtual share type") do |virtual_type|
|
79
46
|
options[:virtual_type] = virtual_type
|
80
47
|
end
|
81
|
-
end.parse!
|
82
|
-
|
83
|
-
ntlm_provider = RubySMB::Gss::Provider::NTLM.new(allow_anonymous: options[:allow_anonymous])
|
84
|
-
ntlm_provider.put_account(options[:username], options[:password], domain: options[:domain]) # password can also be an NTLM hash
|
85
|
-
|
86
|
-
server = RubySMB::Server.new(
|
87
|
-
gss_provider: ntlm_provider,
|
88
|
-
logger: :stdout
|
89
|
-
)
|
90
|
-
server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB1 } unless options[:smbv1]
|
91
|
-
server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB2 } unless options[:smbv2]
|
92
|
-
server.dialects.select! { |dialect| RubySMB::Dialect[dialect].family != RubySMB::Dialect::FAMILY_SMB3 } unless options[:smbv3]
|
93
|
-
|
94
|
-
if server.dialects.empty?
|
95
|
-
puts "at least one version must be enabled"
|
96
|
-
exit false
|
97
48
|
end
|
98
49
|
|
50
|
+
server = RubySMB::Server::Cli.build(options)
|
99
51
|
virtual_disk = RubySMB::Server::Share::Provider::VirtualDisk.new(options[:share_name])
|
100
52
|
|
101
53
|
# greeting is a static text file
|
@@ -135,9 +87,5 @@ elsif options[:virtual_content] || options[:virtual_name] || options[:virtual_ty
|
|
135
87
|
end
|
136
88
|
|
137
89
|
server.add_share(virtual_disk)
|
138
|
-
puts "server is running"
|
139
|
-
server.run do |server_client|
|
140
|
-
puts "received connection"
|
141
|
-
true
|
142
|
-
end
|
143
90
|
|
91
|
+
RubySMB::Server::Cli.run(server)
|
@@ -80,7 +80,7 @@ module RubySMB
|
|
80
80
|
type2_b64_message = smb1_type2_message(challenge_packet)
|
81
81
|
type3_message = @ntlm_client.init_context(type2_b64_message)
|
82
82
|
|
83
|
-
@session_key = @ntlm_client.session_key
|
83
|
+
@application_key = @session_key = @ntlm_client.session_key
|
84
84
|
challenge_message = @ntlm_client.session.challenge_message
|
85
85
|
store_target_info(challenge_message.target_info) if challenge_message.has_flag?(:TARGET_INFO)
|
86
86
|
@os_version = extract_os_version(challenge_message.os_version.to_s) unless challenge_message.os_version.empty?
|
@@ -146,7 +146,7 @@ module RubySMB
|
|
146
146
|
end
|
147
147
|
|
148
148
|
# Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
|
149
|
-
def
|
149
|
+
def smb1_session_setup_response(raw_response)
|
150
150
|
packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
|
151
151
|
|
152
152
|
unless packet.valid?
|
@@ -159,6 +159,11 @@ module RubySMB
|
|
159
159
|
packet
|
160
160
|
end
|
161
161
|
|
162
|
+
# Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
|
163
|
+
def smb1_ntlmssp_final_packet(raw_response)
|
164
|
+
smb1_session_setup_response(raw_response)
|
165
|
+
end
|
166
|
+
|
162
167
|
# Takes the raw binary string and returns a {RubySMB::SMB1::Packet::SessionSetupResponse}
|
163
168
|
def smb1_ntlmssp_challenge_packet(raw_response)
|
164
169
|
packet = RubySMB::SMB1::Packet::SessionSetupResponse.read(raw_response)
|
@@ -205,7 +210,7 @@ module RubySMB
|
|
205
210
|
type2_b64_message = smb2_type2_message(challenge_packet)
|
206
211
|
type3_message = @ntlm_client.init_context(type2_b64_message)
|
207
212
|
|
208
|
-
@session_key = @ntlm_client.session_key
|
213
|
+
@application_key = @session_key = @ntlm_client.session_key
|
209
214
|
challenge_message = ntlm_client.session.challenge_message
|
210
215
|
store_target_info(challenge_message.target_info) if challenge_message.has_flag?(:TARGET_INFO)
|
211
216
|
@os_version = extract_os_version(challenge_message.os_version.to_s) unless challenge_message.os_version.empty?
|
@@ -222,6 +227,21 @@ module RubySMB
|
|
222
227
|
# disable encryption when necessary
|
223
228
|
@session_encrypt_data = false
|
224
229
|
end
|
230
|
+
|
231
|
+
# see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/7fd079ca-17e6-4f02-8449-46b606ea289c
|
232
|
+
if @dialect == '0x0300' || @dialect == '0x0302'
|
233
|
+
@application_key = RubySMB::Crypto::KDF.counter_mode(
|
234
|
+
@session_key,
|
235
|
+
"SMB2APP\x00",
|
236
|
+
"SmbRpc\x00"
|
237
|
+
)
|
238
|
+
else
|
239
|
+
@application_key = RubySMB::Crypto::KDF.counter_mode(
|
240
|
+
@session_key,
|
241
|
+
"SMBAppKey\x00",
|
242
|
+
@preauth_integrity_hash_value
|
243
|
+
)
|
244
|
+
end
|
225
245
|
# otherwise, leave encryption to the default value that it was initialized to
|
226
246
|
end
|
227
247
|
######
|
@@ -235,7 +255,7 @@ module RubySMB
|
|
235
255
|
end
|
236
256
|
|
237
257
|
# Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
238
|
-
def
|
258
|
+
def smb2_session_setup_response(raw_response)
|
239
259
|
packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)
|
240
260
|
unless packet.valid?
|
241
261
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -248,6 +268,11 @@ module RubySMB
|
|
248
268
|
packet
|
249
269
|
end
|
250
270
|
|
271
|
+
# Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
272
|
+
def smb2_ntlmssp_final_packet(raw_response)
|
273
|
+
smb2_session_setup_response(raw_response)
|
274
|
+
end
|
275
|
+
|
251
276
|
# Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
252
277
|
def smb2_ntlmssp_challenge_packet(raw_response)
|
253
278
|
packet = RubySMB::SMB2::Packet::SessionSetupResponse.read(raw_response)
|
@@ -118,6 +118,7 @@ module RubySMB
|
|
118
118
|
self.server_max_buffer_size = packet.parameter_block.max_buffer_size - 260
|
119
119
|
self.negotiated_smb_version = 1
|
120
120
|
self.session_encrypt_data = false
|
121
|
+
self.negotiation_security_buffer = packet.data_block.security_blob
|
121
122
|
'SMB1'
|
122
123
|
when RubySMB::SMB2::Packet::NegotiateResponse
|
123
124
|
self.smb1 = false
|
@@ -137,6 +138,7 @@ module RubySMB
|
|
137
138
|
self.server_start_time = packet.server_start_time.to_time if packet.server_start_time != 0
|
138
139
|
self.server_system_time = packet.system_time.to_time if packet.system_time != 0
|
139
140
|
self.server_supports_multi_credit = self.dialect != '0x0202' && packet&.capabilities&.large_mtu == 1
|
141
|
+
self.negotiation_security_buffer = packet.security_buffer
|
140
142
|
case self.dialect
|
141
143
|
when '0x02ff'
|
142
144
|
when '0x0300', '0x0302'
|
data/lib/ruby_smb/client.rb
CHANGED
@@ -54,6 +54,13 @@ module RubySMB
|
|
54
54
|
# The default maximum size of a SMB message that the Server accepts (in bytes)
|
55
55
|
SERVER_MAX_BUFFER_SIZE = 4356
|
56
56
|
|
57
|
+
# The application key. After authenticating to the remote server, this value is the session key for dialects less
|
58
|
+
# than version 3 and a unique value for v3 dialects. See:
|
59
|
+
# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/901ae284-31d3-4ea1-ae8a-766fc8bfe00e
|
60
|
+
# @!attribute [rw] application_key
|
61
|
+
# @return [String]
|
62
|
+
attr_accessor :application_key
|
63
|
+
|
57
64
|
# The dispatcher responsible for sending packets
|
58
65
|
# @!attribute [rw] dispatcher
|
59
66
|
# @return [RubySMB::Dispatcher::Socket]
|
@@ -288,13 +295,19 @@ module RubySMB
|
|
288
295
|
attr_accessor :negotiated_smb_version
|
289
296
|
|
290
297
|
# Whether or not the server supports multi-credit operations. It is
|
291
|
-
# reported by the LARGE_MTU
|
298
|
+
# reported by the LARGE_MTU capability as part of the negotiation process
|
292
299
|
# (SMB 2.x and 3.x).
|
293
300
|
# @!attribute [rw] server_supports_multi_credit
|
294
301
|
# @return [Boolean] true if the server supports multi-credit operations,
|
295
302
|
# false otherwise
|
296
303
|
attr_accessor :server_supports_multi_credit
|
297
304
|
|
305
|
+
# The negotiated security buffer. This is nil until the negotiation process
|
306
|
+
# has finished.
|
307
|
+
# @!attribute [rw] negotiation_security_buffer
|
308
|
+
# @return [String] The raw security buffer bytes
|
309
|
+
attr_accessor :negotiation_security_buffer
|
310
|
+
|
298
311
|
# @param dispatcher [RubySMB::Dispatcher::Socket] the packet dispatcher to use
|
299
312
|
# @param smb1 [Boolean] whether or not to enable SMB1 support
|
300
313
|
# @param smb2 [Boolean] whether or not to enable SMB2 support
|
@@ -313,6 +326,7 @@ module RubySMB
|
|
313
326
|
@sequence_counter = 0
|
314
327
|
@session_id = 0x00
|
315
328
|
@session_key = ''
|
329
|
+
@application_key = ''
|
316
330
|
@session_is_guest = false
|
317
331
|
@signing_required = false
|
318
332
|
@smb1 = smb1
|
@@ -332,7 +346,7 @@ module RubySMB
|
|
332
346
|
# session setup response is received
|
333
347
|
@session_encrypt_data = always_encrypt
|
334
348
|
|
335
|
-
@ntlm_client =
|
349
|
+
@ntlm_client = RubySMB::NTLM::Client.new(
|
336
350
|
@username,
|
337
351
|
@password,
|
338
352
|
workstation: @local_workstation,
|
@@ -404,7 +418,7 @@ module RubySMB
|
|
404
418
|
@password = pass.encode('utf-8') || ''.encode('utf-8')
|
405
419
|
@username = user.encode('utf-8') || ''.encode('utf-8')
|
406
420
|
|
407
|
-
@ntlm_client =
|
421
|
+
@ntlm_client = RubySMB::NTLM::Client.new(
|
408
422
|
@username,
|
409
423
|
@password,
|
410
424
|
workstation: @local_workstation,
|
@@ -617,6 +631,7 @@ module RubySMB
|
|
617
631
|
def wipe_state!
|
618
632
|
self.session_id = 0x00
|
619
633
|
self.user_id = 0x00
|
634
|
+
self.application_key = ''
|
620
635
|
self.session_key = ''
|
621
636
|
self.session_is_guest = false
|
622
637
|
self.sequence_counter = 0
|
@@ -13,6 +13,19 @@ module RubySMB
|
|
13
13
|
# Raised when an invalid packet is received
|
14
14
|
class InvalidPacket < DcerpcError; end
|
15
15
|
|
16
|
+
# Raised when a fault response is received
|
17
|
+
class FaultError < InvalidPacket
|
18
|
+
attr_reader :status_code
|
19
|
+
def initialize(message=nil, status:)
|
20
|
+
@status_code = status
|
21
|
+
super(message)
|
22
|
+
end
|
23
|
+
|
24
|
+
def status_name
|
25
|
+
RubySMB::Dcerpc::Fault::Status.name(@status_code)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
16
29
|
# Raised when an error is returned during a Winreg operation
|
17
30
|
class WinregError < DcerpcError; end
|
18
31
|
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module RubySMB::Dcerpc::Fault
|
2
|
+
module Status
|
3
|
+
# DCERPC
|
4
|
+
NCA_S_FAULT_OTHER = 0x00000001
|
5
|
+
NCA_S_FAULT_ACCESS_DENIED = 0x00000005
|
6
|
+
NCA_S_FAULT_NDR = 0x000006F7
|
7
|
+
NCA_S_FAULT_CANT_PERFORM = 0x000006D8
|
8
|
+
NCA_S_FAULT_INT_DIV_BY_ZERO = 0x1C000001
|
9
|
+
NCA_S_FAULT_ADDR_ERROR = 0x1C000002
|
10
|
+
NCA_S_FAULT_FP_DIV_ZERO = 0x1C000003
|
11
|
+
NCA_S_FAULT_FP_UNDERFLOW = 0x1C000004
|
12
|
+
NCA_S_FAULT_FP_OVERFLOW = 0x1C000005
|
13
|
+
NCA_S_FAULT_INVALID_TAG = 0x1C000006
|
14
|
+
NCA_S_FAULT_INVALID_BOUND = 0x1C000007
|
15
|
+
NCA_RPC_VERSION_MISMATCH = 0x1C000008
|
16
|
+
NCA_UNSPEC_REJECT = 0x1C000009
|
17
|
+
NCA_S_BAD_ACTID = 0x1C00000A
|
18
|
+
NCA_WHO_ARE_YOU_FAILED = 0x1C00000B
|
19
|
+
NCA_MANAGER_NOT_ENTERED = 0x1C00000C
|
20
|
+
NCA_S_FAULT_CANCEL = 0x1C00000D
|
21
|
+
NCA_S_FAULT_ILL_INST = 0x1C00000E
|
22
|
+
NCA_S_FAULT_FP_ERROR = 0x1C00000F
|
23
|
+
NCA_S_FAULT_INT_OVERFLOW = 0x1C000010
|
24
|
+
NCA_S_FAULT_PIPE_EMPTY = 0x1C000014
|
25
|
+
NCA_S_FAULT_PIPE_CLOSED = 0x1C000015
|
26
|
+
NCA_S_FAULT_PIPE_ORDER = 0x1C000016
|
27
|
+
NCA_S_FAULT_PIPE_DISCIPLINE = 0x1C000017
|
28
|
+
NCA_S_FAULT_PIPE_COMM_ERROR = 0x1C000018
|
29
|
+
NCA_S_FAULT_PIPE_MEMORY = 0x1C000019
|
30
|
+
NCA_S_FAULT_CONTEXT_MISMATCH = 0x1C00001A
|
31
|
+
NCA_S_FAULT_REMOTE_NO_MEMORY = 0x1C00001B
|
32
|
+
NCA_INVALID_PRES_CONTEXT_ID = 0x1C00001C
|
33
|
+
NCA_UNSUPPORTED_AUTHN_LEVEL = 0x1C00001D
|
34
|
+
NCA_INVALID_CHECKSUM = 0x1C00001F
|
35
|
+
NCA_INVALID_CRC = 0x1C000020
|
36
|
+
NCS_S_FAULT_USER_DEFINED = 0x1C000021
|
37
|
+
NCA_S_FAULT_TX_OPEN_FAILED = 0x1C000022
|
38
|
+
NCA_S_FAULT_CODESET_CONV_ERROR = 0x1C000023
|
39
|
+
NCA_S_FAULT_OBJECT_NOT_FOUND = 0x1C000024
|
40
|
+
NCA_S_FAULT_NO_CLIENT_STUB = 0x1C000025
|
41
|
+
NCA_OP_RNG_ERROR = 0x1C010002
|
42
|
+
NCA_UNK_IF = 0x1C010003
|
43
|
+
NCA_WRONG_BOOT_TIME = 0x1C010006
|
44
|
+
NCA_S_YOU_CRASHED = 0x1C010009
|
45
|
+
NCA_PROTO_ERROR = 0x1C01000B
|
46
|
+
NCA_OUT_ARGS_TOO_BIG = 0x1C010013
|
47
|
+
NCA_SERVER_TOO_BUSY = 0x1C010014
|
48
|
+
NCA_UNSUPPORTED_TYPE = 0x1C010017
|
49
|
+
# Microsoft specific codes
|
50
|
+
E_NOTIMPL = 0x80004001
|
51
|
+
E_POINTER = 0x80004003
|
52
|
+
E_AOBRT = 0x80004004
|
53
|
+
E_UNEXPECTED = 0x8000FFFF
|
54
|
+
RPC_E_SERVERFAULT = 0x80010105
|
55
|
+
RPC_E_DISCONNECTED = 0x80010108
|
56
|
+
RPC_E_INVALID_IPID = 0x80010113
|
57
|
+
RPC_E_TIMEOUT = 0x8001011F
|
58
|
+
DISP_E_MEMBERNOTFOUND = 0x80020003
|
59
|
+
DISP_E_UNKNOWNNAME = 0x80020006
|
60
|
+
DISP_E_BADPARAMCOUNT = 0x8002000E
|
61
|
+
CBA_E_MALFORMED = 0x8004CB00
|
62
|
+
CBA_E_UNKNOWNOBJECT = 0x8004CB01
|
63
|
+
CBA_E_INVALIDID = 0x8004CB05
|
64
|
+
CBA_E_INVALIDCOOKIE = 0x8004CB09
|
65
|
+
CBA_E_QOSTYPEUNSUPPORTED = 0x8004CB0B
|
66
|
+
CBA_E_QOSVALUEUNSUPPORTED = 0x8004CB0C
|
67
|
+
CBA_E_NOTAPPLICABLE = 0x8004CB0F
|
68
|
+
CBA_E_LIMITVIOLATION = 0x8004CB12
|
69
|
+
CBA_E_QOSTYPENOTAPPLICABLE = 0x8004CB13
|
70
|
+
CBA_E_OUTOFPARTNERACCOS = 0x8004CB18
|
71
|
+
CBA_E_FLAGUNSUPPORTED = 0x8004CB1C
|
72
|
+
CBA_E_FRAMECOUNTUNSUPPORTED = 0x8004CB23
|
73
|
+
CBA_E_MODECHANGE = 0x8004CB25
|
74
|
+
E_OUTOFMEMORY = 0x8007000E
|
75
|
+
E_INVALIDARG = 0x80070057
|
76
|
+
RPC_S_PROCNUM_OUT_OF_RANGE = 0x800706D1
|
77
|
+
OR_INVALID_OXID = 0x80070776
|
78
|
+
|
79
|
+
def self.name(value)
|
80
|
+
constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/lib/ruby_smb/dcerpc/ndr.rb
CHANGED
@@ -312,29 +312,31 @@ module RubySMB::Dcerpc::Ndr
|
|
312
312
|
def initialize_instance
|
313
313
|
@read_until_index = 0
|
314
314
|
@max_count = 0
|
315
|
+
@max_count_set = false
|
315
316
|
super
|
316
317
|
end
|
317
318
|
|
318
319
|
def insert(index, *objs)
|
319
320
|
obj = super
|
320
|
-
@max_count = length
|
321
|
+
@max_count = length unless @max_count_set
|
321
322
|
obj
|
322
323
|
end
|
323
324
|
|
324
325
|
def slice_index(index)
|
325
326
|
obj = super
|
326
|
-
@max_count = length
|
327
|
+
@max_count = length unless @max_count_set
|
327
328
|
obj
|
328
329
|
end
|
329
330
|
|
330
331
|
def []=(index, value)
|
331
332
|
obj = super
|
332
|
-
@max_count = length
|
333
|
+
@max_count = length unless @max_count_set
|
333
334
|
obj
|
334
335
|
end
|
335
336
|
|
336
337
|
def set_max_count(val)
|
337
338
|
@max_count = @read_until_index = val
|
339
|
+
@max_count_set = true
|
338
340
|
end
|
339
341
|
end
|
340
342
|
|
@@ -650,7 +652,7 @@ module RubySMB::Dcerpc::Ndr
|
|
650
652
|
include ConstructedTypePlugin
|
651
653
|
|
652
654
|
def should_process_max_count?
|
653
|
-
# According to the NDR
|
655
|
+
# According to the NDR definition for Structures Containing a Conformant
|
654
656
|
# Array:
|
655
657
|
#
|
656
658
|
# "In the NDR representation of a structure that contains a
|
@@ -761,13 +763,13 @@ module RubySMB::Dcerpc::Ndr
|
|
761
763
|
return (4 - (rel_offset % 4)) % 4
|
762
764
|
end
|
763
765
|
if obj.is_a?(ConfPlugin)
|
764
|
-
# `max_count` should have been handled at the
|
766
|
+
# `max_count` should have been handled at the beginning of the structure
|
765
767
|
# already. We need to fix `rel_offset` since it includes the
|
766
768
|
# `max_count` 4 bytes, plus the possible padding bytes needed to align
|
767
769
|
# the structure. This is required because BinData Struct is not
|
768
|
-
# aware of `max_count` and
|
770
|
+
# aware of `max_count` and consider the first field to be the beginning
|
769
771
|
# of the structure instead. We have to make sure the alignment is
|
770
|
-
# calculated from the
|
772
|
+
# calculated from the beginning of the structure.
|
771
773
|
align = eval_parameter(:byte_align)
|
772
774
|
pad_length = (align - (4 % align)) % align
|
773
775
|
rel_offset += (4 + pad_length)
|
@@ -776,7 +778,7 @@ module RubySMB::Dcerpc::Ndr
|
|
776
778
|
# (not Varying). The size information (max_count) has been place in
|
777
779
|
# from of the structure and no other size information is present before
|
778
780
|
# the actual elements of the array. Therefore, the alignment must be
|
779
|
-
# done
|
781
|
+
# done according to the rules of the elements. Since a NdrArray has its
|
780
782
|
# default :byte_align value set to 4 (:max_count size), we have to make
|
781
783
|
# sure the element size is used instead.
|
782
784
|
unless obj.is_a?(VarPlugin)
|
@@ -838,6 +840,10 @@ module RubySMB::Dcerpc::Ndr
|
|
838
840
|
end
|
839
841
|
end
|
840
842
|
|
843
|
+
#
|
844
|
+
# [Unions](https://pubs.opengroup.org/onlinepubs/9629399/chap14.htm#tagcjh_19_03_08)
|
845
|
+
#
|
846
|
+
|
841
847
|
# TODO: Unions
|
842
848
|
# TODO: Pipes
|
843
849
|
|
@@ -1207,6 +1213,11 @@ module RubySMB::Dcerpc::Ndr
|
|
1207
1213
|
extend PointerClassPlugin
|
1208
1214
|
end
|
1209
1215
|
|
1216
|
+
class NdrUint16ArrayPtr < NdrConfVarArray
|
1217
|
+
default_parameters type: :ndr_uint16
|
1218
|
+
extend PointerClassPlugin
|
1219
|
+
end
|
1220
|
+
|
1210
1221
|
class NdrFileTimePtr < NdrFileTime
|
1211
1222
|
extend PointerClassPlugin
|
1212
1223
|
end
|
@@ -60,16 +60,21 @@ module RubySMB
|
|
60
60
|
string :default
|
61
61
|
end
|
62
62
|
choice 'Samr', selection: -> { opnum } do
|
63
|
-
samr_connect_request
|
64
|
-
samr_lookup_domain_in_sam_server_request
|
65
|
-
samr_open_domain_request
|
66
|
-
samr_enumerate_users_in_domain_request
|
67
|
-
samr_rid_to_sid_request
|
68
|
-
samr_close_handle_request
|
69
|
-
samr_get_alias_membership_request
|
70
|
-
samr_open_user_request
|
71
|
-
samr_get_groups_for_user_request
|
72
|
-
|
63
|
+
samr_connect_request Samr::SAMR_CONNECT
|
64
|
+
samr_lookup_domain_in_sam_server_request Samr::SAMR_LOOKUP_DOMAIN_IN_SAM_SERVER
|
65
|
+
samr_open_domain_request Samr::SAMR_OPEN_DOMAIN
|
66
|
+
samr_enumerate_users_in_domain_request Samr::SAMR_ENUMERATE_USERS_IN_DOMAIN
|
67
|
+
samr_rid_to_sid_request Samr::SAMR_RID_TO_SID
|
68
|
+
samr_close_handle_request Samr::SAMR_CLOSE_HANDLE
|
69
|
+
samr_get_alias_membership_request Samr::SAMR_GET_ALIAS_MEMBERSHIP
|
70
|
+
samr_open_user_request Samr::SAMR_OPEN_USER
|
71
|
+
samr_get_groups_for_user_request Samr::SAMR_GET_GROUPS_FOR_USER
|
72
|
+
samr_enumerate_domains_in_sam_server_request Samr::SAMR_ENUMERATE_DOMAINS_IN_SAM_SERVER
|
73
|
+
samr_lookup_names_in_domain_request Samr::SAMR_LOOKUP_NAMES_IN_DOMAIN
|
74
|
+
samr_create_user2_in_domain_request Samr::SAMR_CREATE_USER2_IN_DOMAIN
|
75
|
+
samr_set_information_user2_request Samr::SAMR_SET_INFORMATION_USER2
|
76
|
+
samr_delete_user_request Samr::SAMR_DELETE_USER
|
77
|
+
string :default
|
73
78
|
end
|
74
79
|
choice 'Wkssvc', selection: -> { opnum } do
|
75
80
|
netr_wksta_get_info_request Wkssvc::NETR_WKSTA_GET_INFO
|
@@ -109,6 +109,11 @@ module RubySMB
|
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
|
+
class RpcUnicodeStringConfVarArray < Ndr::NdrConfVarArray
|
113
|
+
extend Ndr::ArrayClassPlugin
|
114
|
+
default_parameters type: :rpc_unicode_string
|
115
|
+
end
|
116
|
+
|
112
117
|
# A pointer to a RPC_UNICODE_STRING structure
|
113
118
|
class PrpcUnicodeString < RpcUnicodeString
|
114
119
|
extend Ndr::PointerClassPlugin
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.4.4 SamrCreateUser2InDomain (Opnum 50)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/a98d7fbb-1735-4fbf-b41a-ef363c899002)
|
6
|
+
class SamrCreateUser2InDomainRequest < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
sampr_handle :domain_handle
|
12
|
+
rpc_unicode_string :name
|
13
|
+
ndr_uint32 :account_type
|
14
|
+
ndr_uint32 :desired_access
|
15
|
+
|
16
|
+
def initialize_instance
|
17
|
+
super
|
18
|
+
@opnum = SAMR_CREATE_USER2_IN_DOMAIN
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Samr
|
4
|
+
|
5
|
+
# [3.1.5.4.4 SamrCreateUser2InDomain (Opnum 50)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-samr/a98d7fbb-1735-4fbf-b41a-ef363c899002)
|
6
|
+
class SamrCreateUser2InDomainResponse < BinData::Record
|
7
|
+
attr_reader :opnum
|
8
|
+
|
9
|
+
endian :little
|
10
|
+
|
11
|
+
sampr_handle :user_handle
|
12
|
+
ndr_uint32 :granted_access
|
13
|
+
ndr_uint32 :relative_id
|
14
|
+
ndr_uint32 :error_status
|
15
|
+
|
16
|
+
def initialize_instance
|
17
|
+
super
|
18
|
+
@opnum = SAMR_CREATE_USER2_IN_DOMAIN
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|