ruby_smb 0.0.21 → 0.0.22
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/examples/net_share_enum_all.rb +5 -2
- data/lib/ruby_smb.rb +1 -1
- data/lib/ruby_smb/client.rb +4 -35
- data/lib/ruby_smb/dcerpc.rb +7 -22
- data/lib/ruby_smb/dcerpc/bind.rb +30 -36
- data/lib/ruby_smb/dcerpc/bind_ack.rb +72 -0
- data/lib/ruby_smb/dcerpc/error.rb +15 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +31 -30
- data/lib/ruby_smb/dcerpc/p_syntax_id_t.rb +11 -0
- data/lib/ruby_smb/dcerpc/pdu_header.rb +29 -0
- data/lib/ruby_smb/dcerpc/ptypes.rb +26 -0
- data/lib/ruby_smb/dcerpc/request.rb +17 -30
- data/lib/ruby_smb/dcerpc/response.rb +15 -34
- data/lib/ruby_smb/dcerpc/srvsvc.rb +5 -7
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +8 -4
- data/lib/ruby_smb/dcerpc/uuid.rb +31 -13
- data/lib/ruby_smb/smb1/bit_field.rb +0 -1
- data/lib/ruby_smb/smb1/bit_field/trans_flags.rb +3 -2
- data/lib/ruby_smb/smb1/data_block.rb +5 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +67 -0
- data/lib/ruby_smb/smb1/packet.rb +1 -0
- data/lib/ruby_smb/smb1/packet/trans.rb +7 -1
- data/lib/ruby_smb/smb1/packet/trans/data_block.rb +19 -7
- data/lib/ruby_smb/smb1/packet/trans/request.rb +36 -25
- data/lib/ruby_smb/smb1/packet/trans/response.rb +22 -21
- data/lib/ruby_smb/smb1/packet/trans/subcommands.rb +1 -0
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +61 -0
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +44 -0
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +3 -0
- data/lib/ruby_smb/smb2/dcerpc.rb +68 -0
- data/lib/ruby_smb/smb2/pipe.rb +3 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +53 -6
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +224 -0
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +255 -7
- data/spec/lib/ruby_smb/dcerpc/p_syntax_id_t_spec.rb +31 -0
- data/spec/lib/ruby_smb/dcerpc/pdu_header_spec.rb +84 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +106 -13
- data/spec/lib/ruby_smb/dcerpc/response_spec.rb +89 -8
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +176 -0
- data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +97 -1
- data/spec/lib/ruby_smb/smb1/data_block_spec.rb +43 -3
- data/spec/lib/ruby_smb/smb1/packet/trans/data_block_spec.rb +137 -0
- data/spec/lib/ruby_smb/smb1/packet/trans/request_spec.rb +239 -13
- data/spec/lib/ruby_smb/smb1/packet/trans/response_spec.rb +122 -13
- data/spec/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request_spec.rb +254 -0
- data/spec/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response_spec.rb +122 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +199 -1
- data/spec/lib/ruby_smb/smb2/file_spec.rb +2 -1
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +196 -1
- metadata +25 -10
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/dcerpc/handle.rb +0 -60
- data/lib/ruby_smb/smb1/bit_field/trans2_flags.rb +0 -15
- data/spec/lib/ruby_smb/dcerpc/handle_spec.rb +0 -31
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +0 -13
- data/spec/lib/ruby_smb/smb1/bit_field/trans2_flags_spec.rb +0 -26
@@ -2,32 +2,31 @@ module RubySMB
|
|
2
2
|
module SMB1
|
3
3
|
module Packet
|
4
4
|
module Trans
|
5
|
-
|
6
|
-
|
5
|
+
|
6
|
+
# This class represents a generic SMB1 Trans Response Packet as defined in
|
7
|
+
# [2.2.4.33.2 Response](https://msdn.microsoft.com/en-us/library/ee442061.aspx)
|
7
8
|
class Response < RubySMB::GenericPacket
|
8
9
|
# A SMB1 Parameter Block
|
9
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
10
|
-
uint16 :total_parameter_count,
|
11
|
-
uint16
|
12
|
-
uint16
|
13
|
-
uint16
|
14
|
-
uint16
|
15
|
-
uint16
|
16
|
-
uint16
|
17
|
-
uint16
|
18
|
-
uint16
|
19
|
-
uint8
|
20
|
-
uint8
|
21
|
-
|
22
|
-
array :setup, type: :uint16, initial_length: 0
|
11
|
+
uint16 :total_parameter_count, label: 'Total Parameter Count(bytes)', initial_value: -> { parameter_count }
|
12
|
+
uint16 :total_data_count, label: 'Total Data Count(bytes)', initial_value: -> { data_count }
|
13
|
+
uint16 :reserved, label: 'Reserved Space', value: 0x0000
|
14
|
+
uint16 :parameter_count, label: 'Parameter Count(bytes)', initial_value: -> { parent.data_block.trans_parameters.length }
|
15
|
+
uint16 :parameter_offset, label: 'Parameter Offset', initial_value: -> { parent.data_block.trans_parameters.abs_offset }
|
16
|
+
uint16 :parameter_displacement, label: 'Parameter Displacement'
|
17
|
+
uint16 :data_count, label: 'Data Count(bytes)', initial_value: -> { parent.data_block.trans_data.length }
|
18
|
+
uint16 :data_offset, label: 'Data Offset', initial_value: -> { parent.data_block.trans_data.abs_offset }
|
19
|
+
uint16 :data_displacement, label: 'Data Displacement'
|
20
|
+
uint8 :setup_count, label: 'Setup Count', initial_value: -> { setup.length }
|
21
|
+
uint8 :reserved2, label: 'Reserved Space', value: 0x00
|
22
|
+
array :setup, type: :uint16, initial_length: :setup_count
|
23
23
|
end
|
24
24
|
|
25
|
-
# The {RubySMB::SMB1::DataBlock} specific to this packet type.
|
26
25
|
class DataBlock < RubySMB::SMB1::Packet::Trans::DataBlock
|
27
|
-
string :pad1,
|
28
|
-
string :trans_parameters,
|
29
|
-
string :pad2,
|
30
|
-
string :trans_data,
|
26
|
+
string :pad1, length: lambda { pad1_length }
|
27
|
+
string :trans_parameters, label: 'Trans Parameters', read_length: -> { parent.parameter_block.parameter_count }
|
28
|
+
string :pad2, length: lambda { pad2_length }
|
29
|
+
string :trans_data, label: 'Trans Data', read_length: -> { parent.parameter_block.data_count }
|
31
30
|
end
|
32
31
|
|
33
32
|
smb_header :smb_header
|
@@ -39,8 +38,10 @@ module RubySMB
|
|
39
38
|
smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
|
40
39
|
smb_header.flags.reply = 1
|
41
40
|
end
|
41
|
+
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
46
|
-
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB1
|
3
|
+
module Packet
|
4
|
+
module Trans
|
5
|
+
|
6
|
+
# A Trans TRANSACT_NMPIPE Request Packet as defined in
|
7
|
+
# [2.2.5.6.1 Request](https://msdn.microsoft.com/en-us/library/ee441832.aspx)
|
8
|
+
class TransactNmpipeRequest < RubySMB::GenericPacket
|
9
|
+
|
10
|
+
class ParameterBlock < RubySMB::SMB1::Packet::Trans::Request::ParameterBlock
|
11
|
+
end
|
12
|
+
|
13
|
+
class TransData < BinData::Record
|
14
|
+
string :write_data, label: 'Write Data', read_length: -> { parent.parent.parameter_block.data_count }
|
15
|
+
|
16
|
+
# Returns the length of the TransData struct in number of bytes
|
17
|
+
def length
|
18
|
+
do_num_bytes
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class DataBlock < RubySMB::SMB1::Packet::Trans::DataBlock
|
23
|
+
# If unicode is set, the name field must be aligned to start on a 2-byte
|
24
|
+
# boundary from the start of the SMB header:
|
25
|
+
string :pad_name, length: -> { pad_name_length },
|
26
|
+
onlyif: -> { parent.smb_header.flags2.unicode.to_i == 1 }
|
27
|
+
choice :name, :selection => lambda { parent.smb_header.flags2.unicode.to_i },
|
28
|
+
:copy_on_change => true do
|
29
|
+
stringz 0, label: 'Name', initial_value: "\\PIPE\\"
|
30
|
+
stringz16 1, label: 'Name', initial_value: "\\PIPE\\".encode('utf-16le')
|
31
|
+
end
|
32
|
+
string :pad1, length: lambda { pad1_length }
|
33
|
+
string :trans_parameters, label: 'Trans Parameters', read_length: -> { parent.parameter_block.parameter_count }
|
34
|
+
string :pad2, length: lambda { pad2_length }
|
35
|
+
trans_data :trans_data, label: 'Trans Data'
|
36
|
+
end
|
37
|
+
|
38
|
+
smb_header :smb_header
|
39
|
+
parameter_block :parameter_block
|
40
|
+
data_block :data_block
|
41
|
+
|
42
|
+
|
43
|
+
def initialize_instance
|
44
|
+
super
|
45
|
+
smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
|
46
|
+
parameter_block.max_parameter_count = 0x0000
|
47
|
+
parameter_block.max_setup_count = 0x00
|
48
|
+
parameter_block.setup << RubySMB::SMB1::Packet::Trans::Subcommands::TRANSACT_NMPIPE
|
49
|
+
# FID: must be set to a valid FID from a server response for a
|
50
|
+
# previous SMB command to open or create a named pipe.
|
51
|
+
parameter_block.setup << 0x0000
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_fid(fid)
|
55
|
+
parameter_block.setup[1] = fid
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB1
|
3
|
+
module Packet
|
4
|
+
module Trans
|
5
|
+
|
6
|
+
# A Trans TRANSACT_NMPIPE Response Packet as defined in
|
7
|
+
# [2.2.5.6.2 Response](https://msdn.microsoft.com/en-us/library/ee442003.aspx)
|
8
|
+
class TransactNmpipeResponse < RubySMB::GenericPacket
|
9
|
+
|
10
|
+
class ParameterBlock < RubySMB::SMB1::Packet::Trans::Response::ParameterBlock
|
11
|
+
end
|
12
|
+
|
13
|
+
class TransData < BinData::Record
|
14
|
+
string :read_data, label: 'Read Data', read_length: -> { parent.parameter_block.data_count }
|
15
|
+
|
16
|
+
# Returns the length of the TransData struct in number of bytes
|
17
|
+
def length
|
18
|
+
do_num_bytes
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class DataBlock < RubySMB::SMB1::Packet::Trans::DataBlock
|
23
|
+
string :pad1, length: lambda { pad1_length }
|
24
|
+
string :trans_parameters, label: 'Trans Parameters', read_length: -> { parent.parameter_block.parameter_count }
|
25
|
+
string :pad2, length: lambda { pad2_length }
|
26
|
+
trans_data :trans_data, label: 'Trans Data'
|
27
|
+
end
|
28
|
+
|
29
|
+
smb_header :smb_header
|
30
|
+
parameter_block :parameter_block
|
31
|
+
data_block :data_block
|
32
|
+
|
33
|
+
|
34
|
+
def initialize_instance
|
35
|
+
super
|
36
|
+
smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
|
37
|
+
smb_header.flags.reply = 1
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -13,7 +13,7 @@ module RubySMB
|
|
13
13
|
uint16 :max_data_count, label: 'Max Data Count(bytes)'
|
14
14
|
uint8 :max_setup_count, label: 'Max Setup Count'
|
15
15
|
uint8 :reserved, label: 'Reserved Space', initial_value: 0x00
|
16
|
-
|
16
|
+
trans_flags :flags
|
17
17
|
uint32 :timeout, label: 'Timeout', initial_value: 0x00000000
|
18
18
|
uint16 :reserved2, label: 'Reserved Space', initial_value: 0x00
|
19
19
|
uint16 :parameter_count, label: 'Parameter Count(bytes)', initial_value: -> { parent.data_block.trans2_parameters.length }
|
data/lib/ruby_smb/smb1/pipe.rb
CHANGED
@@ -3,6 +3,9 @@ module RubySMB
|
|
3
3
|
# Represents a pipe on the Remote server that we can perform
|
4
4
|
# various I/O operations on.
|
5
5
|
class Pipe < File
|
6
|
+
require 'ruby_smb/smb1/dcerpc'
|
7
|
+
|
8
|
+
include RubySMB::SMB1::Dcerpc
|
6
9
|
|
7
10
|
# Reference: https://msdn.microsoft.com/en-us/library/ee441883.aspx
|
8
11
|
STATUS_DISCONNECTED = 0x0001
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
module Dcerpc
|
4
|
+
|
5
|
+
def net_share_enum_all(host)
|
6
|
+
bind(endpoint: RubySMB::Dcerpc::Srvsvc)
|
7
|
+
|
8
|
+
response = request(RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL, host: host)
|
9
|
+
|
10
|
+
shares = RubySMB::Dcerpc::Srvsvc::NetShareEnumAll.parse_response(response.stub.to_binary_s)
|
11
|
+
shares.map{|s|{name: s[0], type: s[1], comment: s[2]}}
|
12
|
+
end
|
13
|
+
|
14
|
+
def bind(options={})
|
15
|
+
bind_req = RubySMB::Dcerpc::Bind.new(options)
|
16
|
+
ioctl_response = ioctl_send_recv(bind_req, options)
|
17
|
+
begin
|
18
|
+
dcerpc_response = RubySMB::Dcerpc::BindAck.read(ioctl_response.output_data)
|
19
|
+
rescue IOError
|
20
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
|
21
|
+
end
|
22
|
+
unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::BIND_ACK
|
23
|
+
raise RubySMB::Dcerpc::Error::BindError, "Not a BindAck packet"
|
24
|
+
end
|
25
|
+
|
26
|
+
res_list = dcerpc_response.p_result_list
|
27
|
+
if res_list.n_results == 0 ||
|
28
|
+
res_list.p_results[0].result != RubySMB::Dcerpc::BindAck::ACCEPTANCE
|
29
|
+
raise RubySMB::Dcerpc::Error::BindError,
|
30
|
+
"Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
|
31
|
+
end
|
32
|
+
dcerpc_response
|
33
|
+
end
|
34
|
+
|
35
|
+
def request(opnum, options={})
|
36
|
+
dcerpc_request = RubySMB::Dcerpc::Request.new({ :opnum => opnum }, options)
|
37
|
+
ioctl_response = ioctl_send_recv(dcerpc_request, options)
|
38
|
+
begin
|
39
|
+
dcerpc_response = RubySMB::Dcerpc::Response.read(ioctl_response.output_data)
|
40
|
+
rescue IOError
|
41
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
|
42
|
+
end
|
43
|
+
unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::RESPONSE
|
44
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Not a Response packet"
|
45
|
+
end
|
46
|
+
dcerpc_response
|
47
|
+
end
|
48
|
+
|
49
|
+
def ioctl_send_recv(action, options={})
|
50
|
+
request = set_header_fields(RubySMB::SMB2::Packet::IoctlRequest.new(options))
|
51
|
+
request.ctl_code = 0x0011C017
|
52
|
+
request.flags.is_fsctl = 0x00000001
|
53
|
+
request.buffer = action.to_binary_s
|
54
|
+
ioctl_raw_response = @tree.client.send_recv(request)
|
55
|
+
ioctl_response = RubySMB::SMB2::Packet::IoctlResponse.read(ioctl_raw_response)
|
56
|
+
unless ioctl_response.smb2_header.command == RubySMB::SMB2::Commands::IOCTL
|
57
|
+
raise RubySMB::Error::InvalidPacket, 'Not a IoctlResponse packet'
|
58
|
+
end
|
59
|
+
unless ioctl_response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
60
|
+
raise RubySMB::Error::UnexpectedStatusCode, ioctl_response.status_code.name
|
61
|
+
end
|
62
|
+
ioctl_response
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/lib/ruby_smb/smb2/pipe.rb
CHANGED
data/lib/ruby_smb/version.rb
CHANGED
@@ -201,8 +201,8 @@ RSpec.describe RubySMB::Client do
|
|
201
201
|
allow(dispatcher).to receive(:send_packet) do |packet, _opts|
|
202
202
|
expect(packet).to be_a(RubySMB::Nbss::SessionRequest)
|
203
203
|
expect(packet.session_header.session_packet_type).to eq RubySMB::Nbss::SESSION_REQUEST
|
204
|
-
expect(packet.called_name).to eq encoded_called_name
|
205
|
-
expect(packet.calling_name).to eq encoded_calling_name
|
204
|
+
expect(packet.called_name).to eq encoded_called_name
|
205
|
+
expect(packet.calling_name).to eq encoded_calling_name
|
206
206
|
expect(packet.session_header.packet_length).to eq (encoded_called_name.size + encoded_calling_name.size)
|
207
207
|
end
|
208
208
|
client.session_request
|
@@ -1123,11 +1123,58 @@ RSpec.describe RubySMB::Client do
|
|
1123
1123
|
end
|
1124
1124
|
|
1125
1125
|
describe '#net_share_enum_all' do
|
1126
|
-
let(:
|
1126
|
+
let(:tree){ double("Tree") }
|
1127
|
+
let(:named_pipe){ double("Named Pipe") }
|
1127
1128
|
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1129
|
+
before :example do
|
1130
|
+
allow(tree).to receive(:open_file).and_return(named_pipe)
|
1131
|
+
allow(named_pipe).to receive(:net_share_enum_all)
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
context 'with SMB1' do
|
1135
|
+
before :example do
|
1136
|
+
allow(smb1_client).to receive(:tree_connect).and_return(tree)
|
1137
|
+
end
|
1138
|
+
|
1139
|
+
it 'it calls the #tree_connect method to connect to the "host" IPC$ share' do
|
1140
|
+
ipc_share = "\\\\#{sock.peeraddr}\\IPC$"
|
1141
|
+
expect(smb1_client).to receive(:tree_connect).with(ipc_share).and_return(tree)
|
1142
|
+
smb1_client.net_share_enum_all(sock.peeraddr)
|
1143
|
+
end
|
1144
|
+
|
1145
|
+
it 'it calls the Tree #open_file method to open "srvsvc" named pipe' do
|
1146
|
+
expect(tree).to receive(:open_file).with(filename: "srvsvc", write: true, read: true).and_return(named_pipe)
|
1147
|
+
smb1_client.net_share_enum_all(sock.peeraddr)
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
it 'it calls the File #net_share_enum_all method with the correct host' do
|
1151
|
+
host = "1.2.3.4"
|
1152
|
+
expect(named_pipe).to receive(:net_share_enum_all).with(host)
|
1153
|
+
smb1_client.net_share_enum_all(host)
|
1154
|
+
end
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
context 'with SMB2' do
|
1158
|
+
before :example do
|
1159
|
+
allow(smb2_client).to receive(:tree_connect).and_return(tree)
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
it 'it calls the #tree_connect method to connect to the "host" IPC$ share' do
|
1163
|
+
ipc_share = "\\\\#{sock.peeraddr}\\IPC$"
|
1164
|
+
expect(smb2_client).to receive(:tree_connect).with(ipc_share).and_return(tree)
|
1165
|
+
smb2_client.net_share_enum_all(sock.peeraddr)
|
1166
|
+
end
|
1167
|
+
|
1168
|
+
it 'it calls the Tree #open_file method to open "srvsvc" named pipe' do
|
1169
|
+
expect(tree).to receive(:open_file).with(filename: "srvsvc", write: true, read: true).and_return(named_pipe)
|
1170
|
+
smb2_client.net_share_enum_all(sock.peeraddr)
|
1171
|
+
end
|
1172
|
+
|
1173
|
+
it 'it calls the File #net_share_enum_all method with the correct host' do
|
1174
|
+
host = "1.2.3.4"
|
1175
|
+
expect(named_pipe).to receive(:net_share_enum_all).with(host)
|
1176
|
+
smb2_client.net_share_enum_all(host)
|
1177
|
+
end
|
1131
1178
|
end
|
1132
1179
|
end
|
1133
1180
|
end
|
@@ -0,0 +1,224 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc::BindAck do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :pdu_header }
|
5
|
+
it { is_expected.to respond_to :max_xmit_frag }
|
6
|
+
it { is_expected.to respond_to :max_recv_frag }
|
7
|
+
it { is_expected.to respond_to :assoc_group_id }
|
8
|
+
it { is_expected.to respond_to :sec_addr }
|
9
|
+
it { is_expected.to respond_to :p_result_list }
|
10
|
+
it { is_expected.to respond_to :auth_verifier }
|
11
|
+
|
12
|
+
it 'is little endian' do
|
13
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#pdu_header' do
|
17
|
+
subject(:header) { packet.pdu_header }
|
18
|
+
|
19
|
+
it 'is a standard PDU Header' do
|
20
|
+
expect(header).to be_a RubySMB::Dcerpc::PDUHeader
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should have the #ptype field set to PTypes::BIND_ACK' do
|
24
|
+
expect(header.ptype).to eq RubySMB::Dcerpc::PTypes::BIND_ACK
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe '#max_xmit_frag' do
|
29
|
+
it 'should be a 16-bit unsigned integer' do
|
30
|
+
expect(packet.max_xmit_frag).to be_a BinData::Uint16le
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should have a default value of 0xFFFF' do
|
34
|
+
expect(packet.max_xmit_frag).to eq 0xFFFF
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#max_recv_frag' do
|
39
|
+
it 'should be a 16-bit unsigned integer' do
|
40
|
+
expect(packet.max_recv_frag).to be_a BinData::Uint16le
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should have a default value of 0xFFFF' do
|
44
|
+
expect(packet.max_recv_frag).to eq 0xFFFF
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#assoc_group_id' do
|
49
|
+
it 'should be a 32-bit unsigned integer' do
|
50
|
+
expect(packet.assoc_group_id).to be_a BinData::Uint32le
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#pad' do
|
55
|
+
it 'should keep #p_result_list 4-byte aligned' do
|
56
|
+
packet.sec_addr.port_spec = "test"
|
57
|
+
expect(packet.p_result_list.abs_offset % 4).to eq 0
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#p_result_list' do
|
62
|
+
it 'should be a PContListT structure' do
|
63
|
+
expect(packet.p_result_list).to be_a RubySMB::Dcerpc::PResultListT
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe '#auth_verifier' do
|
68
|
+
it 'should be a string' do
|
69
|
+
expect(packet.auth_verifier).to be_a BinData::String
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should not exist if the #auth_length PDU header field is 0' do
|
73
|
+
packet.pdu_header.auth_length = 0
|
74
|
+
expect(packet.auth_verifier?).to be false
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should exist only if the #auth_length PDU header field is greater than 0' do
|
78
|
+
packet.pdu_header.auth_length = 10
|
79
|
+
expect(packet.auth_verifier?).to be true
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'reads #auth_length bytes' do
|
83
|
+
auth_verifier = '12345678'
|
84
|
+
packet.pdu_header.auth_length = 6
|
85
|
+
packet.auth_verifier.read(auth_verifier)
|
86
|
+
expect(packet.auth_verifier).to eq(auth_verifier[0,6])
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#pad_length' do
|
91
|
+
it 'returns 0 when #p_result_list is already 4-byte aligned' do
|
92
|
+
packet.sec_addr.port_spec = 'align'
|
93
|
+
expect(packet.pad_length).to eq 0
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'returns 2 when #p_result_list is only 2-byte aligned' do
|
97
|
+
packet.sec_addr.port_spec = 'align' + 'AA'
|
98
|
+
expect(packet.pad_length).to eq 2
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'reads its own binary representation and output the same packet' do
|
103
|
+
packet.sec_addr.port_spec = "port spec"
|
104
|
+
packet.p_result_list.n_results = 2
|
105
|
+
packet.auth_verifier = '123456'
|
106
|
+
packet.pdu_header.auth_length = 6
|
107
|
+
binary = packet.to_binary_s
|
108
|
+
expect(described_class.read(binary)).to eq(packet)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
RSpec.describe RubySMB::Dcerpc::PortAnyT do
|
113
|
+
subject(:packet) { described_class.new }
|
114
|
+
|
115
|
+
it { is_expected.to respond_to :str_length }
|
116
|
+
it { is_expected.to respond_to :port_spec }
|
117
|
+
|
118
|
+
it 'is little endian' do
|
119
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#str_length' do
|
123
|
+
it 'should be a 16-bit unsigned integer' do
|
124
|
+
expect(packet.str_length).to be_a BinData::Uint16le
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'should be the size of #port_spec string, including the NULL terminator' do
|
128
|
+
str = 'test'
|
129
|
+
packet.port_spec = str
|
130
|
+
expect(packet.str_length).to eq(str.size + 1)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '#port_spec' do
|
135
|
+
it 'should be a Stringz' do
|
136
|
+
expect(packet.port_spec).to be_a BinData::Stringz
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'reads its own binary representation and output the same packet' do
|
141
|
+
packet.port_spec = "port spec"
|
142
|
+
binary = packet.to_binary_s
|
143
|
+
expect(described_class.read(binary)).to eq(packet)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
RSpec.describe RubySMB::Dcerpc::PResultListT do
|
148
|
+
subject(:packet) { described_class.new }
|
149
|
+
|
150
|
+
it { is_expected.to respond_to :n_results }
|
151
|
+
it { is_expected.to respond_to :p_results }
|
152
|
+
|
153
|
+
it 'is little endian' do
|
154
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
155
|
+
end
|
156
|
+
|
157
|
+
describe '#n_results' do
|
158
|
+
it 'should be a 8-bit unsigned integer' do
|
159
|
+
expect(packet.n_results).to be_a BinData::Uint8
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe '#p_results' do
|
164
|
+
it 'should be an array of type PResultT' do
|
165
|
+
expect(packet.p_results).to be_a BinData::Array
|
166
|
+
type = packet.p_results.get_parameter(:type)
|
167
|
+
expect(type.instantiate).to be_a RubySMB::Dcerpc::PResultT
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should have #n_results elements' do
|
171
|
+
n_elements = 4
|
172
|
+
packet.n_results = n_elements
|
173
|
+
expect(packet.p_results.size).to eq n_elements
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'reads its own binary representation and output the same packet' do
|
178
|
+
packet.n_results = 4
|
179
|
+
binary = packet.to_binary_s
|
180
|
+
expect(described_class.read(binary)).to eq(packet)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
RSpec.describe RubySMB::Dcerpc::PResultT do
|
185
|
+
subject(:packet) { described_class.new }
|
186
|
+
|
187
|
+
it { is_expected.to respond_to :result }
|
188
|
+
it { is_expected.to respond_to :reason }
|
189
|
+
it { is_expected.to respond_to :transfer_syntax }
|
190
|
+
|
191
|
+
it 'is little endian' do
|
192
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
193
|
+
end
|
194
|
+
|
195
|
+
describe '#result' do
|
196
|
+
it 'should be a 16-bit unsigned integer' do
|
197
|
+
expect(packet.result).to be_a BinData::Uint16le
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe '#reason' do
|
202
|
+
it 'should be a 16-bit unsigned integer' do
|
203
|
+
expect(packet.reason).to be_a BinData::Uint16le
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
describe '#transfer_syntax' do
|
208
|
+
it 'should be a PSyntaxIdT' do
|
209
|
+
expect(packet.transfer_syntax).to be_a RubySMB::Dcerpc::PSyntaxIdT
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'is set to the NDR presentation syntax' do
|
213
|
+
expect(packet.transfer_syntax.if_uuid).to eq RubySMB::Dcerpc::Ndr::UUID
|
214
|
+
expect(packet.transfer_syntax.if_ver_major).to eq RubySMB::Dcerpc::Ndr::VER_MAJOR
|
215
|
+
expect(packet.transfer_syntax.if_ver_minor).to eq RubySMB::Dcerpc::Ndr::VER_MINOR
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'reads its own binary representation and output the same packet' do
|
220
|
+
binary = packet.to_binary_s
|
221
|
+
expect(described_class.read(binary)).to eq(packet)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|