ruby_smb 3.2.5 → 3.2.6

Sign up to get free protection for your applications and to get access to all the features.
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