ruby_smb 3.1.5 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/verify.yml +27 -4
  4. data/README.md +1 -2
  5. data/lib/ruby_smb/client/authentication.rb +4 -30
  6. data/lib/ruby_smb/dcerpc/client.rb +6 -261
  7. data/lib/ruby_smb/dcerpc/dfsnm/netr_dfs_add_std_root_request.rb +24 -0
  8. data/lib/ruby_smb/dcerpc/dfsnm/netr_dfs_add_std_root_response.rb +21 -0
  9. data/lib/ruby_smb/dcerpc/dfsnm/netr_dfs_remove_std_root_request.rb +23 -0
  10. data/lib/ruby_smb/dcerpc/dfsnm/netr_dfs_remove_std_root_response.rb +21 -0
  11. data/lib/ruby_smb/dcerpc/dfsnm.rb +84 -0
  12. data/lib/ruby_smb/dcerpc/error.rb +21 -0
  13. data/lib/ruby_smb/dcerpc/icpr/cert_server_request_request.rb +27 -0
  14. data/lib/ruby_smb/dcerpc/icpr/cert_server_request_response.rb +28 -0
  15. data/lib/ruby_smb/dcerpc/icpr.rb +84 -0
  16. data/lib/ruby_smb/dcerpc/ndr.rb +38 -2
  17. data/lib/ruby_smb/dcerpc/request.rb +10 -1
  18. data/lib/ruby_smb/dcerpc.rb +246 -12
  19. data/lib/ruby_smb/error.rb +25 -11
  20. data/lib/ruby_smb/peer_info.rb +39 -0
  21. data/lib/ruby_smb/signing.rb +2 -0
  22. data/lib/ruby_smb/smb1/pipe.rb +23 -1
  23. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +5 -1
  24. data/lib/ruby_smb/smb2/pipe.rb +23 -0
  25. data/lib/ruby_smb/version.rb +1 -1
  26. data/spec/lib/ruby_smb/dcerpc/dfsnm/netr_dfs_add_std_root_request_spec.rb +57 -0
  27. data/spec/lib/ruby_smb/dcerpc/dfsnm/netr_dfs_add_std_root_response_spec.rb +34 -0
  28. data/spec/lib/ruby_smb/dcerpc/dfsnm/netr_dfs_remove_std_root_request_spec.rb +49 -0
  29. data/spec/lib/ruby_smb/dcerpc/dfsnm/netr_dfs_remove_std_root_response_spec.rb +34 -0
  30. data/spec/lib/ruby_smb/dcerpc/icpr/cert_server_request_request_spec.rb +64 -0
  31. data/spec/lib/ruby_smb/dcerpc/icpr/cert_server_request_response_spec.rb +71 -0
  32. data/spec/lib/ruby_smb/dcerpc/icpr/cert_trans_blob_spec.rb +33 -0
  33. data/spec/lib/ruby_smb/dcerpc_spec.rb +2 -1
  34. data/spec/spec_helper.rb +6 -8
  35. data/spec/support/openssl.conf +14 -0
  36. data.tar.gz.sig +0 -0
  37. metadata +27 -2
  38. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4749ae5185070d44e447593cd863ee5ac17a87468b16b14a251f68e0166b7663
4
- data.tar.gz: b63378e4367136e0c6dffc35aa02b5c5ce1df450d5b64300eaee060e7938e9ec
3
+ metadata.gz: 9ce8d4ea99335efaf6bbc1ef003231ffa8a809382760e54dc26be04b76e53529
4
+ data.tar.gz: f284dabf7fe032ae02933a517abb2371f7c7c37eb641876f1cbf2b8cc0e4c2ac
5
5
  SHA512:
6
- metadata.gz: f09557d4ba6148796bb6adf2c1169ebad237f021527975fabb179e1eb2099cfb2c17e45d3b57629c7fc61106092317076e41c77d39f8cb3d4335d280a75e144c
7
- data.tar.gz: e969cc9f474e64e4cf7ba9bcf39e1dfc30b9e365bf6c758abd1e7ff905a6e9a3a8f3c3b33fc88f3104b7998201406d8b78bca34e746c58cfa4c03353bd94f789
6
+ metadata.gz: 5cf115ffd4c634f593bceef2bb503d2c0a2b19c5cfa73391887d35ce2691472fabda03e47462b716f8c870d7dedbc5dc815f644887b259d1268658752396ea17
7
+ data.tar.gz: 46ba6053ca246692ef29c545c8a9682b6675c4bf50d10d3611107bf537470226986aeece854516d59d99afa1642ee2d72fed99f39c1731112292fcbb6d8138d2
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,5 +1,21 @@
1
1
  name: Verify
2
2
 
3
+ # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
4
+ permissions:
5
+ actions: none
6
+ checks: none
7
+ contents: none
8
+ deployments: none
9
+ id-token: none
10
+ issues: none
11
+ discussions: none
12
+ packages: none
13
+ pages: none
14
+ pull-requests: none
15
+ repository-projects: none
16
+ security-events: none
17
+ statuses: none
18
+
3
19
  on:
4
20
  push:
5
21
  branches:
@@ -10,7 +26,7 @@ on:
10
26
 
11
27
  jobs:
12
28
  test:
13
- runs-on: ubuntu-18.04
29
+ runs-on: ${{ matrix.os }}
14
30
  timeout-minutes: 40
15
31
 
16
32
  strategy:
@@ -19,15 +35,22 @@ jobs:
19
35
  ruby:
20
36
  - 2.6
21
37
  - 2.7
22
- - 3.0.3
23
- - 3.1.1
38
+ - 3.0
39
+ - 3.1
40
+ os:
41
+ - ubuntu-18.04
42
+ - ubuntu-22.04
43
+ exclude:
44
+ - { os: ubuntu-22.04, ruby: 2.6 }
45
+ - { os: ubuntu-22.04, ruby: 2.7 }
46
+ - { os: ubuntu-22.04, ruby: 3.0 }
24
47
  test_cmd:
25
48
  - bundle exec rspec
26
49
 
27
50
  env:
28
51
  RAILS_ENV: test
29
52
 
30
- name: Ruby ${{ matrix.ruby }} - ${{ matrix.test_cmd }}
53
+ name: ${{ matrix.os }} - Ruby ${{ matrix.ruby }} - ${{ matrix.test_cmd }}
31
54
  steps:
32
55
  - name: Checkout code
33
56
  uses: actions/checkout@v2
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # RubySMB
2
2
 
3
3
  [![Code Climate](https://codeclimate.com/github/rapid7/ruby_smb.png)](https://codeclimate.com/github/rapid7/ruby_smb)
4
- [![Coverage Status](https://coveralls.io/repos/github/rapid7/ruby_smb/badge.svg?branch=master)](https://coveralls.io/github/rapid7/ruby_smb?branch=master)
5
4
 
6
5
  This is a native Ruby implementation of the SMB Protocol Family. It currently supports:
7
6
 
@@ -187,7 +186,7 @@ Example:
187
186
  ```
188
187
  ### Using the Client
189
188
 
190
- Sitting on top of the packet layer in RubySMB is the RubySMB::Client class. This is the abstraction that most users of RubySMB will interact with. It provides simple conveience methods for performing SMB actions. It handles the creation, sending and receiving of packets for the user, providing reasonable defaults in many cases.
189
+ Sitting on top of the packet layer in RubySMB is the RubySMB::Client class. This is the abstraction that most users of RubySMB will interact with. It provides simple convenience methods for performing SMB actions. It handles the creation, sending and receiving of packets for the user, providing reasonable defaults in many cases.
191
190
 
192
191
  #### Negotiation
193
192
 
@@ -1,7 +1,11 @@
1
+ require 'ruby_smb/peer_info'
2
+
1
3
  module RubySMB
2
4
  class Client
3
5
  # This module holds all the backend client methods for authentication.
4
6
  module Authentication
7
+ include RubySMB::PeerInfo
8
+
5
9
  # Responsible for handling Authentication and Session Setup for
6
10
  # the SMB Client. It returns the final Status code from the authentication
7
11
  # exchange.
@@ -356,36 +360,6 @@ module RubySMB
356
360
  packet.security_mode.signing_enabled = 1
357
361
  packet
358
362
  end
359
-
360
- # Extract and store useful information about the peer/server from the
361
- # NTLM Type 2 (challenge) TargetInfo fields.
362
- #
363
- # @param target_info_str [String] the Target Info string
364
- def store_target_info(target_info_str)
365
- target_info = Net::NTLM::TargetInfo.new(target_info_str)
366
- {
367
- Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME => :@default_name,
368
- Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME => :@default_domain,
369
- Net::NTLM::TargetInfo::MSV_AV_DNS_COMPUTER_NAME => :@dns_host_name,
370
- Net::NTLM::TargetInfo::MSV_AV_DNS_DOMAIN_NAME => :@dns_domain_name,
371
- Net::NTLM::TargetInfo::MSV_AV_DNS_TREE_NAME => :@dns_tree_name
372
- }.each do |constant, attribute|
373
- if target_info.av_pairs[constant]
374
- value = target_info.av_pairs[constant].dup
375
- value.force_encoding('UTF-16LE')
376
- instance_variable_set(attribute, value.encode('UTF-8'))
377
- end
378
- end
379
- end
380
-
381
- # Extract the peer/server version number from the NTLM Type 2 (challenge)
382
- # Version field.
383
- #
384
- # @param version [String] the version number as a binary string
385
- # @return [String] the formated version number (<major>.<minor>.<build>)
386
- def extract_os_version(version)
387
- version.unpack('CCS').join('.')
388
- end
389
363
  end
390
364
  end
391
365
  end
@@ -8,8 +8,11 @@ module RubySMB
8
8
  require 'net/ntlm'
9
9
  require 'ruby_smb/dcerpc'
10
10
  require 'ruby_smb/gss'
11
+ require 'ruby_smb/peer_info'
11
12
 
13
+ include Dcerpc
12
14
  include Epm
15
+ include PeerInfo
13
16
 
14
17
  # The default maximum size of a RPC message that the Client accepts (in bytes)
15
18
  MAX_BUFFER_SIZE = 64512
@@ -134,11 +137,11 @@ module RubySMB
134
137
  end
135
138
 
136
139
  # Connect to the RPC endpoint. If a TCP socket was not provided, it takes
137
- # care of asking the Enpoint Mapper Interface the port used by the given
140
+ # care of asking the Endpoint Mapper Interface the port used by the given
138
141
  # endpoint provided in #initialize and connect a TCP socket
139
142
  #
140
143
  # @param port [Integer] An optional port number to connect to. If
141
- # provided, it will not ask the Enpoint Mapper Interface for a port
144
+ # provided, it will not ask the Endpoint Mapper Interface for a port
142
145
  # number.
143
146
  # @return [TcpSocket] The connected TCP socket
144
147
  def connect(port: nil)
@@ -172,218 +175,14 @@ module RubySMB
172
175
  @tcp_socket.close if @tcp_socket && !@tcp_socket.closed?
173
176
  end
174
177
 
175
- # Add the authentication verifier to the packet. This includes a sec
176
- # trailer and the actual authentication data.
177
- #
178
- # @param req [BinData::Record] the request to be updated
179
- # @param auth [String] the authentication data
180
- # @param auth_type [Integer] the authentication type
181
- # @param auth_level [Integer] the authentication level
182
- def add_auth_verifier(req, auth, auth_type, auth_level)
183
- req.sec_trailer = {
184
- auth_type: auth_type,
185
- auth_level: auth_level,
186
- auth_context_id: @ctx_id + @auth_ctx_id_base
187
- }
188
- req.auth_value = auth
189
- req.pdu_header.auth_length = auth.length
190
-
191
- nil
192
- end
193
-
194
178
  def process_ntlm_type2(type2_message)
195
- ntlmssp_offset = type2_message.index('NTLMSSP')
196
- type2_blob = type2_message.slice(ntlmssp_offset..-1)
197
- type2_b64_message = [type2_blob].pack('m')
198
- type3_message = @ntlm_client.init_context(type2_b64_message)
199
- auth3 = type3_message.serialize
200
-
201
- @session_key = @ntlm_client.session_key
179
+ auth3 = super
202
180
  challenge_message = @ntlm_client.session.challenge_message
203
181
  store_target_info(challenge_message.target_info) if challenge_message.has_flag?(:TARGET_INFO)
204
182
  @os_version = extract_os_version(challenge_message.os_version.to_s) unless challenge_message.os_version.empty?
205
183
  auth3
206
184
  end
207
185
 
208
- # Send a rpc_auth3 PDU that ends the authentication handshake.
209
- #
210
- # @param response [BindAck] the BindAck response packet
211
- # @param auth_type [Integer] the authentication type
212
- # @param auth_level [Integer] the authentication level
213
- # @raise [ArgumentError] if `:auth_type` is unknown
214
- # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
215
- def send_auth3(response, auth_type, auth_level)
216
- case auth_type
217
- when RPC_C_AUTHN_NONE
218
- when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
219
- auth3 = process_ntlm_type2(response.auth_value)
220
- when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
221
- # TODO
222
- raise NotImplementedError
223
- else
224
- raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
225
- end
226
-
227
- rpc_auth3 = RpcAuth3.new
228
- add_auth_verifier(rpc_auth3, auth3, auth_type, auth_level)
229
- rpc_auth3.pdu_header.call_id = @call_id
230
-
231
- # The server should not respond
232
- send_packet(rpc_auth3)
233
- @call_id += 1
234
-
235
- nil
236
- end
237
-
238
- # Bind to the remote server interface endpoint. It takes care of adding
239
- # the necessary authentication verifier if `:auth_level` is set to
240
- # anything different than RPC_C_AUTHN_LEVEL_NONE
241
- #
242
- # @param endpoint [Module] the endpoint to bind to. This must be a Dcerpc
243
- # class with UUID, VER_MAJOR and VER_MINOR constants defined.
244
- # @param auth_level [Integer] the authentication level
245
- # @param auth_type [Integer] the authentication type
246
- # @return [BindAck] the BindAck response packet
247
- # @raise [Error::InvalidPacket] if an invalid packet is received
248
- # @raise [Error::BindError] if the response is not a BindAck packet or if the Bind result code is not ACCEPTANCE
249
- # @raise [ArgumentError] if `:auth_type` is unknown
250
- # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
251
- def bind(endpoint: @endpoint, auth_level: RPC_C_AUTHN_LEVEL_NONE, auth_type: nil)
252
- bind_req = Bind.new(endpoint: endpoint)
253
- bind_req.pdu_header.call_id = @call_id
254
- # TODO: evasion: generate random UUIDs for bogus binds
255
-
256
- if auth_level && auth_level != RPC_C_AUTHN_LEVEL_NONE
257
- case auth_type
258
- when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
259
- raise ArgumentError, "NTLM Client not initialized. Username and password must be provided" unless @ntlm_client
260
- type1_message = @ntlm_client.init_context
261
- auth = type1_message.serialize
262
- when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
263
- when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL
264
- # TODO
265
- raise NotImplementedError
266
- else
267
- raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
268
- end
269
- add_auth_verifier(bind_req, auth, auth_type, auth_level)
270
- end
271
-
272
- send_packet(bind_req)
273
- bindack_response = recv_struct(BindAck)
274
- # TODO: see if BindNack response should be handled too
275
-
276
- res_list = bindack_response.p_result_list
277
- if res_list.n_results == 0 ||
278
- res_list.p_results[0].result != BindAck::ACCEPTANCE
279
- raise Error::BindError,
280
- "Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
281
- end
282
-
283
- @max_buffer_size = bindack_response.max_xmit_frag
284
- @call_id = bindack_response.pdu_header.call_id
285
-
286
- if auth_level && auth_level != RPC_C_AUTHN_LEVEL_NONE
287
- # The number of legs needed to build the security context is defined
288
- # by the security provider
289
- # (see [2.2.1.1.7 Security Providers](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d4097450-c62f-484b-872f-ddf59a7a0d36))
290
- case auth_type
291
- when RPC_C_AUTHN_WINNT
292
- send_auth3(bindack_response, auth_type, auth_level)
293
- when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
294
- # TODO
295
- raise NotImplementedError
296
- end
297
- end
298
-
299
- nil
300
- end
301
-
302
- # Extract and store useful information about the peer/server from the
303
- # NTLM Type 2 (challenge) TargetInfo fields.
304
- #
305
- # @param target_info_str [String] the Target Info string
306
- def store_target_info(target_info_str)
307
- target_info = Net::NTLM::TargetInfo.new(target_info_str)
308
- {
309
- Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME => :@default_name,
310
- Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME => :@default_domain,
311
- Net::NTLM::TargetInfo::MSV_AV_DNS_COMPUTER_NAME => :@dns_host_name,
312
- Net::NTLM::TargetInfo::MSV_AV_DNS_DOMAIN_NAME => :@dns_domain_name,
313
- Net::NTLM::TargetInfo::MSV_AV_DNS_TREE_NAME => :@dns_tree_name
314
- }.each do |constant, attribute|
315
- if target_info.av_pairs[constant]
316
- value = target_info.av_pairs[constant].dup
317
- value.force_encoding('UTF-16LE')
318
- instance_variable_set(attribute, value.encode('UTF-8'))
319
- end
320
- end
321
- end
322
-
323
- # Extract the peer/server version number from the NTLM Type 2 (challenge)
324
- # Version field.
325
- #
326
- # @param version [String] the version number as a binary string
327
- # @return [String] the formated version number (<major>.<minor>.<build>)
328
- def extract_os_version(version)
329
- #version.unpack('CCS').join('.')
330
- begin
331
- os_version = NTLM::OSVersion.read(version)
332
- rescue IOError
333
- return ''
334
- end
335
- return "#{os_version.major}.#{os_version.minor}.#{os_version.build}"
336
- end
337
-
338
- # Add the authentication verifier to a Request packet. This includes a
339
- # sec trailer and the signature of the packet. This also encrypts the
340
- # Request stub if privacy is required (`:auth_level` option is
341
- # RPC_C_AUTHN_LEVEL_PKT_PRIVACY).
342
- #
343
- # @param dcerpc_req [Request] the Request packet to be updated
344
- # @param opts [Hash] the authenticaiton options: `:auth_type` and `:auth_level`
345
- # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
346
- # @raise [ArgumentError] if `:auth_type` is unknown
347
- def set_integrity_privacy(dcerpc_req, auth_level:, auth_type:)
348
- dcerpc_req.sec_trailer = {
349
- auth_type: auth_type,
350
- auth_level: auth_level,
351
- auth_context_id: @ctx_id + @auth_ctx_id_base
352
- }
353
- dcerpc_req.auth_value = ' ' * 16
354
- dcerpc_req.pdu_header.auth_length = 16
355
-
356
- data_to_sign = plain_stub = dcerpc_req.stub.to_binary_s + dcerpc_req.auth_pad.to_binary_s
357
- if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
358
- data_to_sign = dcerpc_req.to_binary_s[0..-(dcerpc_req.pdu_header.auth_length + 1)]
359
- end
360
-
361
- encrypted_stub = ''
362
- if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
363
- case auth_type
364
- when RPC_C_AUTHN_NONE
365
- when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
366
- encrypted_stub = @ntlm_client.session.seal_message(plain_stub)
367
- when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
368
- # TODO
369
- raise NotImplementedError
370
- else
371
- raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
372
- end
373
- end
374
-
375
- signature = @ntlm_client.session.sign_message(data_to_sign)
376
-
377
- unless encrypted_stub.empty?
378
- pad_length = dcerpc_req.sec_trailer.auth_pad_length.to_i
379
- dcerpc_req.enable_encrypted_stub
380
- dcerpc_req.stub = encrypted_stub[0..-(pad_length + 1)]
381
- dcerpc_req.auth_pad = encrypted_stub[-(pad_length)..-1]
382
- end
383
- dcerpc_req.auth_value = signature
384
- dcerpc_req.pdu_header.auth_length = signature.size
385
- end
386
-
387
186
  # Send a DCERPC request with the provided stub packet.
388
187
  #
389
188
  # @param stub_packet [BinData::Record] the stub packet to be sent as
@@ -482,60 +281,6 @@ module RubySMB
482
281
  raise Error::CommunicationError, "An error occurred reading from the Socket: #{e.message}"
483
282
  end
484
283
 
485
- # Process the security context received in a response. It decrypts the
486
- # encrypted stub if `:auth_level` is set to anything different than
487
- # RPC_C_AUTHN_LEVEL_PKT_PRIVACY. It also checks the packet signature and
488
- # raises an InvalidPacket error if it fails. Note that the exception is
489
- # disabled by default and can be enabled with the
490
- # `:raise_signature_error` option
491
- #
492
- # @param dcerpc_response [Response] the Response packet
493
- # containing the security context to process
494
- # @param opts [Hash] the authenticaiton options: `:auth_type` and
495
- # `:auth_level`. To enable errors when signature check fails, set the
496
- # `:raise_signature_error` option to true
497
- # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
498
- # @raise [Error::CommunicationError] if socket-related error occurs
499
- def handle_integrity_privacy(dcerpc_response, auth_level:, auth_type:, raise_signature_error: false)
500
- decrypted_stub = ''
501
- if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
502
- encrypted_stub = dcerpc_response.stub.to_binary_s + dcerpc_response.auth_pad.to_binary_s
503
- case auth_type
504
- when RPC_C_AUTHN_NONE
505
- when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
506
- decrypted_stub = @ntlm_client.session.unseal_message(encrypted_stub)
507
- when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
508
- # TODO
509
- raise NotImplementedError
510
- else
511
- raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
512
- end
513
- end
514
-
515
- unless decrypted_stub.empty?
516
- pad_length = dcerpc_response.sec_trailer.auth_pad_length.to_i
517
- dcerpc_response.stub = decrypted_stub[0..-(pad_length + 1)]
518
- dcerpc_response.auth_pad = decrypted_stub[-(pad_length)..-1]
519
- end
520
-
521
- signature = dcerpc_response.auth_value
522
- data_to_check = dcerpc_response.stub.to_binary_s
523
- if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
524
- data_to_check = dcerpc_response.to_binary_s[0..-(dcerpc_response.pdu_header.auth_length + 1)]
525
- end
526
- unless @ntlm_client.session.verify_signature(signature, data_to_check)
527
- if raise_signature_error
528
- raise Error::InvalidPacket.new(
529
- "Wrong packet signature received (set `raise_signature_error` to false to ignore)"
530
- )
531
- end
532
- end
533
-
534
- @call_id += 1
535
-
536
- nil
537
- end
538
-
539
284
  end
540
285
  end
541
286
  end
@@ -0,0 +1,24 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Dfsnm
4
+
5
+ # [3.1.4.4.1 NetrDfsAddStdRoot (Opnum 12)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dfsnm/b18ef17a-7a9c-4e22-b1bf-6a4d07e87b2d)
6
+ class NetrDfsAddStdRootRequest < BinData::Record
7
+ attr_reader :opnum
8
+
9
+ endian :little
10
+
11
+ ndr_conf_var_wide_stringz :server_name
12
+ ndr_conf_var_wide_stringz :root_share
13
+ ndr_conf_var_wide_stringz :comment
14
+ ndr_uint32 :api_flags
15
+
16
+ def initialize_instance
17
+ super
18
+ @opnum = NETR_DFS_ADD_STD_ROOT
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Dfsnm
4
+
5
+ # [3.1.4.4.1 NetrDfsAddStdRoot (Opnum 12)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dfsnm/b18ef17a-7a9c-4e22-b1bf-6a4d07e87b2d)
6
+ class NetrDfsAddStdRootResponse < BinData::Record
7
+ attr_reader :opnum
8
+
9
+ endian :little
10
+
11
+ ndr_uint32 :error_status
12
+
13
+ def initialize_instance
14
+ super
15
+ @opnum = NETR_DFS_ADD_STD_ROOT
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,23 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Dfsnm
4
+
5
+ # [3.1.4.4.2 NetrDfsRemoveStdRoot (Opnum 13)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dfsnm/e9da023d-554a-49bc-837a-69f22d59fd18)
6
+ class NetrDfsRemoveStdRootRequest < BinData::Record
7
+ attr_reader :opnum
8
+
9
+ endian :little
10
+
11
+ ndr_conf_var_wide_stringz :server_name
12
+ ndr_conf_var_wide_stringz :root_share
13
+ ndr_uint32 :api_flags
14
+
15
+ def initialize_instance
16
+ super
17
+ @opnum = NETR_DFS_REMOVE_STD_ROOT
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Dfsnm
4
+
5
+ # [3.1.4.4.2 NetrDfsRemoveStdRoot (Opnum 13)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dfsnm/e9da023d-554a-49bc-837a-69f22d59fd18)
6
+ class NetrDfsRemoveStdRootResponse < BinData::Record
7
+ attr_reader :opnum
8
+
9
+ endian :little
10
+
11
+ ndr_uint32 :error_status
12
+
13
+ def initialize_instance
14
+ super
15
+ @opnum = NETR_DFS_REMOVE_STD_ROOT
16
+ end
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,84 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Dfsnm
4
+
5
+ UUID = '4fc742e0-4a10-11cf-8273-00aa004ae673'
6
+ VER_MAJOR = 3
7
+ VER_MINOR = 0
8
+
9
+ # Operation numbers
10
+ NETR_DFS_ADD_STD_ROOT = 0x000c
11
+ NETR_DFS_REMOVE_STD_ROOT = 0x000d
12
+
13
+ require 'ruby_smb/dcerpc/dfsnm/netr_dfs_add_std_root_request'
14
+ require 'ruby_smb/dcerpc/dfsnm/netr_dfs_add_std_root_response'
15
+ require 'ruby_smb/dcerpc/dfsnm/netr_dfs_remove_std_root_request'
16
+ require 'ruby_smb/dcerpc/dfsnm/netr_dfs_remove_std_root_response'
17
+
18
+ # Create a new stand-alone DFS namespace.
19
+ #
20
+ # @param server_name [String] The host name of the DFS root target.
21
+ # @param root_share [String] The DFS root target share name.
22
+ # @param comment [String] A comment associated with the DFS namespace.
23
+ # @return nothing is returned on success
24
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
25
+ # NetrDfsAddStdRootResponse packet
26
+ # @raise [RubySMB::Dcerpc::Error::DfsnmError] if the response error status
27
+ # is not ERROR_SUCCESS
28
+ def netr_dfs_add_std_root(server_name, root_share, comment: '')
29
+ netr_dfs_add_std_root_request = NetrDfsAddStdRootRequest.new(
30
+ server_name: server_name,
31
+ root_share: root_share,
32
+ comment: comment
33
+ )
34
+ response = dcerpc_request(netr_dfs_add_std_root_request)
35
+ begin
36
+ netr_dfs_add_std_root_response = NetrDfsAddStdRootResponse.read(response)
37
+ rescue IOError
38
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading NetrDfsAddStdRootResponse'
39
+ end
40
+ unless netr_dfs_add_std_root_response.error_status == WindowsError::Win32::ERROR_SUCCESS
41
+ status_code = WindowsError::Win32.find_by_retval(netr_dfs_add_std_root_response.error_status.value).first
42
+ raise RubySMB::Dcerpc::Error::DfsnmError.new(
43
+ "Error returned with netr_dfs_add_std_root: #{status_code}",
44
+ status_code: status_code
45
+ )
46
+ end
47
+
48
+ nil
49
+ end
50
+
51
+ # Delete the specified stand-alone DFS namespace.
52
+ #
53
+ # @param server_name [String] The host name of the DFS root target.
54
+ # @param root_share [String] The DFS root target share name.
55
+ # @return nothing is returned on success
56
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a
57
+ # NetrDfsRemoveStdRootResponse packet
58
+ # @raise [RubySMB::Dcerpc::Error::DfsnmError] if the response error status
59
+ # is not ERROR_SUCCESS
60
+ def netr_dfs_remove_std_root(server_name, root_share)
61
+ netr_dfs_remove_std_root_request = NetrDfsRemoveStdRootRequest.new(
62
+ server_name: server_name,
63
+ root_share: root_share
64
+ )
65
+ response = dcerpc_request(netr_dfs_remove_std_root_request)
66
+ begin
67
+ netr_dfs_remove_std_root_response = NetrDfsRemoveStdRootResponse.read(response)
68
+ rescue IOError
69
+ raise RubySMB::Dcerpc::Error::InvalidPacket, 'Error reading NetrDfsRemoveStdRootResponse'
70
+ end
71
+ unless netr_dfs_remove_std_root_response.error_status == WindowsError::Win32::ERROR_SUCCESS
72
+ status_code = WindowsError::Win32.find_by_retval(netr_dfs_remove_std_root_response.error_status.value).first
73
+ raise RubySMB::Dcerpc::Error::DfsnmError.new(
74
+ "Error returned with netr_dfs_remove_std_root: #{status_code}",
75
+ status_code: status_code
76
+ )
77
+ end
78
+
79
+ nil
80
+ end
81
+
82
+ end
83
+ end
84
+ end
@@ -46,6 +46,27 @@ module RubySMB
46
46
 
47
47
  # Raised when an error is returned during a Epm operation
48
48
  class EpmError < DcerpcError; end
49
+
50
+ # Raised when an error is returned during a Dfsnm operation
51
+ class DfsnmError < DcerpcError
52
+ include RubySMB::Error::UnexpectedStatusCode::Mixin
53
+
54
+ def initialize(msg, status_code: nil)
55
+ self.status_code = status_code unless status_code.nil?
56
+
57
+ super(msg)
58
+ end
59
+ end
60
+
61
+ class IcprError < DcerpcError
62
+ include RubySMB::Error::UnexpectedStatusCode::Mixin
63
+
64
+ def initialize(msg, status_code: nil)
65
+ self.status_code = status_code unless status_code.nil?
66
+
67
+ super(msg)
68
+ end
69
+ end
49
70
  end
50
71
  end
51
72
  end
@@ -0,0 +1,27 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Icpr
6
+
7
+ # [3.2.4.1.1 CertServerRequest (Opnum 0)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-icpr/0c6f150e-3ead-4006-b37f-ebbf9e2cf2e7)
8
+ class CertServerRequestRequest < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ ndr_uint32 :dw_flags
14
+ ndr_wide_stringz_ptr :pwsz_authority
15
+ ndr_uint32 :pdw_request_id
16
+ cert_trans_blob :pctb_attribs
17
+ cert_trans_blob :pctb_request
18
+
19
+ def initialize_instance
20
+ super
21
+ @opnum = CERT_SERVER_REQUEST
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end