ruby_smb 3.2.5 → 3.2.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 94370417b66a804dd7d24a57070fe9e5accf48f042baf4cbc56ead2227b92bd5
4
- data.tar.gz: 5f130535d6ccf03dd60c9fc879b0bb050d328c4906f40a702260370c24ac52a3
3
+ metadata.gz: 6220ba1edc47882a9d30dd1937d877c22094ebaf9c2a72cb806489a65598e1ce
4
+ data.tar.gz: 1b650bfdd2b6ba8323e9d3e7f4e161c7a659dddbffc7fa21a03d4a2e538f7297
5
5
  SHA512:
6
- metadata.gz: fcc08f98211ef0970ab0cedd56f5955d9ca3f52235b2751a84972036b67f3b2f2c3fd07c22919e8522d4ad1876d43ca3099a1286140abedece7f399f0dc871bf
7
- data.tar.gz: a4fe143def77e9e85fb40e44dfb5f33be4fb8499c4aff196ded4ad1710f84f278be70752fd9a4827cbc66e1afe299716f80854a74492998fb26c5cd6f6572a7d
6
+ metadata.gz: 9e49bc0af1cd4ad61cba01ec70aecead1adbe3b4d58d6127593878596bdbc7f64c8d50b9aaa396004ffc3a3b5e8cf1806053d0825d44322aa4d4584bdddeced7
7
+ data.tar.gz: 36ca2d7c9e6256a0faabac441e89ea86d43ccd8d2de342dba4965679d2e2c4fafa541fbc09c4457d656a2cccef1af53fe5ab487245800914ad8b9a6431679088
checksums.yaml.gz.sig CHANGED
Binary file
data/cortex.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ info:
3
+ title: Ruby Smb
4
+ description: A native Ruby implementation of the SMB Protocol Family
5
+ x-cortex-git:
6
+ github:
7
+ alias: r7org
8
+ repository: rapid7/ruby_smb
9
+ x-cortex-tag: ruby-smb
10
+ x-cortex-type: service
11
+ x-cortex-domain-parents:
12
+ - tag: metasploit
13
+ openapi: 3.0.1
14
+ servers:
15
+ - url: "/"
@@ -60,7 +60,7 @@ dc_infos.each do |dc_info|
60
60
  puts "Decrypting hash for user: #{dn}"
61
61
 
62
62
  entinf_struct = user_record.pmsg_out.msg_getchg.p_objects.entinf
63
- object_sid = rid = entinf_struct.p_name.sid[-4..-1].unpack('<L').first
63
+ object_sid = rid = entinf_struct.p_name.sid[-4..-1].unpack('L<').first
64
64
  lm_hash = Net::NTLM.lm_hash('')
65
65
  nt_hash = Net::NTLM.ntlm_hash('')
66
66
  disabled = nil
@@ -0,0 +1,30 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ # The Alter context PDU as defined in
4
+ # [The alter_context PDU](https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_01)
5
+ class AlterContext < BinData::Record
6
+ PTYPE = PTypes::ALTER_CONTEXT
7
+
8
+ endian :little
9
+
10
+ # PDU Header
11
+ pdu_header :pdu_header, label: 'PDU header'
12
+ ndr_uint16 :max_xmit_frag, label: 'Max transmit frag size', initial_value: RubySMB::Dcerpc::MAX_XMIT_FRAG
13
+ ndr_uint16 :max_recv_frag, label: 'Max receive frag size', initial_value: RubySMB::Dcerpc::MAX_RECV_FRAG
14
+ ndr_uint32 :assoc_group_id, label: 'Incarnation of client-server assoc group'
15
+ p_cont_list_t :p_context_list, label: 'Presentation context list', endpoint: -> { endpoint }
16
+
17
+ # Auth Verifier
18
+ sec_trailer :sec_trailer, onlyif: -> { pdu_header.auth_length > 0 }
19
+ string :auth_value,
20
+ onlyif: -> { pdu_header.auth_length > 0 },
21
+ read_length: -> { pdu_header.auth_length }
22
+
23
+ def initialize_instance
24
+ super
25
+ pdu_header.ptype = PTYPE
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,42 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ # The Alter context resp PDU as defined in
4
+ # [The alter_context_resp PDU](https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_02)
5
+
6
+ class AlterContextResp < BinData::Record
7
+ PTYPE = PTypes::ALTER_CONTEXT_RESP
8
+
9
+ # Presentation context negotiation results
10
+ ACCEPTANCE = 0
11
+ USER_REJECTION = 1
12
+ PROVIDER_REJECTION = 2
13
+
14
+ # Reasons for rejection of a context element
15
+ REASON_NOT_SPECIFIED = 0
16
+ ABSTRACT_SYNTAX_NOT_SUPPORTED = 1
17
+ PROPOSED_TRANSFER_SYNTAXES_NOT_SUPPORTED = 2
18
+ LOCAL_LIMIT_EXCEEDED = 3
19
+
20
+ endian :little
21
+
22
+ # PDU Header
23
+ pdu_header :pdu_header, label: 'PDU header'
24
+ ndr_uint16 :max_xmit_frag, label: 'Max transmit frag size', initial_value: RubySMB::Dcerpc::MAX_XMIT_FRAG
25
+ ndr_uint16 :max_recv_frag, label: 'Max receive frag size', initial_value: RubySMB::Dcerpc::MAX_RECV_FRAG
26
+ ndr_uint32 :assoc_group_id, label: 'Association group ID'
27
+ port_any_t :sec_addr, label: 'Secondary address'
28
+ p_result_list_t :p_result_list, label: 'Presentation context result list'
29
+
30
+ # Auth Verifier
31
+ sec_trailer :sec_trailer, onlyif: -> { pdu_header.auth_length > 0 }
32
+ string :auth_value,
33
+ onlyif: -> { pdu_header.auth_length > 0 },
34
+ read_length: -> { pdu_header.auth_length }
35
+
36
+ def initialize_instance
37
+ super
38
+ pdu_header.ptype = PTYPE
39
+ end
40
+ end
41
+ end
42
+ end
@@ -2,38 +2,6 @@ module RubySMB
2
2
  module Dcerpc
3
3
  # The Bind PDU as defined in
4
4
  # [The bind PDU](http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_03)
5
- class PContElemT < Ndr::NdrStruct
6
- default_parameter byte_align: 4
7
- endian :little
8
-
9
- ndr_uint16 :p_cont_id, label: 'Context ID'
10
- ndr_uint8 :n_transfer_syn, label: 'Number of transfer syntaxes', initial_value: 1
11
- ndr_uint8 :reserved
12
- p_syntax_id_t :abstract_syntax, label: 'Abstract syntax',
13
- uuid: -> { endpoint::UUID },
14
- ver_major: -> { endpoint::VER_MAJOR },
15
- ver_minor: -> { endpoint::VER_MINOR }
16
- array :transfer_syntaxes, label: 'Transfer syntax', type: :p_syntax_id_t,
17
- initial_length: -> { n_transfer_syn },
18
- uuid: -> { Ndr::UUID },
19
- ver_major: -> { Ndr::VER_MAJOR },
20
- ver_minor: -> { Ndr::VER_MINOR },
21
- byte_align: 4
22
- end
23
-
24
- class PContListT < Ndr::NdrStruct
25
- default_parameter byte_align: 4
26
- endian :little
27
-
28
- ndr_uint8 :n_context_elem, label: 'Number of context elements', initial_value: -> { 1 }
29
- ndr_uint8 :reserved
30
- ndr_uint16 :reserved2
31
- array :p_cont_elem, label: 'Presentation context elements', type: :p_cont_elem_t,
32
- initial_length: -> {n_context_elem},
33
- endpoint: -> {endpoint},
34
- byte_align: 4
35
- end
36
-
37
5
  class Bind < BinData::Record
38
6
  PTYPE = PTypes::BIND
39
7
 
@@ -41,9 +9,9 @@ module RubySMB
41
9
 
42
10
  # PDU Header
43
11
  pdu_header :pdu_header, label: 'PDU header'
44
- ndr_uint16 :max_xmit_frag, label: 'max transmit frag size', initial_value: RubySMB::Dcerpc::MAX_XMIT_FRAG
45
- ndr_uint16 :max_recv_frag, label: 'max receive frag size', initial_value: RubySMB::Dcerpc::MAX_RECV_FRAG
46
- ndr_uint32 :assoc_group_id, label: 'incarnation of client-server assoc group'
12
+ ndr_uint16 :max_xmit_frag, label: 'Max transmit frag size', initial_value: RubySMB::Dcerpc::MAX_XMIT_FRAG
13
+ ndr_uint16 :max_recv_frag, label: 'Max receive frag size', initial_value: RubySMB::Dcerpc::MAX_RECV_FRAG
14
+ ndr_uint32 :assoc_group_id, label: 'Incarnation of client-server assoc group'
47
15
  p_cont_list_t :p_context_list, label: 'Presentation context list', endpoint: -> { endpoint }
48
16
 
49
17
  # Auth Verifier
@@ -2,37 +2,6 @@ module RubySMB
2
2
  module Dcerpc
3
3
  # The Bind ACK PDU as defined in
4
4
  # [The bind_ack PDU](http://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_04_04)
5
-
6
- class PResultT < Ndr::NdrStruct
7
- default_parameter byte_align: 4
8
- endian :little
9
-
10
- ndr_uint16 :result, label: 'Presentation context negotiation results'
11
- ndr_uint16 :reason, label: 'Rejection reason'
12
- p_syntax_id_t :transfer_syntax, label: 'Presentation syntax ID',
13
- uuid: -> { Ndr::UUID },
14
- ver_major: -> { Ndr::VER_MAJOR },
15
- ver_minor: -> { Ndr::VER_MINOR }
16
- end
17
-
18
- class PResultListT < Ndr::NdrStruct
19
- default_parameter byte_align: 4
20
- endian :little
21
-
22
- ndr_uint8 :n_results, label: 'Number of results', initial_value: -> { p_results.size }
23
- ndr_uint8 :reserved
24
- ndr_uint16 :reserved2
25
- array :p_results, label: 'Results', type: :p_result_t, initial_length: -> { n_results }, byte_align: 4
26
- end
27
-
28
- class PortAnyT < Ndr::NdrStruct
29
- default_parameter byte_align: 2
30
- endian :little
31
-
32
- ndr_uint16 :str_length, label: 'Length', initial_value: -> { port_spec.to_binary_s.size }
33
- stringz :port_spec, label: 'Port string spec', byte_align: 2
34
- end
35
-
36
5
  class BindAck < BinData::Record
37
6
  PTYPE = PTypes::BIND_ACK
38
7
 
@@ -209,6 +209,10 @@ module RubySMB
209
209
  if auth_level &&
210
210
  [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
211
211
  set_integrity_privacy(dcerpc_req, auth_level: auth_level, auth_type: auth_type)
212
+ # Per the spec (MS_RPCE 2.2.2.11): start of the trailer should be a multiple of 16 bytes offset from the start of the stub
213
+ valid_offset = (((dcerpc_req.sec_trailer.abs_offset - dcerpc_req.stub.abs_offset) % 16))
214
+ valid_auth_pad = (dcerpc_req.sec_trailer.auth_pad_length == dcerpc_req.auth_pad.length)
215
+ raise Error::InvalidPacket unless valid_offset == 0 && valid_auth_pad
212
216
  end
213
217
 
214
218
  send_packet(dcerpc_req)
@@ -613,8 +613,8 @@ module RubySMB
613
613
  drs_bind_request = DrsBindRequest.new(pext_client: drs_extensions_int)
614
614
  response = dcerpc_request(
615
615
  drs_bind_request,
616
- auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
617
- auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
616
+ auth_level: @auth_level,
617
+ auth_type: @auth_type
618
618
  )
619
619
  begin
620
620
  drs_bind_response = DrsBindResponse.read(response)
@@ -640,8 +640,8 @@ module RubySMB
640
640
  drs_bind_request.pext_client.assign(drs_extensions_int)
641
641
  response = dcerpc_request(
642
642
  drs_bind_request,
643
- auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
644
- auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
643
+ auth_level: @auth_level,
644
+ auth_type: @auth_type
645
645
  )
646
646
  begin
647
647
  drs_bind_response = DrsBindResponse.read(response)
@@ -668,8 +668,8 @@ module RubySMB
668
668
  drs_unbind_request = DrsUnbindRequest.new(ph_drs: ph_drs)
669
669
  response = dcerpc_request(
670
670
  drs_unbind_request,
671
- auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
672
- auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
671
+ auth_level: @auth_level,
672
+ auth_type: @auth_type
673
673
  )
674
674
  begin
675
675
  drs_unbind_response = DrsUnbindResponse.read(response)
@@ -709,8 +709,8 @@ module RubySMB
709
709
  )
710
710
  response = dcerpc_request(
711
711
  drs_domain_controller_info_request,
712
- auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
713
- auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
712
+ auth_level: @auth_level,
713
+ auth_type: @auth_type
714
714
  )
715
715
  begin
716
716
  drs_domain_controller_info_response = DrsDomainControllerInfoResponse.read(response)
@@ -759,8 +759,8 @@ module RubySMB
759
759
  )
760
760
  response = dcerpc_request(
761
761
  drs_crack_names_request,
762
- auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
763
- auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
762
+ auth_level: @auth_level,
763
+ auth_type: @auth_type
764
764
  )
765
765
  begin
766
766
  drs_crack_names_response = DrsCrackNamesResponse.read(response)
@@ -790,8 +790,8 @@ module RubySMB
790
790
  unless @session_key
791
791
  raise RubySMB::Error::EncryptionError, 'Unable to decrypt attribute value: session key is empty'
792
792
  end
793
- encrypted_payload = EncryptedPayload.read(attribute)
794
793
 
794
+ encrypted_payload = EncryptedPayload.read(attribute)
795
795
  signature = OpenSSL::Digest::MD5.digest(@session_key + encrypted_payload.salt.to_binary_s)
796
796
  rc4 = OpenSSL::Cipher.new('rc4')
797
797
  rc4.decrypt
@@ -886,8 +886,8 @@ module RubySMB
886
886
 
887
887
  response = dcerpc_request(
888
888
  drs_get_nc_changes_request,
889
- auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
890
- auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
889
+ auth_level: @auth_level,
890
+ auth_type: @auth_type
891
891
  )
892
892
  begin
893
893
  drs_get_nc_changes_response = DrsGetNcChangesResponse.read(response)
@@ -0,0 +1,37 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ # The presentation context list and its element as defined in
4
+ # [Connection-oriented PDU Data Types - Declarations](https://pubs.opengroup.org/onlinepubs/9629399/chap12.htm#tagcjh_17_06_03_01)
5
+ class PContElemT < Ndr::NdrStruct
6
+ default_parameter byte_align: 4
7
+ endian :little
8
+
9
+ ndr_uint16 :p_cont_id, label: 'Context ID'
10
+ ndr_uint8 :n_transfer_syn, label: 'Number of transfer syntaxes', initial_value: 1
11
+ ndr_uint8 :reserved
12
+ p_syntax_id_t :abstract_syntax, label: 'Abstract syntax',
13
+ uuid: -> { endpoint::UUID },
14
+ ver_major: -> { endpoint::VER_MAJOR },
15
+ ver_minor: -> { endpoint::VER_MINOR }
16
+ array :transfer_syntaxes, label: 'Transfer syntax', type: :p_syntax_id_t,
17
+ initial_length: -> { n_transfer_syn },
18
+ uuid: -> { Ndr::UUID },
19
+ ver_major: -> { Ndr::VER_MAJOR },
20
+ ver_minor: -> { Ndr::VER_MINOR },
21
+ byte_align: 4
22
+ end
23
+
24
+ class PContListT < Ndr::NdrStruct
25
+ default_parameter byte_align: 4
26
+ endian :little
27
+
28
+ ndr_uint8 :n_context_elem, label: 'Number of context elements', initial_value: -> { 1 }
29
+ ndr_uint8 :reserved
30
+ ndr_uint16 :reserved2
31
+ array :p_cont_elem, label: 'Presentation context elements', type: :p_cont_elem_t,
32
+ initial_length: -> {n_context_elem},
33
+ endpoint: -> {endpoint},
34
+ byte_align: 4
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,13 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ class PResultListT < Ndr::NdrStruct
4
+ default_parameter byte_align: 4
5
+ endian :little
6
+
7
+ ndr_uint8 :n_results, label: 'Number of results', initial_value: -> { p_results.size }
8
+ ndr_uint8 :reserved
9
+ ndr_uint16 :reserved2
10
+ array :p_results, label: 'Results', type: :p_result_t, initial_length: -> { n_results }, byte_align: 4
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ class PResultT < Ndr::NdrStruct
4
+ default_parameter byte_align: 4
5
+ endian :little
6
+
7
+ ndr_uint16 :result, label: 'Presentation context negotiation results'
8
+ ndr_uint16 :reason, label: 'Rejection reason'
9
+ p_syntax_id_t :transfer_syntax, label: 'Presentation syntax ID',
10
+ uuid: -> { Ndr::UUID },
11
+ ver_major: -> { Ndr::VER_MAJOR },
12
+ ver_minor: -> { Ndr::VER_MINOR }
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ class PortAnyT < Ndr::NdrStruct
4
+ default_parameter byte_align: 2
5
+ endian :little
6
+
7
+ ndr_uint16 :str_length, label: 'Length', initial_value: -> { port_spec.to_binary_s.size }
8
+ stringz :port_spec, label: 'Port string spec', byte_align: 2, onlyif: -> { str_length > 0 }
9
+ end
10
+ end
11
+ end
@@ -103,9 +103,10 @@ module RubySMB
103
103
  end
104
104
  string :default
105
105
  end
106
- string :auth_pad,
106
+
107
+ string :auth_pad,
107
108
  onlyif: -> { has_auth_verifier? },
108
- length: -> { (16 - (stub.num_bytes % 16)) % 16 }
109
+ length: -> { calculate_padding_size }
109
110
 
110
111
  # Auth Verifier
111
112
  sec_trailer :sec_trailer, onlyif: -> { has_auth_verifier? }
@@ -113,6 +114,11 @@ module RubySMB
113
114
  onlyif: -> { has_auth_verifier? },
114
115
  read_length: -> { pdu_header.auth_length }
115
116
 
117
+ # Per the spec (MS_RPCE 2.2.2.11): start of the trailer should be a multiple of 16 bytes offset from the start of the stub
118
+ def calculate_padding_size
119
+ (16 - (stub.num_bytes % 16)) % 16
120
+ end
121
+
116
122
  def initialize_instance
117
123
  super
118
124
  pdu_header.ptype = PTYPE
@@ -125,7 +131,6 @@ module RubySMB
125
131
  def has_auth_verifier?
126
132
  self.pdu_header.auth_length > 0
127
133
  end
128
-
129
134
  end
130
135
  end
131
136
  end
@@ -18,7 +18,7 @@ module RubySMB
18
18
  string :stub, label: 'Stub', read_length: -> { stub_length }
19
19
  string :auth_pad,
20
20
  onlyif: -> { has_auth_verifier? },
21
- length: -> { (16 - (stub.num_bytes % 16)) % 16 }
21
+ length: -> { calculate_padding_size }
22
22
 
23
23
  # Auth Verifier
24
24
  sec_trailer :sec_trailer, onlyif: -> { has_auth_verifier? }
@@ -26,6 +26,11 @@ module RubySMB
26
26
  onlyif: -> { has_auth_verifier? },
27
27
  read_length: -> { pdu_header.auth_length }
28
28
 
29
+ # Per the spec (MS_RPCE 2.2.2.11): start of the trailer should be a multiple of 16 bytes offset from the start of the stub
30
+ def calculate_padding_size
31
+ (16 - (stub.num_bytes % 16)) % 16
32
+ end
33
+
29
34
  def initialize_instance
30
35
  super
31
36
  pdu_header.ptype = PTYPE
@@ -51,11 +51,128 @@ module RubySMB
51
51
  require 'ruby_smb/dcerpc/request'
52
52
  require 'ruby_smb/dcerpc/response'
53
53
  require 'ruby_smb/dcerpc/rpc_auth3'
54
+ require 'ruby_smb/dcerpc/port_any_t'
55
+ require 'ruby_smb/dcerpc/p_cont_list_t'
56
+ require 'ruby_smb/dcerpc/p_result_t'
57
+ require 'ruby_smb/dcerpc/p_result_list_t'
58
+ require 'ruby_smb/dcerpc/alter_context'
54
59
  require 'ruby_smb/dcerpc/bind'
55
60
  require 'ruby_smb/dcerpc/bind_ack'
61
+ require 'ruby_smb/dcerpc/alter_context_resp'
56
62
  require 'ruby_smb/dcerpc/print_system'
57
63
  require 'ruby_smb/dcerpc/encrypting_file_system'
58
64
 
65
+ # Initialize the auth provider using NTLM. This function should be overriden for other providers (e.g. Kerberos, etc.)
66
+ # @raise ArgumentError If @ntlm_client isn't initialized with a username and password.
67
+ # @return Serialized message for initializing the auth provider (NTLM, unless this class is extended/overridden)
68
+ def auth_provider_init
69
+ raise ArgumentError, "NTLM Client not initialized. Username and password must be provided" unless @ntlm_client
70
+ type1_message = @ntlm_client.init_context
71
+
72
+ type1_message.serialize
73
+ end
74
+
75
+ # Encrypt the value in dcerpc_req.stub, and add a valid signature to the request.
76
+ # This function modifies the request object in-place, and does not return anything.
77
+ # This function should be overriden for other providers (e.g. Kerberos, etc.)
78
+ # @param dcerpc_req [Request] The Request object to be encrypted and signed in-place
79
+ def auth_provider_encrypt_and_sign(dcerpc_req)
80
+ auth_type = dcerpc_req.sec_trailer.auth_type
81
+ auth_level = dcerpc_req.sec_trailer.auth_level
82
+ unless [RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT].include?(auth_type)
83
+ raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
84
+ end
85
+ plaintext = dcerpc_req.stub.to_binary_s
86
+ pad_length = get_auth_padding_length(plaintext.length)
87
+ dcerpc_req.auth_pad = "\x00" * pad_length
88
+ data_to_sign = plain_stub_with_padding = dcerpc_req.stub.to_binary_s + dcerpc_req.auth_pad.to_binary_s
89
+ dcerpc_req.sec_trailer.auth_pad_length = pad_length
90
+ if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
91
+ data_to_sign = dcerpc_req.to_binary_s[0..-(dcerpc_req.pdu_header.auth_length + 1)]
92
+ end
93
+
94
+ if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
95
+ encrypted = @ntlm_client.session.seal_message(plain_stub_with_padding)
96
+ set_encrypted_packet(dcerpc_req, encrypted, pad_length)
97
+ end
98
+ signature = @ntlm_client.session.sign_message(data_to_sign)
99
+
100
+ set_signature_on_packet(dcerpc_req, signature)
101
+ end
102
+
103
+ # Get the response's full stub value (which will include the auth-pad)
104
+ # @param dcerpc_response [Response] The Response object to extract from
105
+ # @return [String] The full stub, including auth_pad
106
+ def get_response_full_stub(dcerpc_response)
107
+ dcerpc_response.stub.to_binary_s + dcerpc_response.auth_pad.to_binary_s
108
+ end
109
+
110
+ # Decrypt the value in dcerpc_req.stub, and validate its signature.
111
+ # This function modifies the request object in-place, and returns whether the signature was valid.
112
+ # This function should be overriden for other providers (e.g. Kerberos, etc.)
113
+ # @param dcerpc_response [Response] The Response packet to decrypt and verify in-place
114
+ # @raise ArgumentError If the auth type is not NTLM
115
+ # @return [Boolean] Is the packet's signature valid?
116
+ def auth_provider_decrypt_and_verify(dcerpc_response)
117
+ auth_type = dcerpc_response.sec_trailer.auth_type
118
+ auth_level = dcerpc_response.sec_trailer.auth_level
119
+ unless [RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT].include?(auth_type)
120
+ raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
121
+ end
122
+ signature = dcerpc_response.auth_value
123
+ if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
124
+ encrypted_stub = get_response_full_stub(dcerpc_response)
125
+ plaintext = @ntlm_client.session.unseal_message(encrypted_stub)
126
+ set_decrypted_packet(dcerpc_response, plaintext)
127
+ end
128
+ data_to_check = dcerpc_response.stub.to_binary_s
129
+ if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
130
+ data_to_check = dcerpc_response.to_binary_s[0..-(dcerpc_response.pdu_header.auth_length + 1)]
131
+ end
132
+
133
+ @ntlm_client.session.verify_signature(signature, data_to_check)
134
+ end
135
+
136
+ # Completes local initialisation of @ntlm_client using the server's response
137
+ #
138
+ # @param type2_message [String] NTLM type 2 message sent from server
139
+ # @return [String] Type 3 message to be sent to the server to complete the NTLM handshake
140
+ def process_ntlm_type2(type2_message)
141
+ ntlmssp_offset = type2_message.index('NTLMSSP')
142
+ type2_blob = type2_message.slice(ntlmssp_offset..-1)
143
+ type2_b64_message = [type2_blob].pack('m')
144
+ type3_message = @ntlm_client.init_context(type2_b64_message)
145
+ auth3 = type3_message.serialize
146
+
147
+ @session_key = @ntlm_client.session_key
148
+ auth3
149
+ end
150
+
151
+ # Send a rpc_auth3 PDU that ends the authentication handshake.
152
+ # This function should be overriden for other providers (e.g. Kerberos, etc.)
153
+ #
154
+ # @param response [BindAck] the BindAck response packet
155
+ # @param options [Hash] Unused by the NTLM auth provider
156
+ def auth_provider_complete_handshake(response, options)
157
+ auth3 = process_ntlm_type2(response.auth_value)
158
+
159
+ rpc_auth3 = RpcAuth3.new
160
+ add_auth_verifier(rpc_auth3, auth3)
161
+ rpc_auth3.pdu_header.call_id = @call_id
162
+
163
+ # The server should not respond
164
+ send_packet(rpc_auth3)
165
+ @call_id += 1
166
+
167
+ nil
168
+ end
169
+
170
+ def force_set_auth_params(auth_type, auth_level)
171
+ @auth_type = auth_type
172
+ @auth_level = auth_level
173
+ end
174
+
175
+
59
176
  # Bind to the remote server interface endpoint. It takes care of adding
60
177
  # the necessary authentication verifier if `:auth_level` is set to
61
178
  # anything different than RPC_C_AUTHN_LEVEL_NONE
@@ -74,23 +191,16 @@ module RubySMB
74
191
  @call_id ||= 1
75
192
  bind_req = Bind.new(options)
76
193
  bind_req.pdu_header.call_id = @call_id
194
+ auth_type = options.fetch(:auth_type) { RPC_C_AUTHN_WINNT }
195
+ auth_level = options.fetch(:auth_level) { RPC_C_AUTHN_LEVEL_NONE }
77
196
 
78
- if options[:auth_level] && options[:auth_level] != RPC_C_AUTHN_LEVEL_NONE
79
- case options[:auth_type]
80
- when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
81
- @ctx_id = 0
82
- @auth_ctx_id_base = rand(0xFFFFFFFF)
83
- raise ArgumentError, "NTLM Client not initialized. Username and password must be provided" unless @ntlm_client
84
- type1_message = @ntlm_client.init_context
85
- auth = type1_message.serialize
86
- when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
87
- when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL
88
- # TODO
89
- raise NotImplementedError
90
- else
91
- raise ArgumentError, "Unsupported Auth Type: #{options[:auth_type]}"
92
- end
93
- add_auth_verifier(bind_req, auth, options[:auth_type], options[:auth_level])
197
+ force_set_auth_params(auth_type, auth_level)
198
+
199
+ if @auth_level != RPC_C_AUTHN_LEVEL_NONE
200
+ @ctx_id = 0
201
+ @auth_ctx_id_base = rand(0xFFFFFFFF)
202
+ auth = auth_provider_init
203
+ add_auth_verifier(bind_req, auth)
94
204
  end
95
205
 
96
206
  send_packet(bind_req)
@@ -110,17 +220,11 @@ module RubySMB
110
220
  self.max_buffer_size = dcerpc_response.max_xmit_frag
111
221
  @call_id = dcerpc_response.pdu_header.call_id
112
222
 
113
- if options[:auth_level] && options[:auth_level] != RPC_C_AUTHN_LEVEL_NONE
223
+ if auth_level != RPC_C_AUTHN_LEVEL_NONE
114
224
  # The number of legs needed to build the security context is defined
115
225
  # by the security provider
116
- # (see [2.2.1.1.7 Security Providers](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d4097450-c62f-484b-872f-ddf59a7a0d36))
117
- case options[:auth_type]
118
- when RPC_C_AUTHN_WINNT
119
- send_auth3(dcerpc_response, options[:auth_type], options[:auth_level])
120
- when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
121
- # TODO
122
- raise NotImplementedError
123
- end
226
+ # (see [2.2.1.1.7 Security Providers](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d4097450-c62f-484b-872f-ddf59a7a0d36))
227
+ auth_provider_complete_handshake(dcerpc_response, options)
124
228
  end
125
229
 
126
230
  dcerpc_response
@@ -156,16 +260,24 @@ module RubySMB
156
260
  nil
157
261
  end
158
262
 
263
+ def get_auth_padding_length(plaintext_len)
264
+ (16 - (plaintext_len % 16)) % 16
265
+ end
266
+
159
267
  # Add the authentication verifier to a Request packet. This includes a
160
268
  # sec trailer and the signature of the packet. This also encrypts the
161
269
  # Request stub if privacy is required (`:auth_level` option is
162
270
  # RPC_C_AUTHN_LEVEL_PKT_PRIVACY).
163
271
  #
164
272
  # @param dcerpc_req [Request] the Request packet to be updated
165
- # @param opts [Hash] the authenticaiton options: `:auth_type` and `:auth_level`
273
+ # @param opts [Hash] the authentication options: `:auth_type` and `:auth_level`
166
274
  # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
167
275
  # @raise [ArgumentError] if `:auth_type` is unknown
168
276
  def set_integrity_privacy(dcerpc_req, auth_level:, auth_type:)
277
+ unless [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
278
+ raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
279
+ end
280
+
169
281
  dcerpc_req.sec_trailer = {
170
282
  auth_type: auth_type,
171
283
  auth_level: auth_level,
@@ -174,35 +286,30 @@ module RubySMB
174
286
  dcerpc_req.auth_value = ' ' * 16
175
287
  dcerpc_req.pdu_header.auth_length = 16
176
288
 
177
- data_to_sign = plain_stub = dcerpc_req.stub.to_binary_s + dcerpc_req.auth_pad.to_binary_s
178
- if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
179
- data_to_sign = dcerpc_req.to_binary_s[0..-(dcerpc_req.pdu_header.auth_length + 1)]
180
- end
181
-
182
- encrypted_stub = ''
183
- if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
184
- case auth_type
185
- when RPC_C_AUTHN_NONE
186
- when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
187
- encrypted_stub = @ntlm_client.session.seal_message(plain_stub)
188
- when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
189
- # TODO
190
- raise NotImplementedError
191
- else
192
- raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
193
- end
194
- end
289
+ auth_provider_encrypt_and_sign(dcerpc_req)
290
+ end
195
291
 
196
- signature = @ntlm_client.session.sign_message(data_to_sign)
292
+ def set_signature_on_packet(dcerpc_req, signature)
293
+ dcerpc_req.auth_value = signature
294
+ dcerpc_req.pdu_header.auth_length = signature.size
295
+ end
197
296
 
297
+ def set_encrypted_packet(dcerpc_req, encrypted_stub, pad_length)
198
298
  unless encrypted_stub.empty?
199
- pad_length = dcerpc_req.sec_trailer.auth_pad_length.to_i
200
299
  dcerpc_req.enable_encrypted_stub
201
- dcerpc_req.stub = encrypted_stub[0..-(pad_length + 1)]
202
- dcerpc_req.auth_pad = encrypted_stub[-(pad_length)..-1]
300
+ dcerpc_req.stub = encrypted_stub[0..-(pad_length+1)]
301
+ if pad_length != 0
302
+ dcerpc_req.auth_pad = encrypted_stub[-(pad_length)..-1]
303
+ end
304
+ end
305
+ end
306
+
307
+ def set_decrypted_packet(dcerpc_response, decrypted_stub)
308
+ unless decrypted_stub.empty?
309
+ pad_length = dcerpc_response.sec_trailer.auth_pad_length.to_i
310
+ dcerpc_response.stub = decrypted_stub[0..-(pad_length + 1)]
311
+ dcerpc_response.auth_pad = decrypted_stub[-(pad_length + 1)..-1]
203
312
  end
204
- dcerpc_req.auth_value = signature
205
- dcerpc_req.pdu_header.auth_length = signature.size
206
313
  end
207
314
 
208
315
  # Process the security context received in a response. It decrypts the
@@ -214,39 +321,18 @@ module RubySMB
214
321
  #
215
322
  # @param dcerpc_response [Response] the Response packet
216
323
  # containing the security context to process
217
- # @param opts [Hash] the authenticaiton options: `:auth_type` and
324
+ # @param opts [Hash] the authentication options: `:auth_type` and
218
325
  # `:auth_level`. To enable errors when signature check fails, set the
219
326
  # `:raise_signature_error` option to true
220
327
  # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
221
328
  # @raise [Error::CommunicationError] if socket-related error occurs
222
329
  def handle_integrity_privacy(dcerpc_response, auth_level:, auth_type:, raise_signature_error: false)
223
- decrypted_stub = ''
224
- if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
225
- encrypted_stub = dcerpc_response.stub.to_binary_s + dcerpc_response.auth_pad.to_binary_s
226
- case auth_type
227
- when RPC_C_AUTHN_NONE
228
- when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
229
- decrypted_stub = @ntlm_client.session.unseal_message(encrypted_stub)
230
- when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
231
- # TODO
232
- raise NotImplementedError
233
- else
234
- raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
235
- end
236
- end
237
-
238
- unless decrypted_stub.empty?
239
- pad_length = dcerpc_response.sec_trailer.auth_pad_length.to_i
240
- dcerpc_response.stub = decrypted_stub[0..-(pad_length + 1)]
241
- dcerpc_response.auth_pad = decrypted_stub[-(pad_length)..-1]
330
+ unless [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
331
+ raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
242
332
  end
333
+ signature_valid = auth_provider_decrypt_and_verify(dcerpc_response)
243
334
 
244
- signature = dcerpc_response.auth_value
245
- data_to_check = dcerpc_response.stub.to_binary_s
246
- if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
247
- data_to_check = dcerpc_response.to_binary_s[0..-(dcerpc_response.pdu_header.auth_length + 1)]
248
- end
249
- unless @ntlm_client.session.verify_signature(signature, data_to_check)
335
+ unless signature_valid
250
336
  if raise_signature_error
251
337
  raise Error::InvalidPacket.new(
252
338
  "Wrong packet signature received (set `raise_signature_error` to false to ignore)"
@@ -264,12 +350,10 @@ module RubySMB
264
350
  #
265
351
  # @param req [BinData::Record] the request to be updated
266
352
  # @param auth [String] the authentication data
267
- # @param auth_type [Integer] the authentication type
268
- # @param auth_level [Integer] the authentication level
269
- def add_auth_verifier(req, auth, auth_type, auth_level)
353
+ def add_auth_verifier(req, auth)
270
354
  req.sec_trailer = {
271
- auth_type: auth_type,
272
- auth_level: auth_level,
355
+ auth_type: @auth_type,
356
+ auth_level: @auth_level,
273
357
  auth_context_id: @ctx_id + @auth_ctx_id_base
274
358
  }
275
359
  req.auth_value = auth
@@ -277,46 +361,5 @@ module RubySMB
277
361
 
278
362
  nil
279
363
  end
280
-
281
- def process_ntlm_type2(type2_message)
282
- ntlmssp_offset = type2_message.index('NTLMSSP')
283
- type2_blob = type2_message.slice(ntlmssp_offset..-1)
284
- type2_b64_message = [type2_blob].pack('m')
285
- type3_message = @ntlm_client.init_context(type2_b64_message)
286
- auth3 = type3_message.serialize
287
-
288
- @session_key = @ntlm_client.session_key
289
- auth3
290
- end
291
-
292
- # Send a rpc_auth3 PDU that ends the authentication handshake.
293
- #
294
- # @param response [BindAck] the BindAck response packet
295
- # @param auth_type [Integer] the authentication type
296
- # @param auth_level [Integer] the authentication level
297
- # @raise [ArgumentError] if `:auth_type` is unknown
298
- # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
299
- def send_auth3(response, auth_type, auth_level)
300
- case auth_type
301
- when RPC_C_AUTHN_NONE
302
- when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
303
- auth3 = process_ntlm_type2(response.auth_value)
304
- when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
305
- # TODO
306
- raise NotImplementedError
307
- else
308
- raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
309
- end
310
-
311
- rpc_auth3 = RpcAuth3.new
312
- add_auth_verifier(rpc_auth3, auth3, auth_type, auth_level)
313
- rpc_auth3.pdu_header.call_id = @call_id
314
-
315
- # The server should not respond
316
- send_packet(rpc_auth3)
317
- @call_id += 1
318
-
319
- nil
320
- end
321
364
  end
322
365
  end
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '3.2.5'.freeze
2
+ VERSION = '3.2.6'.freeze
3
3
  end
@@ -9,7 +9,12 @@ RSpec.describe RubySMB::Dcerpc::Client do
9
9
  let(:endpoint) { RubySMB::Dcerpc::Samr }
10
10
 
11
11
  subject(:client) { described_class.new(host, endpoint) }
12
- subject(:auth_client) { described_class.new(host, endpoint, username: 'testuser', password: '1234') }
12
+ subject(:auth_client) do
13
+ result = described_class.new(host, endpoint, username: 'testuser', password: '1234')
14
+ result.force_set_auth_params(RubySMB::Dcerpc::RPC_C_AUTHN_WINNT, RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
15
+
16
+ result
17
+ end
13
18
 
14
19
  it { is_expected.to respond_to :domain }
15
20
  it { is_expected.to respond_to :local_workstation }
@@ -135,21 +140,21 @@ RSpec.describe RubySMB::Dcerpc::Client do
135
140
  describe '#add_auth_verifier' do
136
141
  let(:req) { RubySMB::Dcerpc::Bind.new }
137
142
  let(:auth_type) { RubySMB::Dcerpc::RPC_C_AUTHN_WINNT }
138
- let(:auth_level) { 0 }
143
+ let(:auth_level) { RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY }
139
144
  let(:auth) { 'serialized auth value' }
140
145
 
141
146
  it 'sets #auth_value field to the expected value' do
142
- auth_client.add_auth_verifier(req, auth, auth_type, auth_level)
147
+ auth_client.add_auth_verifier(req, auth)
143
148
  expect(req.auth_value).to eq(auth)
144
149
  end
145
150
 
146
151
  it 'sets PDUHeader #auth_length field to the expected value' do
147
- auth_client.add_auth_verifier(req, auth, auth_type, auth_level)
152
+ auth_client.add_auth_verifier(req, auth)
148
153
  expect(req.pdu_header.auth_length).to eq(auth.length)
149
154
  end
150
155
 
151
156
  it 'sets #sec_trailer field to the expected value' do
152
- auth_client.add_auth_verifier(req, auth, auth_type, auth_level)
157
+ auth_client.add_auth_verifier(req, auth)
153
158
  expect(req.sec_trailer.auth_type).to eq(auth_type)
154
159
  expect(req.sec_trailer.auth_level).to eq(auth_level)
155
160
  expect(req.sec_trailer.auth_context_id).to eq(auth_client.instance_variable_get(:@auth_ctx_id_base))
@@ -202,29 +207,29 @@ RSpec.describe RubySMB::Dcerpc::Client do
202
207
  end
203
208
 
204
209
  it 'add an auth verifier to the RpcAuth3 packet' do
205
- auth_client.send_auth3(bindack, auth_type, auth_level)
206
- expect(auth_client).to have_received(:add_auth_verifier).with(rpc_auth3, auth3, auth_type, auth_level)
210
+ auth_client.auth_provider_complete_handshake(bindack, auth_type: auth_type, auth_level: auth_level)
211
+ expect(auth_client).to have_received(:add_auth_verifier).with(rpc_auth3, auth3)
207
212
  end
208
213
 
209
214
  it 'sets the PDUHeader #call_id to the expected value' do
210
215
  auth_client.instance_variable_set(:@call_id, 56)
211
- auth_client.send_auth3(bindack, auth_type, auth_level)
216
+ auth_client.auth_provider_complete_handshake(bindack, auth_type: auth_type, auth_level: auth_level)
212
217
  expect(rpc_auth3.pdu_header.call_id).to eq(56)
213
218
  end
214
219
 
215
220
  it 'sends the RpcAuth3 packet' do
216
- auth_client.send_auth3(bindack, auth_type, auth_level)
221
+ auth_client.auth_provider_complete_handshake(bindack, auth_type: auth_type, auth_level: auth_level)
217
222
  expect(auth_client).to have_received(:send_packet).with(rpc_auth3)
218
223
  end
219
224
 
220
225
  it 'increments #call_id' do
221
- auth_client.send_auth3(bindack, auth_type, auth_level)
226
+ auth_client.auth_provider_complete_handshake(bindack, auth_type: auth_type, auth_level: auth_level)
222
227
  expect(auth_client.instance_variable_get(:@call_id)).to eq(2)
223
228
  end
224
229
 
225
230
  context 'with RPC_C_AUTHN_WINNT auth_type' do
226
231
  it 'processes NTLM type2 message' do
227
- auth_client.send_auth3(bindack, auth_type, auth_level)
232
+ auth_client.auth_provider_complete_handshake(bindack, auth_type: auth_type, auth_level: auth_level)
228
233
  expect(auth_client).to have_received(:process_ntlm_type2).with(auth)
229
234
  end
230
235
  end
@@ -300,7 +305,7 @@ RSpec.describe RubySMB::Dcerpc::Client do
300
305
 
301
306
  context 'with RPC_C_AUTHN_WINNT auth_type' do
302
307
  let(:kwargs) do {
303
- auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_DEFAULT,
308
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
304
309
  auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
305
310
  }
306
311
  end
@@ -310,7 +315,7 @@ RSpec.describe RubySMB::Dcerpc::Client do
310
315
  allow(client.ntlm_client).to receive(:init_context).and_return(type1_message)
311
316
  allow(type1_message).to receive(:serialize).and_return(auth)
312
317
  allow(client).to receive(:add_auth_verifier)
313
- allow(client).to receive(:send_auth3)
318
+ allow(client).to receive(:auth_provider_complete_handshake)
314
319
  end
315
320
 
316
321
  it 'raises an exception if the NTLM client is not initialized' do
@@ -320,12 +325,12 @@ RSpec.describe RubySMB::Dcerpc::Client do
320
325
 
321
326
  it 'adds the auth verifier with a NTLM type1 message' do
322
327
  client.bind(**kwargs)
323
- expect(client).to have_received(:add_auth_verifier).with(bind_req, auth, kwargs[:auth_type], kwargs[:auth_level])
328
+ expect(client).to have_received(:add_auth_verifier).with(bind_req, auth)
324
329
  end
325
330
 
326
331
  it 'sends an auth3 request' do
327
332
  client.bind(**kwargs)
328
- expect(client).to have_received(:send_auth3).with(bindack_response, kwargs[:auth_type], kwargs[:auth_level])
333
+ expect(client).to have_received(:auth_provider_complete_handshake).with(bindack_response, auth_type: kwargs[:auth_type], auth_level: kwargs[:auth_level])
329
334
  end
330
335
  end
331
336
  end
@@ -372,10 +377,14 @@ RSpec.describe RubySMB::Dcerpc::Client do
372
377
 
373
378
  describe '#set_integrity_privacy' do
374
379
  let(:dcerpc_req) do
375
- RubySMB::Dcerpc::Request.new(
380
+ req = RubySMB::Dcerpc::Request.new(
376
381
  { opnum: RubySMB::Dcerpc::Winreg::REG_ENUM_KEY },
377
382
  { endpoint: 'Winreg' }
378
383
  )
384
+ req.sec_trailer.auth_pad_length = 8
385
+ req.auth_pad = "\x00" * 8
386
+
387
+ req
379
388
  end
380
389
  let(:auth_level) { RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY }
381
390
  let(:auth_type) { RubySMB::Dcerpc::RPC_C_AUTHN_WINNT }
@@ -656,6 +665,8 @@ RSpec.describe RubySMB::Dcerpc::Client do
656
665
  # Make sure the encrypted stub includes the correct pad to make sure sec_trailer is 16-bytes aligned
657
666
  allow(session).to receive(:unseal_message).and_return(decrypted_stub + auth_pad)
658
667
  allow(session).to receive(:verify_signature).and_return true
668
+ dcerpc_res.sec_trailer.auth_type = auth_type
669
+ dcerpc_res.sec_trailer.auth_level = auth_level
659
670
  end
660
671
 
661
672
  it 'verifies the signature' do
@@ -698,6 +709,8 @@ RSpec.describe RubySMB::Dcerpc::Client do
698
709
  context 'without RPC_C_AUTHN_LEVEL_PKT_PRIVACY auth_level' do
699
710
  it 'does not encrypt the stub' do
700
711
  plain_stub = dcerpc_res.stub.to_binary_s
712
+ dcerpc_res.sec_trailer.auth_level = RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_INTEGRITY
713
+ dcerpc_res.sec_trailer.auth_type = RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
701
714
  auth_client.handle_integrity_privacy(dcerpc_res, auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, auth_type: auth_type)
702
715
  expect(dcerpc_res.stub).to eq(plain_stub)
703
716
  expect(session).to_not have_received(:unseal_message)
@@ -706,6 +719,8 @@ RSpec.describe RubySMB::Dcerpc::Client do
706
719
 
707
720
  context 'with an unsupported auth_level' do
708
721
  it 'raises an Argument exception' do
722
+ dcerpc_res.sec_trailer.auth_level = RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_INTEGRITY
723
+ dcerpc_res.sec_trailer.auth_type = 88
709
724
  expect { auth_client.handle_integrity_privacy(dcerpc_res, auth_level: auth_level, auth_type: 88) }.to raise_error(ArgumentError)
710
725
  end
711
726
  end
@@ -6,7 +6,10 @@ RSpec.describe RubySMB::Dcerpc::Drsr do
6
6
  end
7
7
 
8
8
  let(:drsr) do
9
- RubySMB::Dcerpc::Client.new('1.2.3.4', RubySMB::Dcerpc::Drsr)
9
+ drsr = RubySMB::Dcerpc::Client.new('1.2.3.4', RubySMB::Dcerpc::Drsr)
10
+ drsr.force_set_auth_params(RubySMB::Dcerpc::RPC_C_AUTHN_WINNT, RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY)
11
+
12
+ drsr
10
13
  end
11
14
 
12
15
  describe described_class::DrsHandle do
@@ -134,12 +134,6 @@ RSpec.describe RubySMB::Dcerpc::Request do
134
134
  packet.pdu_header.auth_length = 10
135
135
  expect(packet.auth_pad?).to be true
136
136
  end
137
-
138
- it 'makes sure #sec_trailer is 16-bytes aligned with the begining of the PDU body (stub)' do
139
- packet.pdu_header.auth_length = 6
140
- packet.stub = 'A' * rand(0xFF)
141
- expect((packet.sec_trailer.abs_offset - packet.stub.abs_offset) % 16).to eq(0)
142
- end
143
137
  end
144
138
 
145
139
  describe '#sec_trailer' do
@@ -77,12 +77,6 @@ RSpec.describe RubySMB::Dcerpc::Response do
77
77
  packet.pdu_header.auth_length = 10
78
78
  expect(packet.auth_pad?).to be true
79
79
  end
80
-
81
- it 'makes sure #sec_trailer is 16-bytes aligned with the begining of the PDU body (stub)' do
82
- packet.pdu_header.auth_length = 6
83
- packet.stub = 'A' * rand(0xFF)
84
- expect((packet.sec_trailer.abs_offset - packet.stub.abs_offset) % 16).to eq(0)
85
- end
86
80
  end
87
81
 
88
82
  describe '#sec_trailer' do
@@ -36,20 +36,6 @@ RSpec.describe RubySMB::Dcerpc::SecTrailer do
36
36
  expect(packet.auth_pad_length).to eq(0)
37
37
  end
38
38
 
39
- context 'when the parent structure has an #auth_pad field' do
40
- let(:pad) { 'A' * rand(0xFF) }
41
- let(:packet_with_parent) do
42
- Class.new(BinData::Record) do
43
- string :auth_pad
44
- sec_trailer :sec_trailer
45
- end.new(auth_pad: pad)
46
- end
47
-
48
- it 'has a value equal to the size of the #auth_pad field' do
49
- expect(packet_with_parent.sec_trailer.auth_pad_length).to eq(pad.size)
50
- end
51
- end
52
-
53
39
  context 'when the parent structure does not have an #auth_pad field' do
54
40
  let(:pad) { 'A' * rand(0xFF) }
55
41
  let(:packet_with_parent) do
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_smb
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.5
4
+ version: 3.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Metasploit Hackers
@@ -97,7 +97,7 @@ cert_chain:
97
97
  EknWpNgVhohbot1lfVAMmIhdtOVaRVcQQixWPwprDj/ydB8ryDMDosIMcw+fkoXU
98
98
  9GJsSaSRRYQ9UUkVL27b64okU8D48m8=
99
99
  -----END CERTIFICATE-----
100
- date: 2023-03-09 00:00:00.000000000 Z
100
+ date: 2023-10-25 00:00:00.000000000 Z
101
101
  dependencies:
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: redcarpet
@@ -256,6 +256,7 @@ files:
256
256
  - LICENSE.txt
257
257
  - README.md
258
258
  - Rakefile
259
+ - cortex.yaml
259
260
  - examples/anonymous_auth.rb
260
261
  - examples/append_file.rb
261
262
  - examples/auth_capture.rb
@@ -295,6 +296,8 @@ files:
295
296
  - lib/ruby_smb/create_actions.rb
296
297
  - lib/ruby_smb/crypto.rb
297
298
  - lib/ruby_smb/dcerpc.rb
299
+ - lib/ruby_smb/dcerpc/alter_context.rb
300
+ - lib/ruby_smb/dcerpc/alter_context_resp.rb
298
301
  - lib/ruby_smb/dcerpc/bind.rb
299
302
  - lib/ruby_smb/dcerpc/bind_ack.rb
300
303
  - lib/ruby_smb/dcerpc/client.rb
@@ -343,8 +346,12 @@ files:
343
346
  - lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb
344
347
  - lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb
345
348
  - lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb
349
+ - lib/ruby_smb/dcerpc/p_cont_list_t.rb
350
+ - lib/ruby_smb/dcerpc/p_result_list_t.rb
351
+ - lib/ruby_smb/dcerpc/p_result_t.rb
346
352
  - lib/ruby_smb/dcerpc/p_syntax_id_t.rb
347
353
  - lib/ruby_smb/dcerpc/pdu_header.rb
354
+ - lib/ruby_smb/dcerpc/port_any_t.rb
348
355
  - lib/ruby_smb/dcerpc/print_system.rb
349
356
  - lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_request.rb
350
357
  - lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_response.rb
metadata.gz.sig CHANGED
Binary file