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