ruby_smb 3.1.7 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -30,10 +30,18 @@ module RubySMB
30
30
  extend RubySMB::Dcerpc::Wkssvc
31
31
  when 'netdfs', '\\netdfs'
32
32
  extend RubySMB::Dcerpc::Dfsnm
33
+ when 'cert', '\\cert'
34
+ extend RubySMB::Dcerpc::Icpr
33
35
  end
34
36
  super(tree: tree, response: response, name: name)
35
37
  end
36
38
 
39
+ def bind(options={})
40
+ @size = 1024
41
+ @ntlm_client = @tree.client.ntlm_client
42
+ super
43
+ end
44
+
37
45
  # Performs a peek operation on the named pipe
38
46
  #
39
47
  # @param peek_size [Integer] Amount of data to peek
@@ -98,6 +106,11 @@ module RubySMB
98
106
  options.merge!(endpoint: stub_packet.class.name.split('::').at(-2))
99
107
  dcerpc_request = RubySMB::Dcerpc::Request.new({ opnum: stub_packet.opnum }, options)
100
108
  dcerpc_request.stub.read(stub_packet.to_binary_s)
109
+ if options[:auth_level] &&
110
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
111
+ set_integrity_privacy(dcerpc_request, auth_level: options[:auth_level], auth_type: options[:auth_type])
112
+ end
113
+
101
114
  trans_nmpipe_request = RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest.new(options)
102
115
  @tree.set_header_fields(trans_nmpipe_request)
103
116
  trans_nmpipe_request.set_fid(@fid)
@@ -124,22 +137,33 @@ module RubySMB
124
137
  unless dcerpc_response.pdu_header.pfc_flags.first_frag == 1
125
138
  raise RubySMB::Dcerpc::Error::InvalidPacket, "Not the first fragment"
126
139
  end
140
+ if options[:auth_level] &&
141
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
142
+ handle_integrity_privacy(dcerpc_response, auth_level: options[:auth_level], auth_type: options[:auth_type])
143
+ end
127
144
  stub_data = dcerpc_response.stub.to_s
128
145
 
129
146
  loop do
130
147
  break if dcerpc_response.pdu_header.pfc_flags.last_frag == 1
131
148
  raw_data = read(bytes: @tree.client.max_buffer_size)
132
149
  dcerpc_response = dcerpc_response_from_raw_response(raw_data)
150
+ if options[:auth_level] &&
151
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
152
+ handle_integrity_privacy(dcerpc_response, auth_level: options[:auth_level], auth_type: options[:auth_type])
153
+ end
133
154
  stub_data << dcerpc_response.stub.to_s
134
155
  end
135
156
  stub_data
136
157
  else
137
158
  dcerpc_response = dcerpc_response_from_raw_response(raw_data)
159
+ if options[:auth_level] &&
160
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
161
+ handle_integrity_privacy(dcerpc_response, auth_level: options[:auth_level], auth_type: options[:auth_type])
162
+ end
138
163
  dcerpc_response.stub.to_s
139
164
  end
140
165
  end
141
166
 
142
-
143
167
  private
144
168
 
145
169
  def dcerpc_response_from_raw_response(raw_data)
@@ -21,7 +21,11 @@ module RubySMB
21
21
  uint8 :reserved, label: 'Reserved Space', initial_value: 0x00
22
22
  share_flags :share_flags
23
23
  share_capabilities :capabilities
24
- file_access_mask :maximal_access, label: 'Maximal Access'
24
+ choice :maximal_access, label: 'Maximal Access', selection: -> { share_type } do
25
+ file_access_mask SMB2_SHARE_TYPE_PIPE
26
+ file_access_mask SMB2_SHARE_TYPE_PRINT
27
+ directory_access_mask SMB2_SHARE_TYPE_DISK
28
+ end
25
29
 
26
30
  def initialize_instance
27
31
  super
@@ -27,10 +27,18 @@ module RubySMB
27
27
  extend RubySMB::Dcerpc::Wkssvc
28
28
  when 'netdfs', '\\netdfs'
29
29
  extend RubySMB::Dcerpc::Dfsnm
30
+ when 'cert', '\\cert'
31
+ extend RubySMB::Dcerpc::Icpr
30
32
  end
31
33
  super(tree: tree, response: response, name: name)
32
34
  end
33
35
 
36
+ def bind(options={})
37
+ @size = 1024
38
+ @ntlm_client = @tree.client.ntlm_client
39
+ super
40
+ end
41
+
34
42
  # Performs a peek operation on the named pipe
35
43
  #
36
44
  # @param peek_size [Integer] Amount of data to peek
@@ -91,6 +99,11 @@ module RubySMB
91
99
  options.merge!(endpoint: stub_packet.class.name.split('::').at(-2))
92
100
  dcerpc_request = RubySMB::Dcerpc::Request.new({ opnum: stub_packet.opnum }, options)
93
101
  dcerpc_request.stub.read(stub_packet.to_binary_s)
102
+ if options[:auth_level] &&
103
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
104
+ set_integrity_privacy(dcerpc_request, auth_level: options[:auth_level], auth_type: options[:auth_type])
105
+ end
106
+
94
107
  ioctl_send_recv(dcerpc_request, options)
95
108
  end
96
109
 
@@ -122,17 +135,29 @@ module RubySMB
122
135
  unless dcerpc_response.pdu_header.pfc_flags.first_frag == 1
123
136
  raise RubySMB::Dcerpc::Error::InvalidPacket, "Not the first fragment"
124
137
  end
138
+ if options[:auth_level] &&
139
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
140
+ handle_integrity_privacy(dcerpc_response, auth_level: options[:auth_level], auth_type: options[:auth_type])
141
+ end
125
142
  stub_data = dcerpc_response.stub.to_s
126
143
 
127
144
  loop do
128
145
  break if dcerpc_response.pdu_header.pfc_flags.last_frag == 1
129
146
  raw_data = read(bytes: @tree.client.max_buffer_size)
130
147
  dcerpc_response = dcerpc_response_from_raw_response(raw_data)
148
+ if options[:auth_level] &&
149
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
150
+ handle_integrity_privacy(dcerpc_response, auth_level: options[:auth_level], auth_type: options[:auth_type])
151
+ end
131
152
  stub_data << dcerpc_response.stub.to_s
132
153
  end
133
154
  stub_data
134
155
  else
135
156
  dcerpc_response = dcerpc_response_from_raw_response(raw_data)
157
+ if options[:auth_level] &&
158
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(options[:auth_level])
159
+ handle_integrity_privacy(dcerpc_response, auth_level: options[:auth_level], auth_type: options[:auth_type])
160
+ end
136
161
  dcerpc_response.stub.to_s
137
162
  end
138
163
  end
@@ -0,0 +1,15 @@
1
+ module RubySMB
2
+ module Utils
3
+
4
+ def self.safe_encode(str, encoding)
5
+ str.encode(encoding)
6
+ rescue EncodingError
7
+ if str.encoding == ::Encoding::ASCII_8BIT
8
+ str.dup.force_encoding(encoding)
9
+ else
10
+ raise
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '3.1.7'.freeze
2
+ VERSION = '3.2.1'.freeze
3
3
  end
data/lib/ruby_smb.rb CHANGED
@@ -6,11 +6,13 @@ require 'openssl/ccm'
6
6
  require 'openssl/cmac'
7
7
  require 'windows_error'
8
8
  require 'windows_error/nt_status'
9
+ require 'ruby_smb/ntlm/custom/ntlm'
9
10
  # A packet parsing and manipulation library for the SMB1 and SMB2 protocols
10
11
  #
11
12
  # [[MS-SMB] Server Message Block (SMB) Protocol Version 1](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
12
13
  # [[MS-SMB2] Server Message Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
13
14
  module RubySMB
15
+ require 'ruby_smb/utils'
14
16
  require 'ruby_smb/error'
15
17
  require 'ruby_smb/create_actions'
16
18
  require 'ruby_smb/dispositions'
@@ -0,0 +1,64 @@
1
+ RSpec.describe RubySMB::Dcerpc::Icpr::CertServerRequestRequest do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :dw_flags }
5
+ it { is_expected.to respond_to :pwsz_authority }
6
+ it { is_expected.to respond_to :pdw_request_id }
7
+ it { is_expected.to respond_to :pctb_attribs }
8
+ it { is_expected.to respond_to :pctb_request }
9
+ it { is_expected.to respond_to :opnum }
10
+
11
+ it 'is little endian' do
12
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
13
+ end
14
+ it 'is a BinData::Record' do
15
+ expect(packet).to be_a(BinData::Record)
16
+ end
17
+ describe '#dw_flags' do
18
+ it 'is a NdrUint32 structure' do
19
+ expect(packet.dw_flags).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
20
+ end
21
+ end
22
+ describe '#pwsz_authority' do
23
+ it 'is a NdrWideStringzPtr structure' do
24
+ expect(packet.pwsz_authority).to be_a RubySMB::Dcerpc::Ndr::NdrWideStringzPtr
25
+ end
26
+ end
27
+ describe '#pdw_request_id' do
28
+ it 'is a NdrUint32 structure' do
29
+ expect(packet.pdw_request_id).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
30
+ end
31
+ end
32
+ describe '#pctb_attribs' do
33
+ it 'is a CertTransBlob structure' do
34
+ expect(packet.pctb_attribs).to be_a RubySMB::Dcerpc::Icpr::CertTransBlob
35
+ end
36
+ end
37
+ describe '#pctb_request' do
38
+ it 'is a CertTransBlob structure' do
39
+ expect(packet.pctb_request).to be_a RubySMB::Dcerpc::Icpr::CertTransBlob
40
+ end
41
+ end
42
+ describe '#initialize_instance' do
43
+ it 'sets #opnum to CERT_SERVER_REQUEST constant' do
44
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Icpr::CERT_SERVER_REQUEST)
45
+ end
46
+ end
47
+ it 'reads itself' do
48
+ new_packet = described_class.new({
49
+ dw_flags: 0,
50
+ pwsz_authority: 'DC-CA',
51
+ pdw_request_id: 1,
52
+ pctb_attribs: { pb: 'ATTRIBUTES'.bytes },
53
+ pctb_request: { pb: 'REQUEST'.bytes }
54
+ })
55
+ expected_output = {
56
+ dw_flags: 0,
57
+ pwsz_authority: 'DC-CA'.encode('utf-16le'),
58
+ pdw_request_id: 1,
59
+ pctb_attribs: { cb: 10, pb: 'ATTRIBUTES'.bytes },
60
+ pctb_request: { cb: 7, pb: 'REQUEST'.bytes }
61
+ }
62
+ expect(packet.read(new_packet.to_binary_s)).to eq(expected_output)
63
+ end
64
+ end
@@ -0,0 +1,71 @@
1
+ RSpec.describe RubySMB::Dcerpc::Icpr::CertServerRequestResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :pdw_request_id }
5
+ it { is_expected.to respond_to :pdw_disposition }
6
+ it { is_expected.to respond_to :pctb_cert }
7
+ it { is_expected.to respond_to :pctb_encoded_cert }
8
+ it { is_expected.to respond_to :pctb_disposition_message }
9
+ it { is_expected.to respond_to :error_status }
10
+
11
+ it 'is little endian' do
12
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
13
+ end
14
+ it 'is a BinData::Record' do
15
+ expect(packet).to be_a(BinData::Record)
16
+ end
17
+ describe '#pdw_request_id' do
18
+ it 'is a NdrUint32 structure' do
19
+ expect(packet.pdw_request_id).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
20
+ end
21
+ end
22
+ describe '#pdw_disposition' do
23
+ it 'is a NdrUint32 structure' do
24
+ expect(packet.pdw_disposition).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
25
+ end
26
+ end
27
+ describe '#pctb_cert' do
28
+ it 'is a CertTransBlob structure' do
29
+ expect(packet.pctb_cert).to be_a RubySMB::Dcerpc::Icpr::CertTransBlob
30
+ end
31
+ end
32
+ describe '#pctb_encoded_cert' do
33
+ it 'is a CertTransBlob structure' do
34
+ expect(packet.pctb_encoded_cert).to be_a RubySMB::Dcerpc::Icpr::CertTransBlob
35
+ end
36
+ end
37
+ describe '#pctb_disposition_message' do
38
+ it 'is a CertTransBlob structure' do
39
+ expect(packet.pctb_disposition_message).to be_a RubySMB::Dcerpc::Icpr::CertTransBlob
40
+ end
41
+ end
42
+ describe '#error_status' do
43
+ it 'is a NdrUint32 structure' do
44
+ expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
45
+ end
46
+ end
47
+ describe '#initialize_instance' do
48
+ it 'sets #opnum to CERT_SERVER_REQUEST constant' do
49
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Icpr::CERT_SERVER_REQUEST)
50
+ end
51
+ end
52
+ it 'reads itself' do
53
+ new_packet = described_class.new({
54
+ pdw_request_id: 1,
55
+ pdw_disposition: 0,
56
+ pctb_cert: { pb: 'CERT'.bytes },
57
+ pctb_encoded_cert: { pb: 'ENCODED_CERT'.bytes },
58
+ pctb_disposition_message: { pb: 'DISPOSITION_MESSAGE'.bytes },
59
+ error_status: 0
60
+ })
61
+ expected_output = {
62
+ pdw_request_id: 1,
63
+ pdw_disposition: 0,
64
+ pctb_cert: { cb: 4, pb: 'CERT'.bytes },
65
+ pctb_encoded_cert: { cb: 12, pb: 'ENCODED_CERT'.bytes },
66
+ pctb_disposition_message: { cb: 19, pb: 'DISPOSITION_MESSAGE'.bytes },
67
+ error_status: 0
68
+ }
69
+ expect(packet.read(new_packet.to_binary_s)).to eq(expected_output)
70
+ end
71
+ end
@@ -0,0 +1,33 @@
1
+ RSpec.describe RubySMB::Dcerpc::Icpr::CertTransBlob do
2
+ subject(:struct) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :cb }
5
+ it { is_expected.to respond_to :pb }
6
+
7
+ it 'is little endian' do
8
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
9
+ end
10
+ it 'is a BinData::Record' do
11
+ expect(struct).to be_a(BinData::Record)
12
+ end
13
+ describe '#cb' do
14
+ it 'is a NdrUint32 structure' do
15
+ expect(struct.cb).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
16
+ end
17
+ end
18
+ describe '#pb' do
19
+ it 'is a NdrByteConfArrayPtr structure' do
20
+ expect(struct.pb).to be_a RubySMB::Dcerpc::Ndr::NdrByteConfArrayPtr
21
+ end
22
+ end
23
+ describe '#buffer' do
24
+ it 'returns a string' do
25
+ expect(struct.buffer).to be_a String
26
+ end
27
+ end
28
+ it 'reads itself' do
29
+ new_struct = described_class.new({ pb: 'BUFFER' })
30
+ expected_output = { cb: 6, pb: 'BUFFER'.bytes }
31
+ expect(struct.read(new_struct.to_binary_s)).to eq(expected_output)
32
+ end
33
+ end
@@ -23,6 +23,7 @@ RSpec.describe RubySMB::Dcerpc do
23
23
  allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(bind_ack_packet)
24
24
  allow(tree).to receive(:client).and_return(client)
25
25
  allow(client).to receive(:max_buffer_size=)
26
+ allow(client).to receive(:ntlm_client)
26
27
  end
27
28
 
28
29
  it 'creates a Bind packet' do
@@ -49,7 +50,7 @@ RSpec.describe RubySMB::Dcerpc do
49
50
 
50
51
  it 'raises the expected exception when an invalid packet is received' do
51
52
  allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_raise(IOError)
52
- expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
53
+ expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
53
54
  end
54
55
 
55
56
  it 'raises the expected exception when it is not a BindAck packet' 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.1.7
4
+ version: 3.2.1
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: 2022-08-03 00:00:00.000000000 Z
100
+ date: 2022-11-17 00:00:00.000000000 Z
101
101
  dependencies:
102
102
  - !ruby/object:Gem::Dependency
103
103
  name: redcarpet
@@ -326,6 +326,9 @@ files:
326
326
  - lib/ruby_smb/dcerpc/epm/epm_twrt.rb
327
327
  - lib/ruby_smb/dcerpc/error.rb
328
328
  - lib/ruby_smb/dcerpc/fault.rb
329
+ - lib/ruby_smb/dcerpc/icpr.rb
330
+ - lib/ruby_smb/dcerpc/icpr/cert_server_request_request.rb
331
+ - lib/ruby_smb/dcerpc/icpr/cert_server_request_response.rb
329
332
  - lib/ruby_smb/dcerpc/ndr.rb
330
333
  - lib/ruby_smb/dcerpc/netlogon.rb
331
334
  - lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb
@@ -490,6 +493,8 @@ files:
490
493
  - lib/ruby_smb/nbss/session_request.rb
491
494
  - lib/ruby_smb/ntlm.rb
492
495
  - lib/ruby_smb/ntlm/client.rb
496
+ - lib/ruby_smb/ntlm/custom/ntlm.rb
497
+ - lib/ruby_smb/peer_info.rb
493
498
  - lib/ruby_smb/server.rb
494
499
  - lib/ruby_smb/server/cli.rb
495
500
  - lib/ruby_smb/server/server_client.rb
@@ -669,6 +674,7 @@ files:
669
674
  - lib/ruby_smb/smb2/smb2_header.rb
670
675
  - lib/ruby_smb/smb2/tree.rb
671
676
  - lib/ruby_smb/smb_error.rb
677
+ - lib/ruby_smb/utils.rb
672
678
  - lib/ruby_smb/version.rb
673
679
  - ruby_smb.gemspec
674
680
  - spec/lib/ruby_smb/client_spec.rb
@@ -686,6 +692,9 @@ files:
686
692
  - spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response_spec.rb
687
693
  - spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request_spec.rb
688
694
  - spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response_spec.rb
695
+ - spec/lib/ruby_smb/dcerpc/icpr/cert_server_request_request_spec.rb
696
+ - spec/lib/ruby_smb/dcerpc/icpr/cert_server_request_response_spec.rb
697
+ - spec/lib/ruby_smb/dcerpc/icpr/cert_trans_blob_spec.rb
689
698
  - spec/lib/ruby_smb/dcerpc/ndr_spec.rb
690
699
  - spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb
691
700
  - spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb
@@ -1013,6 +1022,9 @@ test_files:
1013
1022
  - spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response_spec.rb
1014
1023
  - spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request_spec.rb
1015
1024
  - spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response_spec.rb
1025
+ - spec/lib/ruby_smb/dcerpc/icpr/cert_server_request_request_spec.rb
1026
+ - spec/lib/ruby_smb/dcerpc/icpr/cert_server_request_response_spec.rb
1027
+ - spec/lib/ruby_smb/dcerpc/icpr/cert_trans_blob_spec.rb
1016
1028
  - spec/lib/ruby_smb/dcerpc/ndr_spec.rb
1017
1029
  - spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb
1018
1030
  - spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb
metadata.gz.sig CHANGED
Binary file