ruby_smb 1.0.4 → 2.0.2
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 +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +3 -2
- data/Gemfile +6 -2
- data/README.md +35 -47
- data/examples/enum_registry_key.rb +28 -0
- data/examples/enum_registry_values.rb +30 -0
- data/examples/negotiate.rb +51 -8
- data/examples/pipes.rb +2 -1
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +32 -0
- data/lib/ruby_smb.rb +4 -1
- data/lib/ruby_smb/client.rb +207 -18
- data/lib/ruby_smb/client/authentication.rb +27 -8
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +153 -12
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +4 -4
- data/lib/ruby_smb/client/utils.rb +8 -7
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dcerpc.rb +38 -0
- data/lib/ruby_smb/dcerpc/bind.rb +2 -2
- data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +28 -9
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
- data/lib/ruby_smb/dispatcher/socket.rb +4 -3
- data/lib/ruby_smb/error.rb +28 -1
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +6 -4
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +4 -2
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +79 -3
- data/lib/ruby_smb/smb1/tree.rb +12 -3
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
- data/lib/ruby_smb/smb2/file.rb +25 -43
- data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/error_packet.rb +9 -4
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
- data/lib/ruby_smb/smb2/pipe.rb +77 -3
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +23 -17
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1441 -61
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +2 -2
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
- data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +10 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +210 -148
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +86 -62
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
- data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +29 -2
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +220 -149
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +53 -8
- metadata +187 -81
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -0,0 +1,57 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
# This class represents a BaseRegQueryValue Response Packet as defined in
|
6
|
+
# [3.1.5.17 BaseRegQueryValue (Opnum 17)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/8bc10aa3-2f91-44e8-aa33-b3263c49ab9d)
|
7
|
+
class QueryValueResponse < BinData::Record
|
8
|
+
attr_reader :opnum
|
9
|
+
|
10
|
+
endian :little
|
11
|
+
|
12
|
+
ndr_lp_dword :lp_type
|
13
|
+
ndr_lp_byte :lp_data
|
14
|
+
string :pad, length: -> { pad_length }
|
15
|
+
ndr_lp_dword :lpcb_data
|
16
|
+
ndr_lp_dword :lpcb_len
|
17
|
+
uint32 :error_status
|
18
|
+
|
19
|
+
def initialize_instance
|
20
|
+
super
|
21
|
+
@opnum = REG_QUERY_VALUE
|
22
|
+
end
|
23
|
+
|
24
|
+
# Determines the correct length for the padding in front of
|
25
|
+
# #lpcb_data. It should always force a 4-byte alignment.
|
26
|
+
def pad_length
|
27
|
+
offset = (lp_data.abs_offset + lp_data.to_binary_s.length) % 4
|
28
|
+
(4 - offset) % 4
|
29
|
+
end
|
30
|
+
|
31
|
+
# Returns the data portion of the registry value formatted according to its type:
|
32
|
+
# [3.1.1.5 Values](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/3d64dbea-f016-4373-8cac-e43bf343837d)
|
33
|
+
def data
|
34
|
+
bytes = lp_data.bytes.to_a.pack('C*')
|
35
|
+
case lp_type
|
36
|
+
when 1,2
|
37
|
+
bytes.force_encoding('utf-16le').strip
|
38
|
+
when 3
|
39
|
+
bytes
|
40
|
+
when 4
|
41
|
+
bytes.unpack('V').first
|
42
|
+
when 5
|
43
|
+
bytes.unpack('N').first
|
44
|
+
when 7
|
45
|
+
str = bytes.force_encoding('utf-16le')
|
46
|
+
str.split("\0".encode('utf-16le'))
|
47
|
+
when 11
|
48
|
+
bytes.unpack('Q<').first
|
49
|
+
else
|
50
|
+
""
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
# This class represents a REGSAM structure as defined in
|
6
|
+
# [2.2.3 REGSAM](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/fefbc801-b141-4bb1-9dcb-bf366da3ae7e)
|
7
|
+
# [2.4.3 ACCESS_MASK](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp/7a53f60e-e730-4dfe-bbe9-b21b62eb790b)
|
8
|
+
class Regsam < BinData::Record
|
9
|
+
endian :little
|
10
|
+
bit2 :reserved, label: 'Reserved Space'
|
11
|
+
bit1 :key_create_link, label: 'Key Create Link'
|
12
|
+
bit1 :key_notify, label: 'Key Notify'
|
13
|
+
bit1 :key_enumerate_sub_keys, label: 'Key Enumerate Sub Keys'
|
14
|
+
bit1 :key_create_sub_key, label: 'Key Create Sub Key'
|
15
|
+
bit1 :key_set_value, label: 'Key Set Value'
|
16
|
+
bit1 :key_query_value, label: 'Key Query Value'
|
17
|
+
# byte boundary
|
18
|
+
bit6 :reserved2, label: 'Reserved Space'
|
19
|
+
bit1 :key_wow64_32key, label: 'Key Wow64 32key'
|
20
|
+
bit1 :key_wow64_64key, label: 'Key Wow64 64key'
|
21
|
+
# byte boundary
|
22
|
+
bit3 :reserved3, label: 'Reserved Space'
|
23
|
+
bit1 :synchronize, label: 'Synchronize'
|
24
|
+
bit1 :write_owner, label: 'Write Owner'
|
25
|
+
bit1 :write_dac, label: 'Write DAC'
|
26
|
+
bit1 :read_control, label: 'Read Control'
|
27
|
+
bit1 :delete_access, label: 'Delete'
|
28
|
+
# byte boundary
|
29
|
+
bit1 :generic_read, label: 'Generic Read'
|
30
|
+
bit1 :generic_write, label: 'Generic Write'
|
31
|
+
bit1 :generic_execute, label: 'Generic Execute'
|
32
|
+
bit1 :generic_all, label: 'Generic All'
|
33
|
+
bit2 :reserved4, label: 'Reserved Space'
|
34
|
+
bit1 :maximum, label: 'Maximum Allowed'
|
35
|
+
bit1 :system_security, label: 'System Security'
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -48,7 +48,7 @@ module RubySMB
|
|
48
48
|
end
|
49
49
|
|
50
50
|
rescue IOError, Errno::ECONNABORTED, Errno::ECONNRESET => e
|
51
|
-
raise RubySMB::Error::CommunicationError, "An error
|
51
|
+
raise RubySMB::Error::CommunicationError, "An error occurred writing to the Socket: #{e.message}"
|
52
52
|
end
|
53
53
|
nil
|
54
54
|
end
|
@@ -61,13 +61,14 @@ module RubySMB
|
|
61
61
|
# which are assumed to be the NetBiosSessionService header.
|
62
62
|
# @raise [RubySMB::Error::CommunicationError] if the read timeout expires or an error occurs when reading the socket
|
63
63
|
def recv_packet(full_response: false)
|
64
|
+
raise RubySMB::Error::CommunicationError, 'Connection has already been closed' if @tcp_socket.closed?
|
64
65
|
if IO.select([@tcp_socket], nil, nil, @read_timeout).nil?
|
65
66
|
raise RubySMB::Error::CommunicationError, "Read timeout expired when reading from the Socket (timeout=#{@read_timeout})"
|
66
67
|
end
|
67
68
|
|
68
69
|
begin
|
69
70
|
nbss_data = @tcp_socket.read(4)
|
70
|
-
raise
|
71
|
+
raise RubySMB::Error::CommunicationError, 'Socket read returned nil' if nbss_data.nil?
|
71
72
|
nbss_header = RubySMB::Nbss::SessionHeader.read(nbss_data)
|
72
73
|
rescue IOError
|
73
74
|
raise ::RubySMB::Error::NetBiosSessionService, 'NBSS Header is missing'
|
@@ -84,7 +85,7 @@ module RubySMB
|
|
84
85
|
end
|
85
86
|
data
|
86
87
|
rescue Errno::EINVAL, Errno::ECONNABORTED, Errno::ECONNRESET, TypeError, NoMethodError => e
|
87
|
-
raise RubySMB::Error::CommunicationError, "An error
|
88
|
+
raise RubySMB::Error::CommunicationError, "An error occurred reading from the Socket #{e.message}"
|
88
89
|
end
|
89
90
|
end
|
90
91
|
end
|
data/lib/ruby_smb/error.rb
CHANGED
@@ -53,7 +53,28 @@ module RubySMB
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# Raised when a response packet has a NTStatus code that was unexpected.
|
56
|
-
class UnexpectedStatusCode < RubySMBError
|
56
|
+
class UnexpectedStatusCode < RubySMBError
|
57
|
+
attr_reader :status_code
|
58
|
+
|
59
|
+
def initialize(status_code)
|
60
|
+
case status_code
|
61
|
+
when WindowsError::ErrorCode
|
62
|
+
@status_code = status_code
|
63
|
+
when Integer
|
64
|
+
@status_code = WindowsError::NTStatus.find_by_retval(status_code).first
|
65
|
+
if @status_code.nil?
|
66
|
+
@status_code = WindowsError::ErrorCode.new("0x#{status_code.to_s(16)}", status_code, "Unknown 0x#{status_code.to_s(16)}")
|
67
|
+
end
|
68
|
+
else
|
69
|
+
raise ArgumentError, "Status code must be a WindowsError::ErrorCode or an Integer, got #{status_code.class}"
|
70
|
+
end
|
71
|
+
super
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
"The server responded with an unexpected status code: #{status_code.name}"
|
76
|
+
end
|
77
|
+
end
|
57
78
|
|
58
79
|
# Raised when an error occurs with the underlying socket.
|
59
80
|
class CommunicationError < RubySMBError; end
|
@@ -65,5 +86,11 @@ module RubySMB
|
|
65
86
|
# Raised when trying to parse raw binary into a BitField and the data
|
66
87
|
# is invalid.
|
67
88
|
class InvalidBitField < RubySMBError; end
|
89
|
+
|
90
|
+
# Raised when an encryption operation fails
|
91
|
+
class EncryptionError < RubySMBError; end
|
92
|
+
|
93
|
+
# Raised when an signing operation fails
|
94
|
+
class SigningError < RubySMBError; end
|
68
95
|
end
|
69
96
|
end
|
@@ -10,7 +10,7 @@ module RubySMB
|
|
10
10
|
SMB_COM_TRANSACTION2_SECONDARY = 0x33
|
11
11
|
SMB_COM_TREE_DISCONNECT = 0x71
|
12
12
|
SMB_COM_NEGOTIATE = 0x72
|
13
|
-
|
13
|
+
SMB_COM_SESSION_SETUP_ANDX = 0x73
|
14
14
|
SMB_COM_LOGOFF = 0x74
|
15
15
|
SMB_COM_TREE_CONNECT = 0x75
|
16
16
|
SMB_COM_NT_TRANSACT = 0xA0
|
data/lib/ruby_smb/smb1/file.rb
CHANGED
@@ -91,7 +91,7 @@ module RubySMB
|
|
91
91
|
)
|
92
92
|
end
|
93
93
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
94
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
94
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
95
95
|
end
|
96
96
|
response.status_code
|
97
97
|
end
|
@@ -127,7 +127,7 @@ module RubySMB
|
|
127
127
|
)
|
128
128
|
end
|
129
129
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
130
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
130
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
131
131
|
end
|
132
132
|
|
133
133
|
if response.is_a?(RubySMB::SMB1::Packet::ReadAndxResponse)
|
@@ -156,6 +156,8 @@ module RubySMB
|
|
156
156
|
def read_packet(read_length: 0, offset: 0)
|
157
157
|
read_request = set_header_fields(RubySMB::SMB1::Packet::ReadAndxRequest.new)
|
158
158
|
read_request.parameter_block.max_count_of_bytes_to_return = read_length
|
159
|
+
read_request.parameter_block.min_count_of_bytes_to_return = read_length
|
160
|
+
read_request.parameter_block.remaining = read_length
|
159
161
|
read_request.parameter_block.offset = offset
|
160
162
|
read_request
|
161
163
|
end
|
@@ -174,7 +176,7 @@ module RubySMB
|
|
174
176
|
)
|
175
177
|
end
|
176
178
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
177
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
179
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
178
180
|
end
|
179
181
|
|
180
182
|
response.data_block.data.to_binary_s
|
@@ -242,7 +244,7 @@ module RubySMB
|
|
242
244
|
)
|
243
245
|
end
|
244
246
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
245
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
247
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
246
248
|
end
|
247
249
|
bytes_written = response.parameter_block.count_low + (response.parameter_block.count_high << 16)
|
248
250
|
total_bytes_written += bytes_written
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RubySMB
|
2
2
|
module SMB1
|
3
3
|
module Packet
|
4
|
-
# This packet represent an SMB1 Response Packet when the parameter and
|
4
|
+
# This packet represent an SMB1 Error Response Packet when the parameter and
|
5
5
|
# data blocks will be empty.
|
6
6
|
class EmptyPacket < RubySMB::GenericPacket
|
7
7
|
attr_accessor :original_command
|
@@ -12,7 +12,9 @@ module RubySMB
|
|
12
12
|
|
13
13
|
def valid?
|
14
14
|
return smb_header.protocol == RubySMB::SMB1::SMB_PROTOCOL_ID &&
|
15
|
-
|
15
|
+
smb_header.command == @original_command &&
|
16
|
+
parameter_block.word_count == 0 &&
|
17
|
+
data_block.byte_count == 0
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
@@ -4,7 +4,7 @@ module RubySMB
|
|
4
4
|
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Request Packet, without NTLMSSP as defined in
|
5
5
|
# [2.2.4.53.1 Request](https://msdn.microsoft.com/en-us/library/ee441849.aspx)
|
6
6
|
class SessionSetupLegacyRequest < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB1::Commands::
|
7
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
8
8
|
|
9
9
|
# A SMB1 Parameter Block as defined by the {SessionSetupRequest}
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module RubySMB
|
2
2
|
module SMB1
|
3
3
|
module Packet
|
4
|
-
# A SMB1
|
4
|
+
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Legacy Response Packet as defined in
|
5
5
|
# [2.2.4.53.2 Response](https://msdn.microsoft.com/en-us/library/ee442143.aspx)
|
6
6
|
class SessionSetupLegacyResponse < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB1::Commands::
|
7
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
8
8
|
|
9
9
|
# A SMB1 Parameter Block as defined by the {SessionSetupResponse}
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
@@ -4,7 +4,7 @@ module RubySMB
|
|
4
4
|
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Request Packet as defined in
|
5
5
|
# [2.2.4.6.1](https://msdn.microsoft.com/en-us/library/cc246328.aspx)
|
6
6
|
class SessionSetupRequest < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB1::Commands::
|
7
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
8
8
|
|
9
9
|
# A SMB1 Parameter Block as defined by the {SessionSetupRequest}
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module RubySMB
|
2
2
|
module SMB1
|
3
3
|
module Packet
|
4
|
-
# A SMB1
|
4
|
+
# A SMB1 SMB_COM_SESSION_SETUP_ANDX Response Packet as defined in
|
5
5
|
# [2.2.4.6.2](https://msdn.microsoft.com/en-us/library/cc246329.aspx)
|
6
6
|
class SessionSetupResponse < RubySMB::GenericPacket
|
7
|
-
COMMAND = RubySMB::SMB1::Commands::
|
7
|
+
COMMAND = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
|
8
8
|
|
9
9
|
# A SMB1 Parameter Block as defined by the {SessionSetupResponse}
|
10
10
|
class ParameterBlock < RubySMB::SMB1::ParameterBlock
|
data/lib/ruby_smb/smb1/pipe.rb
CHANGED
@@ -3,9 +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/
|
6
|
+
require 'ruby_smb/dcerpc'
|
7
7
|
|
8
|
-
include RubySMB::
|
8
|
+
include RubySMB::Dcerpc
|
9
9
|
|
10
10
|
# Reference: https://msdn.microsoft.com/en-us/library/ee441883.aspx
|
11
11
|
STATUS_DISCONNECTED = 0x0001
|
@@ -13,6 +13,17 @@ module RubySMB
|
|
13
13
|
STATUS_OK = 0x0003
|
14
14
|
STATUS_CLOSED = 0x0004
|
15
15
|
|
16
|
+
def initialize(tree:, response:, name:)
|
17
|
+
raise ArgumentError, 'No Name Provided' if name.nil?
|
18
|
+
case name
|
19
|
+
when 'srvsvc'
|
20
|
+
extend RubySMB::Dcerpc::Srvsvc
|
21
|
+
when 'winreg'
|
22
|
+
extend RubySMB::Dcerpc::Winreg
|
23
|
+
end
|
24
|
+
super(tree: tree, response: response, name: name)
|
25
|
+
end
|
26
|
+
|
16
27
|
# Performs a peek operation on the named pipe
|
17
28
|
#
|
18
29
|
# @param peek_size [Integer] Amount of data to peek
|
@@ -36,7 +47,7 @@ module RubySMB
|
|
36
47
|
end
|
37
48
|
|
38
49
|
unless response.status_code == WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW or response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
39
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
50
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
40
51
|
end
|
41
52
|
|
42
53
|
response
|
@@ -68,6 +79,71 @@ module RubySMB
|
|
68
79
|
state == STATUS_OK
|
69
80
|
end
|
70
81
|
|
82
|
+
# Send a DCERPC request with the provided stub packet.
|
83
|
+
#
|
84
|
+
# @params stub_packet [#opnum] the stub packet to add to the DCERPC request
|
85
|
+
# @return [String] the raw DCERPC response stub
|
86
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response is not valid
|
87
|
+
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response status code is different than STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW
|
88
|
+
def dcerpc_request(stub_packet, options={})
|
89
|
+
options.merge!(endpoint: stub_packet.class.name.split('::').at(-2))
|
90
|
+
dcerpc_request = RubySMB::Dcerpc::Request.new({ opnum: stub_packet.opnum }, options)
|
91
|
+
dcerpc_request.stub.read(stub_packet.to_binary_s)
|
92
|
+
trans_nmpipe_request = RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest.new(options)
|
93
|
+
@tree.set_header_fields(trans_nmpipe_request)
|
94
|
+
trans_nmpipe_request.set_fid(@fid)
|
95
|
+
trans_nmpipe_request.data_block.trans_data.write_data = dcerpc_request.to_binary_s
|
96
|
+
|
97
|
+
trans_nmpipe_raw_response = @tree.client.send_recv(trans_nmpipe_request)
|
98
|
+
trans_nmpipe_response = RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse.read(trans_nmpipe_raw_response)
|
99
|
+
unless trans_nmpipe_response.valid?
|
100
|
+
raise RubySMB::Error::InvalidPacket.new(
|
101
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
102
|
+
expected_cmd: RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse::COMMAND,
|
103
|
+
received_proto: trans_nmpipe_response.smb_header.protocol,
|
104
|
+
received_cmd: trans_nmpipe_response.smb_header.command
|
105
|
+
)
|
106
|
+
end
|
107
|
+
unless [WindowsError::NTStatus::STATUS_SUCCESS,
|
108
|
+
WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW].include?(trans_nmpipe_response.status_code)
|
109
|
+
raise RubySMB::Error::UnexpectedStatusCode, trans_nmpipe_response.status_code
|
110
|
+
end
|
111
|
+
|
112
|
+
raw_data = trans_nmpipe_response.data_block.trans_data.read_data.to_binary_s
|
113
|
+
if trans_nmpipe_response.status_code == WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW
|
114
|
+
raw_data << read(bytes: @tree.client.max_buffer_size - trans_nmpipe_response.parameter_block.data_count)
|
115
|
+
dcerpc_response = dcerpc_response_from_raw_response(raw_data)
|
116
|
+
unless dcerpc_response.pdu_header.pfc_flags.first_frag == 1
|
117
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Not the first fragment"
|
118
|
+
end
|
119
|
+
stub_data = dcerpc_response.stub.to_s
|
120
|
+
|
121
|
+
loop do
|
122
|
+
break if dcerpc_response.pdu_header.pfc_flags.last_frag == 1
|
123
|
+
raw_data = read(bytes: @tree.client.max_buffer_size)
|
124
|
+
dcerpc_response = dcerpc_response_from_raw_response(raw_data)
|
125
|
+
stub_data << dcerpc_response.stub.to_s
|
126
|
+
end
|
127
|
+
stub_data
|
128
|
+
else
|
129
|
+
dcerpc_response = dcerpc_response_from_raw_response(raw_data)
|
130
|
+
dcerpc_response.stub.to_s
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def dcerpc_response_from_raw_response(raw_data)
|
138
|
+
dcerpc_response = RubySMB::Dcerpc::Response.read(raw_data)
|
139
|
+
unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::RESPONSE
|
140
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Not a Response packet"
|
141
|
+
end
|
142
|
+
dcerpc_response
|
143
|
+
rescue IOError
|
144
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
|
145
|
+
end
|
146
|
+
|
71
147
|
end
|
72
148
|
end
|
73
149
|
end
|
data/lib/ruby_smb/smb1/tree.rb
CHANGED
@@ -123,6 +123,15 @@ module RubySMB
|
|
123
123
|
raw_response = @client.send_recv(nt_create_andx_request)
|
124
124
|
response = RubySMB::SMB1::Packet::NtCreateAndxResponse.read(raw_response)
|
125
125
|
unless response.valid?
|
126
|
+
if response.is_a?(RubySMB::SMB1::Packet::EmptyPacket) &&
|
127
|
+
response.smb_header.protocol == RubySMB::SMB1::SMB_PROTOCOL_ID &&
|
128
|
+
response.smb_header.command == response.original_command
|
129
|
+
raise RubySMB::Error::InvalidPacket.new(
|
130
|
+
'The response seems to be an SMB1 NtCreateAndxResponse but an '\
|
131
|
+
'error occurs while parsing it. It is probably missing the '\
|
132
|
+
'required extended information.'
|
133
|
+
)
|
134
|
+
end
|
126
135
|
raise RubySMB::Error::InvalidPacket.new(
|
127
136
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
128
137
|
expected_cmd: RubySMB::SMB1::Packet::NtCreateAndxResponse::COMMAND,
|
@@ -131,7 +140,7 @@ module RubySMB
|
|
131
140
|
)
|
132
141
|
end
|
133
142
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
134
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
143
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
135
144
|
end
|
136
145
|
|
137
146
|
case response.parameter_block.resource_type
|
@@ -191,7 +200,7 @@ module RubySMB
|
|
191
200
|
)
|
192
201
|
end
|
193
202
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
194
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
203
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
195
204
|
end
|
196
205
|
|
197
206
|
results = response.results(type, unicode: unicode)
|
@@ -226,7 +235,7 @@ module RubySMB
|
|
226
235
|
)
|
227
236
|
end
|
228
237
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
229
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
238
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
230
239
|
end
|
231
240
|
|
232
241
|
results += response.results(type, unicode: unicode)
|