ruby_smb 1.1.0 → 2.0.4
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 -5
- data/Gemfile +6 -2
- data/examples/anonymous_auth.rb +3 -3
- data/examples/append_file.rb +10 -8
- data/examples/authenticate.rb +9 -5
- data/examples/delete_file.rb +8 -6
- data/examples/enum_registry_key.rb +5 -4
- data/examples/enum_registry_values.rb +5 -4
- data/examples/list_directory.rb +8 -6
- data/examples/negotiate.rb +51 -8
- data/examples/negotiate_with_netbios_service.rb +9 -5
- data/examples/net_share_enum_all.rb +6 -4
- data/examples/pipes.rb +11 -12
- data/examples/query_service_status.rb +64 -0
- data/examples/read_file.rb +8 -6
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +6 -5
- data/examples/rename_file.rb +9 -7
- data/examples/tree_connect.rb +7 -5
- data/examples/write_file.rb +9 -7
- data/lib/ruby_smb.rb +4 -0
- data/lib/ruby_smb/client.rb +246 -26
- data/lib/ruby_smb/client/authentication.rb +32 -18
- data/lib/ruby_smb/client/echo.rb +2 -4
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +156 -16
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +6 -8
- data/lib/ruby_smb/client/utils.rb +24 -17
- data/lib/ruby_smb/client/winreg.rb +1 -1
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dcerpc.rb +2 -0
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +209 -44
- data/lib/ruby_smb/dcerpc/request.rb +13 -0
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
- data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
- data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
- data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
- data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
- data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
- data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
- data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
- data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
- data/lib/ruby_smb/dispatcher/base.rb +1 -1
- data/lib/ruby_smb/dispatcher/socket.rb +5 -4
- data/lib/ruby_smb/error.rb +49 -6
- data/lib/ruby_smb/field/stringz16.rb +17 -1
- data/lib/ruby_smb/generic_packet.rb +11 -1
- data/lib/ruby_smb/nbss/session_header.rb +4 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +13 -28
- 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 +8 -8
- data/lib/ruby_smb/smb1/tree.rb +25 -12
- 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 +59 -77
- 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/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 +8 -20
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +44 -28
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +3 -1
- data/spec/lib/ruby_smb/client_spec.rb +1408 -70
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
- data/spec/lib/ruby_smb/error_spec.rb +88 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/smb1/file_spec.rb +1 -3
- 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 +30 -5
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
- 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 +147 -71
- 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/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 +9 -45
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +111 -9
- metadata +194 -75
- metadata.gz.sig +2 -1
@@ -13,9 +13,10 @@ module RubySMB
|
|
13
13
|
|
14
14
|
rpc_hkey :hkey
|
15
15
|
rrp_unicode_string :lp_value_name
|
16
|
-
string :
|
16
|
+
string :pad1, length: -> { pad_length(self.lp_value_name) }
|
17
17
|
ndr_lp_dword :lp_type
|
18
|
-
|
18
|
+
ndr_lp_byte_array :lp_data
|
19
|
+
string :pad2, length: -> { pad_length(self.lp_data) }
|
19
20
|
ndr_lp_dword :lpcb_data
|
20
21
|
ndr_lp_dword :lpcb_len
|
21
22
|
|
@@ -24,10 +25,10 @@ module RubySMB
|
|
24
25
|
@opnum = REG_QUERY_VALUE
|
25
26
|
end
|
26
27
|
|
27
|
-
# Determines the correct length for the padding
|
28
|
-
#
|
29
|
-
def pad_length
|
30
|
-
offset = (
|
28
|
+
# Determines the correct length for the padding, so that the next
|
29
|
+
# field is 4-byte aligned.
|
30
|
+
def pad_length(prev_element)
|
31
|
+
offset = (prev_element.abs_offset + prev_element.to_binary_s.length) % 4
|
31
32
|
(4 - offset) % 4
|
32
33
|
end
|
33
34
|
end
|
@@ -9,22 +9,22 @@ module RubySMB
|
|
9
9
|
|
10
10
|
endian :little
|
11
11
|
|
12
|
-
ndr_lp_dword
|
13
|
-
|
14
|
-
string
|
15
|
-
ndr_lp_dword
|
16
|
-
ndr_lp_dword
|
17
|
-
uint32
|
12
|
+
ndr_lp_dword :lp_type
|
13
|
+
ndr_lp_byte_array :lp_data
|
14
|
+
string :pad, length: -> { pad_length(self.lp_data) }
|
15
|
+
ndr_lp_dword :lpcb_data
|
16
|
+
ndr_lp_dword :lpcb_len
|
17
|
+
uint32 :error_status
|
18
18
|
|
19
19
|
def initialize_instance
|
20
20
|
super
|
21
21
|
@opnum = REG_QUERY_VALUE
|
22
22
|
end
|
23
23
|
|
24
|
-
# Determines the correct length for the padding
|
25
|
-
#
|
26
|
-
def pad_length
|
27
|
-
offset = (
|
24
|
+
# Determines the correct length for the padding, so that the next
|
25
|
+
# field is 4-byte aligned.
|
26
|
+
def pad_length(prev_element)
|
27
|
+
offset = (prev_element.abs_offset + prev_element.to_binary_s.length) % 4
|
28
28
|
(4 - offset) % 4
|
29
29
|
end
|
30
30
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
class RpcHkey < Ndr::NdrContextHandle; end
|
6
|
+
|
7
|
+
# This class represents a BaseRegSaveKey Request Packet as defined in
|
8
|
+
# [3.1.5.20 BaseRegSaveKey (Opnum 20)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/f022247d-6ef1-4f46-b195-7f60654f4a0d)
|
9
|
+
class SaveKeyRequest < BinData::Record
|
10
|
+
attr_reader :opnum
|
11
|
+
|
12
|
+
endian :little
|
13
|
+
|
14
|
+
rpc_hkey :hkey
|
15
|
+
rrp_unicode_string :lp_file
|
16
|
+
string :pad, length: -> { pad_length(self.lp_file) }
|
17
|
+
prpc_security_attributes :lp_security_attributes
|
18
|
+
|
19
|
+
def initialize_instance
|
20
|
+
super
|
21
|
+
@opnum = REG_SAVE_KEY
|
22
|
+
end
|
23
|
+
|
24
|
+
# Determines the correct length for the padding, so that the next
|
25
|
+
# field is 4-byte aligned.
|
26
|
+
def pad_length(prev_element)
|
27
|
+
offset = (prev_element.abs_offset + prev_element.to_binary_s.length) % 4
|
28
|
+
(4 - offset) % 4
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module Dcerpc
|
3
|
+
module Winreg
|
4
|
+
|
5
|
+
# This class represents a BaseRegSaveKey Response Packet as defined in
|
6
|
+
# [3.1.5.20 BaseRegSaveKey (Opnum 20)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/f022247d-6ef1-4f46-b195-7f60654f4a0d)
|
7
|
+
class SaveKeyResponse < BinData::Record
|
8
|
+
attr_reader :opnum
|
9
|
+
|
10
|
+
endian :little
|
11
|
+
|
12
|
+
uint32 :error_status
|
13
|
+
|
14
|
+
def initialize_instance
|
15
|
+
super
|
16
|
+
@opnum = REG_CREATE_KEY
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -9,7 +9,7 @@ module RubySMB
|
|
9
9
|
def nbss(packet)
|
10
10
|
nbss = RubySMB::Nbss::SessionHeader.new
|
11
11
|
nbss.session_packet_type = RubySMB::Nbss::SESSION_MESSAGE
|
12
|
-
nbss.
|
12
|
+
nbss.stream_protocol_length = packet.do_num_bytes
|
13
13
|
nbss.to_binary_s
|
14
14
|
end
|
15
15
|
|
@@ -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,19 +61,20 @@ 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'
|
74
75
|
end
|
75
76
|
|
76
|
-
length = nbss_header.
|
77
|
+
length = nbss_header.stream_protocol_length
|
77
78
|
data = full_response ? nbss_header.to_binary_s : ''
|
78
79
|
if length > 0
|
79
80
|
if IO.select([@tcp_socket], nil, nil, @read_timeout).nil?
|
@@ -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
@@ -16,23 +16,26 @@ module RubySMB
|
|
16
16
|
# Raised when trying to parse raw binary into a Packet and the data
|
17
17
|
# is invalid.
|
18
18
|
class InvalidPacket < RubySMBError
|
19
|
+
attr_reader :status_code
|
19
20
|
def initialize(args = nil)
|
20
21
|
if args.nil?
|
21
22
|
super
|
22
23
|
elsif args.is_a? String
|
23
24
|
super(args)
|
24
25
|
elsif args.is_a? Hash
|
25
|
-
expected_proto = args[:expected_proto] ? translate_protocol(args[:expected_proto]) :
|
26
|
-
expected_cmd = args[:expected_cmd] ||
|
27
|
-
received_proto = args[:
|
28
|
-
received_cmd = args[:
|
26
|
+
expected_proto = args[:expected_proto] ? translate_protocol(args[:expected_proto]) : '???'
|
27
|
+
expected_cmd = args[:expected_cmd] || '???'
|
28
|
+
received_proto = args[:packet]&.packet_smb_version || '???'
|
29
|
+
received_cmd = get_cmd(args[:packet]) || '???'
|
30
|
+
@status_code = args[:packet]&.status_code
|
29
31
|
super(
|
30
32
|
"Expecting #{expected_proto} protocol "\
|
31
33
|
"with command=#{expected_cmd}"\
|
32
34
|
"#{(" (" + args[:expected_custom] + ")") if args[:expected_custom]}, "\
|
33
35
|
"got #{received_proto} protocol "\
|
34
36
|
"with command=#{received_cmd}"\
|
35
|
-
"#{(" (" + args[:received_custom] + ")") if args[:received_custom]}"
|
37
|
+
"#{(" (" + args[:received_custom] + ")") if args[:received_custom]}"\
|
38
|
+
"#{(", Status: #{@status_code}") if @status_code}"
|
36
39
|
)
|
37
40
|
else
|
38
41
|
raise ArgumentError, "InvalidPacket expects a String or a Hash, got a #{args.class}"
|
@@ -50,10 +53,44 @@ module RubySMB
|
|
50
53
|
end
|
51
54
|
end
|
52
55
|
private :translate_protocol
|
56
|
+
|
57
|
+
def get_cmd(packet)
|
58
|
+
return nil unless packet
|
59
|
+
case packet.packet_smb_version
|
60
|
+
when 'SMB1'
|
61
|
+
packet.smb_header.command
|
62
|
+
when 'SMB2'
|
63
|
+
packet.smb2_header.command
|
64
|
+
else
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
private :get_cmd
|
53
69
|
end
|
54
70
|
|
55
71
|
# Raised when a response packet has a NTStatus code that was unexpected.
|
56
|
-
class UnexpectedStatusCode < RubySMBError
|
72
|
+
class UnexpectedStatusCode < RubySMBError
|
73
|
+
attr_reader :status_code
|
74
|
+
|
75
|
+
def initialize(status_code)
|
76
|
+
case status_code
|
77
|
+
when WindowsError::ErrorCode
|
78
|
+
@status_code = status_code
|
79
|
+
when Integer
|
80
|
+
@status_code = WindowsError::NTStatus.find_by_retval(status_code).first
|
81
|
+
if @status_code.nil?
|
82
|
+
@status_code = WindowsError::ErrorCode.new("0x#{status_code.to_s(16)}", status_code, "Unknown 0x#{status_code.to_s(16)}")
|
83
|
+
end
|
84
|
+
else
|
85
|
+
raise ArgumentError, "Status code must be a WindowsError::ErrorCode or an Integer, got #{status_code.class}"
|
86
|
+
end
|
87
|
+
super
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_s
|
91
|
+
"The server responded with an unexpected status code: #{status_code.name}"
|
92
|
+
end
|
93
|
+
end
|
57
94
|
|
58
95
|
# Raised when an error occurs with the underlying socket.
|
59
96
|
class CommunicationError < RubySMBError; end
|
@@ -65,5 +102,11 @@ module RubySMB
|
|
65
102
|
# Raised when trying to parse raw binary into a BitField and the data
|
66
103
|
# is invalid.
|
67
104
|
class InvalidBitField < RubySMBError; end
|
105
|
+
|
106
|
+
# Raised when an encryption operation fails
|
107
|
+
class EncryptionError < RubySMBError; end
|
108
|
+
|
109
|
+
# Raised when an signing operation fails
|
110
|
+
class SigningError < RubySMBError; end
|
68
111
|
end
|
69
112
|
end
|
@@ -25,12 +25,17 @@ module RubySMB
|
|
25
25
|
# @see BinData::Stringz
|
26
26
|
def read_and_return_value(io)
|
27
27
|
max_length = eval_parameter(:max_length)
|
28
|
+
if max_length && max_length % 2 != 0
|
29
|
+
raise ArgumentError, "[Stringz16] #max_length should be a multiple of "\
|
30
|
+
"two, since it is Unicode (got #{max_length})"
|
31
|
+
end
|
28
32
|
str = ''
|
29
33
|
i = 0
|
30
34
|
ch = nil
|
31
35
|
|
32
36
|
# read until double NULL-byte or we have read in the max number of bytes
|
33
|
-
|
37
|
+
loop do
|
38
|
+
break if ch == "\0\0" || (max_length && i == max_length)
|
34
39
|
ch = io.readbytes(2)
|
35
40
|
str << ch
|
36
41
|
i += 2
|
@@ -46,6 +51,17 @@ module RubySMB
|
|
46
51
|
def truncate_after_first_zero_byte!(str)
|
47
52
|
str.sub!(/([^\0]*\0\0\0).*/, '\1')
|
48
53
|
end
|
54
|
+
|
55
|
+
def trim_to!(str, max_length = nil)
|
56
|
+
if max_length
|
57
|
+
max_length = 2 if max_length < 2
|
58
|
+
str.slice!(max_length..-1)
|
59
|
+
if str.length == max_length && str[-2, 2] != "\0\0"
|
60
|
+
str[-2, 2] = "\0\0"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
49
65
|
end
|
50
66
|
end
|
51
67
|
end
|
@@ -49,7 +49,17 @@ module RubySMB
|
|
49
49
|
when /SMB1/
|
50
50
|
packet = RubySMB::SMB1::Packet::EmptyPacket.read(val)
|
51
51
|
when /SMB2/
|
52
|
-
|
52
|
+
begin
|
53
|
+
packet = RubySMB::SMB2::Packet::ErrorPacket.read(val)
|
54
|
+
rescue RubySMB::Error::InvalidPacket
|
55
|
+
# Handle the case where an SMB2 error packet is expected, but the
|
56
|
+
# server sent an SMB1 empty packet instead. This behavior has been
|
57
|
+
# observed with older versions of Samba when something goes wrong
|
58
|
+
# on the server side. We just want to give it a chance and try to
|
59
|
+
# parse it as an SMB1 empty packet to keep information and avoid
|
60
|
+
# failing as much as possible.
|
61
|
+
packet = RubySMB::SMB1::Packet::EmptyPacket.read(val)
|
62
|
+
end
|
53
63
|
else
|
54
64
|
raise RubySMB::Error::InvalidPacket, 'Not a valid SMB packet'
|
55
65
|
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module RubySMB
|
2
2
|
module Nbss
|
3
3
|
# Representation of the NetBIOS Session Service Header as defined in
|
4
|
-
# [
|
4
|
+
# SMB: [2.1 Transport](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/f906c680-330c-43ae-9a71-f854e24aeee6)
|
5
|
+
# SMB2: [2.1 Transport](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/1dfacde4-b5c7-4494-8a14-a09d3ab4cc83)
|
5
6
|
class SessionHeader < BinData::Record
|
6
7
|
endian :big
|
7
8
|
|
8
|
-
uint8
|
9
|
-
|
10
|
-
bit17 :packet_length, label: 'Packet Length'
|
9
|
+
uint8 :session_packet_type, label: 'Session Packet Type', initial_value: 0
|
10
|
+
uint24 :stream_protocol_length, label: 'Stream Protocol Length'
|
11
11
|
end
|
12
12
|
end
|
13
13
|
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
@@ -86,12 +86,11 @@ module RubySMB
|
|
86
86
|
raise RubySMB::Error::InvalidPacket.new(
|
87
87
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
88
88
|
expected_cmd: RubySMB::SMB1::Packet::CloseResponse::COMMAND,
|
89
|
-
|
90
|
-
received_cmd: response.smb_header.command
|
89
|
+
packet: response
|
91
90
|
)
|
92
91
|
end
|
93
92
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
94
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
93
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
95
94
|
end
|
96
95
|
response.status_code
|
97
96
|
end
|
@@ -106,11 +105,7 @@ module RubySMB
|
|
106
105
|
# @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
|
107
106
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
108
107
|
def read(bytes: @size, offset: 0)
|
109
|
-
atomic_read_size =
|
110
|
-
@tree.client.max_buffer_size
|
111
|
-
else
|
112
|
-
bytes
|
113
|
-
end
|
108
|
+
atomic_read_size = [bytes, @tree.client.max_buffer_size].min
|
114
109
|
remaining_bytes = bytes
|
115
110
|
data = ''
|
116
111
|
|
@@ -122,12 +117,11 @@ module RubySMB
|
|
122
117
|
raise RubySMB::Error::InvalidPacket.new(
|
123
118
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
124
119
|
expected_cmd: RubySMB::SMB1::Packet::ReadAndxResponse::COMMAND,
|
125
|
-
|
126
|
-
received_cmd: response.smb_header.command
|
120
|
+
packet: response
|
127
121
|
)
|
128
122
|
end
|
129
123
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
130
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
124
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
131
125
|
end
|
132
126
|
|
133
127
|
if response.is_a?(RubySMB::SMB1::Packet::ReadAndxResponse)
|
@@ -171,12 +165,11 @@ module RubySMB
|
|
171
165
|
raise RubySMB::Error::InvalidPacket.new(
|
172
166
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
173
167
|
expected_cmd: RubySMB::SMB1::Packet::ReadAndxResponse::COMMAND,
|
174
|
-
|
175
|
-
received_cmd: response.smb_header.command
|
168
|
+
packet: response
|
176
169
|
)
|
177
170
|
end
|
178
171
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
179
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
172
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
180
173
|
end
|
181
174
|
|
182
175
|
response.data_block.data.to_binary_s
|
@@ -193,8 +186,7 @@ module RubySMB
|
|
193
186
|
raise RubySMB::Error::InvalidPacket.new(
|
194
187
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
195
188
|
expected_cmd: RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse::COMMAND,
|
196
|
-
|
197
|
-
received_cmd: response.smb_header.command
|
189
|
+
packet: response
|
198
190
|
)
|
199
191
|
end
|
200
192
|
response.status_code
|
@@ -227,11 +219,7 @@ module RubySMB
|
|
227
219
|
total_bytes_written = 0
|
228
220
|
|
229
221
|
loop do
|
230
|
-
atomic_write_size =
|
231
|
-
@tree.client.max_buffer_size
|
232
|
-
else
|
233
|
-
bytes
|
234
|
-
end
|
222
|
+
atomic_write_size = [bytes, @tree.client.max_buffer_size].min
|
235
223
|
write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset)
|
236
224
|
raw_response = @tree.client.send_recv(write_request)
|
237
225
|
response = RubySMB::SMB1::Packet::WriteAndxResponse.read(raw_response)
|
@@ -239,12 +227,11 @@ module RubySMB
|
|
239
227
|
raise RubySMB::Error::InvalidPacket.new(
|
240
228
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
241
229
|
expected_cmd: RubySMB::SMB1::Packet::WriteAndxResponse::COMMAND,
|
242
|
-
|
243
|
-
received_cmd: response.smb_header.command
|
230
|
+
packet: response
|
244
231
|
)
|
245
232
|
end
|
246
233
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
247
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
234
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
248
235
|
end
|
249
236
|
bytes_written = response.parameter_block.count_low + (response.parameter_block.count_high << 16)
|
250
237
|
total_bytes_written += bytes_written
|
@@ -279,8 +266,7 @@ module RubySMB
|
|
279
266
|
raise RubySMB::Error::InvalidPacket.new(
|
280
267
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
281
268
|
expected_cmd: RubySMB::SMB1::Packet::WriteAndxResponse::COMMAND,
|
282
|
-
|
283
|
-
received_cmd: response.smb_header.command
|
269
|
+
packet: response
|
284
270
|
)
|
285
271
|
end
|
286
272
|
response.parameter_block.count_low
|
@@ -298,8 +284,7 @@ module RubySMB
|
|
298
284
|
raise RubySMB::Error::InvalidPacket.new(
|
299
285
|
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
300
286
|
expected_cmd: RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse::COMMAND,
|
301
|
-
|
302
|
-
received_cmd: response.smb_header.command
|
287
|
+
packet: response
|
303
288
|
)
|
304
289
|
end
|
305
290
|
response.status_code
|