ruby_smb 3.1.7 → 3.2.1

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.
@@ -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