ruby_smb 1.0.5 → 2.0.3
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/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 +29 -0
- data/examples/enum_registry_values.rb +31 -0
- 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 +13 -13
- 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 +33 -0
- 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 -1
- data/lib/ruby_smb/client.rb +239 -21
- 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 +154 -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 +40 -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 +6 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +260 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +41 -9
- data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +38 -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/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 +421 -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/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 +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 +40 -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/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 +28 -1
- data/lib/ruby_smb/field/stringz16.rb +17 -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 +8 -14
- 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 +81 -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 +51 -61
- 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 +2 -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 +80 -3
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +32 -20
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1583 -102
- 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 +1729 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +135 -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/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/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/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 +104 -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 +95 -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 +35 -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 +138 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- 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 +884 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
- data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
- data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
- 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 +216 -147
- 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 +146 -68
- 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 +3 -24
- 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 +226 -148
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +88 -9
- metadata +257 -81
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -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,19 @@ 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
|
+
when 'svcctl'
|
24
|
+
extend RubySMB::Dcerpc::Svcctl
|
25
|
+
end
|
26
|
+
super(tree: tree, response: response, name: name)
|
27
|
+
end
|
28
|
+
|
16
29
|
# Performs a peek operation on the named pipe
|
17
30
|
#
|
18
31
|
# @param peek_size [Integer] Amount of data to peek
|
@@ -36,7 +49,7 @@ module RubySMB
|
|
36
49
|
end
|
37
50
|
|
38
51
|
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
|
52
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
40
53
|
end
|
41
54
|
|
42
55
|
response
|
@@ -68,6 +81,71 @@ module RubySMB
|
|
68
81
|
state == STATUS_OK
|
69
82
|
end
|
70
83
|
|
84
|
+
# Send a DCERPC request with the provided stub packet.
|
85
|
+
#
|
86
|
+
# @params stub_packet [#opnum] the stub packet to add to the DCERPC request
|
87
|
+
# @return [String] the raw DCERPC response stub
|
88
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response is not valid
|
89
|
+
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response status code is different than STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW
|
90
|
+
def dcerpc_request(stub_packet, options={})
|
91
|
+
options.merge!(endpoint: stub_packet.class.name.split('::').at(-2))
|
92
|
+
dcerpc_request = RubySMB::Dcerpc::Request.new({ opnum: stub_packet.opnum }, options)
|
93
|
+
dcerpc_request.stub.read(stub_packet.to_binary_s)
|
94
|
+
trans_nmpipe_request = RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest.new(options)
|
95
|
+
@tree.set_header_fields(trans_nmpipe_request)
|
96
|
+
trans_nmpipe_request.set_fid(@fid)
|
97
|
+
trans_nmpipe_request.data_block.trans_data.write_data = dcerpc_request.to_binary_s
|
98
|
+
|
99
|
+
trans_nmpipe_raw_response = @tree.client.send_recv(trans_nmpipe_request)
|
100
|
+
trans_nmpipe_response = RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse.read(trans_nmpipe_raw_response)
|
101
|
+
unless trans_nmpipe_response.valid?
|
102
|
+
raise RubySMB::Error::InvalidPacket.new(
|
103
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
104
|
+
expected_cmd: RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse::COMMAND,
|
105
|
+
received_proto: trans_nmpipe_response.smb_header.protocol,
|
106
|
+
received_cmd: trans_nmpipe_response.smb_header.command
|
107
|
+
)
|
108
|
+
end
|
109
|
+
unless [WindowsError::NTStatus::STATUS_SUCCESS,
|
110
|
+
WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW].include?(trans_nmpipe_response.status_code)
|
111
|
+
raise RubySMB::Error::UnexpectedStatusCode, trans_nmpipe_response.status_code
|
112
|
+
end
|
113
|
+
|
114
|
+
raw_data = trans_nmpipe_response.data_block.trans_data.read_data.to_binary_s
|
115
|
+
if trans_nmpipe_response.status_code == WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW
|
116
|
+
raw_data << read(bytes: @tree.client.max_buffer_size - trans_nmpipe_response.parameter_block.data_count)
|
117
|
+
dcerpc_response = dcerpc_response_from_raw_response(raw_data)
|
118
|
+
unless dcerpc_response.pdu_header.pfc_flags.first_frag == 1
|
119
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Not the first fragment"
|
120
|
+
end
|
121
|
+
stub_data = dcerpc_response.stub.to_s
|
122
|
+
|
123
|
+
loop do
|
124
|
+
break if dcerpc_response.pdu_header.pfc_flags.last_frag == 1
|
125
|
+
raw_data = read(bytes: @tree.client.max_buffer_size)
|
126
|
+
dcerpc_response = dcerpc_response_from_raw_response(raw_data)
|
127
|
+
stub_data << dcerpc_response.stub.to_s
|
128
|
+
end
|
129
|
+
stub_data
|
130
|
+
else
|
131
|
+
dcerpc_response = dcerpc_response_from_raw_response(raw_data)
|
132
|
+
dcerpc_response.stub.to_s
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
def dcerpc_response_from_raw_response(raw_data)
|
140
|
+
dcerpc_response = RubySMB::Dcerpc::Response.read(raw_data)
|
141
|
+
unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::RESPONSE
|
142
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Not a Response packet"
|
143
|
+
end
|
144
|
+
dcerpc_response
|
145
|
+
rescue IOError
|
146
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
|
147
|
+
end
|
148
|
+
|
71
149
|
end
|
72
150
|
end
|
73
151
|
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)
|
@@ -4,7 +4,8 @@ module RubySMB
|
|
4
4
|
# The SessionsFlags bit-field for a {RubySMB::SMB2::Packet::SessionSetupResponse}
|
5
5
|
class SessionFlags < BinData::Record
|
6
6
|
endian :little
|
7
|
-
|
7
|
+
bit5 :reserved3, label: 'Reserved', initial_value: 0
|
8
|
+
bit1 :encrypt_data, label: 'Encrypt Data', initial_value: 0
|
8
9
|
bit1 :null, label: 'ASYNC Command', initial_value: 0
|
9
10
|
bit1 :guest, label: 'Is Guest?', initial_value: 0
|
10
11
|
resume_byte_alignment
|
@@ -8,7 +8,7 @@ module RubySMB
|
|
8
8
|
bit2 :reserved1, label: 'Reserved Space'
|
9
9
|
bit1 :vdo_caching, label: 'VDO Caching'
|
10
10
|
bit1 :auto_caching, label: 'Auto Caching'
|
11
|
-
bit2 :reserved2
|
11
|
+
bit2 :reserved2, label: 'Reserved Space'
|
12
12
|
bit1 :dfs_root, label: 'DFS Root'
|
13
13
|
bit1 :dfs, label: 'DFS'
|
14
14
|
# byte boundary
|
@@ -20,9 +20,11 @@ module RubySMB
|
|
20
20
|
bit1 :namespace_caching, label: 'Namespace Caching'
|
21
21
|
bit1 :shared_delete, label: 'Force Shared Delete'
|
22
22
|
bit1 :restrict_exclusive_opens, label: 'Restrict Exclusive Opens'
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
# byte boundary
|
24
|
+
bit5 :reserved3, label: 'Reserved Space'
|
25
|
+
bit1 :identity_remoting, label: 'Identity Remoting'
|
26
|
+
bit2 :reserved4, label: 'Reserved Space'
|
27
|
+
bit8 :reserved5, label: 'Reserved Space'
|
26
28
|
|
27
29
|
def caching_type
|
28
30
|
if vdo_caching == 1 && auto_caching.zero?
|
data/lib/ruby_smb/smb2/file.rb
CHANGED
@@ -52,7 +52,12 @@ module RubySMB
|
|
52
52
|
# @return [RubySMB::SMB2::Tree]
|
53
53
|
attr_accessor :tree
|
54
54
|
|
55
|
-
|
55
|
+
# Whether or not the share associated with this tree connect needs to be encrypted (SMB 3.x)
|
56
|
+
# @!attribute [rw] tree_connect_encrypt_data
|
57
|
+
# @return [Boolean]
|
58
|
+
attr_accessor :tree_connect_encrypt_data
|
59
|
+
|
60
|
+
def initialize(tree:, response:, name:, encrypt: false)
|
56
61
|
raise ArgumentError, 'No Tree Provided' if tree.nil?
|
57
62
|
raise ArgumentError, 'No Response Provided' if response.nil?
|
58
63
|
|
@@ -66,6 +71,7 @@ module RubySMB
|
|
66
71
|
@last_write = response.last_write.to_datetime
|
67
72
|
@size = response.end_of_file
|
68
73
|
@size_on_disk = response.allocation_size
|
74
|
+
@tree_connect_encrypt_data = encrypt
|
69
75
|
end
|
70
76
|
|
71
77
|
# Appends the supplied data to the end of the file.
|
@@ -83,7 +89,7 @@ module RubySMB
|
|
83
89
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
84
90
|
def close
|
85
91
|
close_request = set_header_fields(RubySMB::SMB2::Packet::CloseRequest.new)
|
86
|
-
raw_response = tree.client.send_recv(close_request)
|
92
|
+
raw_response = tree.client.send_recv(close_request, encrypt: @tree_connect_encrypt_data)
|
87
93
|
response = RubySMB::SMB2::Packet::CloseResponse.read(raw_response)
|
88
94
|
unless response.valid?
|
89
95
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -94,7 +100,7 @@ module RubySMB
|
|
94
100
|
)
|
95
101
|
end
|
96
102
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
97
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
103
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
98
104
|
end
|
99
105
|
response.status_code
|
100
106
|
end
|
@@ -109,14 +115,16 @@ module RubySMB
|
|
109
115
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a ReadResponse packet
|
110
116
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
111
117
|
def read(bytes: size, offset: 0)
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
118
|
+
max_read = tree.client.server_max_read_size
|
119
|
+
max_read = 65536 unless tree.client.server_supports_multi_credit
|
120
|
+
atomic_read_size = [bytes, max_read].min
|
121
|
+
credit_charge = 0
|
122
|
+
if tree.client.server_supports_multi_credit
|
123
|
+
credit_charge = (atomic_read_size - 1) / 65536 + 1
|
124
|
+
end
|
125
|
+
|
126
|
+
read_request = read_packet(read_length: atomic_read_size, offset: offset, credit_charge: credit_charge)
|
127
|
+
raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
|
120
128
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
121
129
|
unless response.valid?
|
122
130
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -127,7 +135,7 @@ module RubySMB
|
|
127
135
|
)
|
128
136
|
end
|
129
137
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
130
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
138
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
131
139
|
end
|
132
140
|
|
133
141
|
data = response.buffer.to_binary_s
|
@@ -136,10 +144,10 @@ module RubySMB
|
|
136
144
|
|
137
145
|
while remaining_bytes > 0
|
138
146
|
offset += atomic_read_size
|
139
|
-
atomic_read_size = remaining_bytes if remaining_bytes <
|
147
|
+
atomic_read_size = remaining_bytes if remaining_bytes < max_read
|
140
148
|
|
141
|
-
read_request = read_packet(read_length: atomic_read_size, offset: offset)
|
142
|
-
raw_response = tree.client.send_recv(read_request)
|
149
|
+
read_request = read_packet(read_length: atomic_read_size, offset: offset, credit_charge: credit_charge)
|
150
|
+
raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
|
143
151
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
144
152
|
unless response.valid?
|
145
153
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -150,7 +158,7 @@ module RubySMB
|
|
150
158
|
)
|
151
159
|
end
|
152
160
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
153
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
161
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
154
162
|
end
|
155
163
|
|
156
164
|
data << response.buffer.to_binary_s
|
@@ -163,17 +171,19 @@ module RubySMB
|
|
163
171
|
#
|
164
172
|
# @param bytes [Integer] the number of bytes to read
|
165
173
|
# @param offset [Integer] the byte offset in the file to start reading from
|
174
|
+
# @param credit_charge [Integer] the number of credits that this request consumes
|
166
175
|
# @return [RubySMB::SMB2::Packet::ReadRequest] the data read from the file
|
167
|
-
def read_packet(read_length: 0, offset: 0)
|
176
|
+
def read_packet(read_length: 0, offset: 0, credit_charge: 1)
|
168
177
|
read_request = set_header_fields(RubySMB::SMB2::Packet::ReadRequest.new)
|
169
178
|
read_request.read_length = read_length
|
170
179
|
read_request.offset = offset
|
180
|
+
read_request.smb2_header.credit_charge = credit_charge
|
171
181
|
read_request
|
172
182
|
end
|
173
|
-
|
183
|
+
|
174
184
|
def send_recv_read(read_length: 0, offset: 0)
|
175
185
|
read_request = read_packet(read_length: read_length, offset: offset)
|
176
|
-
raw_response = tree.client.send_recv(read_request)
|
186
|
+
raw_response = tree.client.send_recv(read_request, encrypt: @tree_connect_encrypt_data)
|
177
187
|
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
178
188
|
unless response.valid?
|
179
189
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -183,20 +193,8 @@ module RubySMB
|
|
183
193
|
received_cmd: response.smb2_header.command
|
184
194
|
)
|
185
195
|
end
|
186
|
-
|
187
|
-
|
188
|
-
raw_response = tree.client.dispatcher.recv_packet
|
189
|
-
response = RubySMB::SMB2::Packet::ReadResponse.read(raw_response)
|
190
|
-
unless response.valid?
|
191
|
-
raise RubySMB::Error::InvalidPacket.new(
|
192
|
-
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
193
|
-
expected_cmd: RubySMB::SMB2::Packet::ReadResponse::COMMAND,
|
194
|
-
received_proto: response.smb2_header.protocol,
|
195
|
-
received_cmd: response.smb2_header.command
|
196
|
-
)
|
197
|
-
end
|
198
|
-
elsif response.status_code != WindowsError::NTStatus::STATUS_SUCCESS
|
199
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
196
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
197
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
200
198
|
end
|
201
199
|
response.buffer.to_binary_s
|
202
200
|
end
|
@@ -206,7 +204,7 @@ module RubySMB
|
|
206
204
|
# @return [WindowsError::ErrorCode] the NTStatus Response code
|
207
205
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
|
208
206
|
def delete
|
209
|
-
raw_response = tree.client.send_recv(delete_packet)
|
207
|
+
raw_response = tree.client.send_recv(delete_packet, encrypt: @tree_connect_encrypt_data)
|
210
208
|
response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
|
211
209
|
unless response.valid?
|
212
210
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -246,17 +244,19 @@ module RubySMB
|
|
246
244
|
# @return [WindowsError::ErrorCode] the NTStatus code returned from the operation
|
247
245
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a WriteResponse packet
|
248
246
|
def write(data:'', offset: 0)
|
247
|
+
max_write = tree.client.server_max_write_size
|
248
|
+
max_write = 65536 unless tree.client.server_supports_multi_credit
|
249
249
|
buffer = data.dup
|
250
250
|
bytes = data.length
|
251
|
-
atomic_write_size =
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
251
|
+
atomic_write_size = [bytes, max_write].min
|
252
|
+
credit_charge = 0
|
253
|
+
if tree.client.server_supports_multi_credit
|
254
|
+
credit_charge = (atomic_write_size - 1) / 65536 + 1
|
255
|
+
end
|
256
256
|
|
257
257
|
while buffer.length > 0 do
|
258
|
-
write_request = write_packet(data: buffer.slice!(0,atomic_write_size), offset: offset)
|
259
|
-
raw_response = tree.client.send_recv(write_request)
|
258
|
+
write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset, credit_charge: credit_charge)
|
259
|
+
raw_response = tree.client.send_recv(write_request, encrypt: @tree_connect_encrypt_data)
|
260
260
|
response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
|
261
261
|
unless response.valid?
|
262
262
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -268,7 +268,7 @@ module RubySMB
|
|
268
268
|
end
|
269
269
|
status = response.smb2_header.nt_status.to_nt_status
|
270
270
|
|
271
|
-
offset+= atomic_write_size
|
271
|
+
offset += atomic_write_size
|
272
272
|
return status unless status == WindowsError::NTStatus::STATUS_SUCCESS
|
273
273
|
end
|
274
274
|
|
@@ -279,17 +279,19 @@ module RubySMB
|
|
279
279
|
#
|
280
280
|
# @param data [String] the data to write to the file
|
281
281
|
# @param offset [Integer] the offset in the file to start writing from
|
282
|
+
# @param credit_charge [Integer] the number of credits that this request consumes
|
282
283
|
# @return []RubySMB::SMB2::Packet::WriteRequest] the request packet
|
283
|
-
def write_packet(data:'', offset: 0)
|
284
|
+
def write_packet(data:'', offset: 0, credit_charge: 1)
|
284
285
|
write_request = set_header_fields(RubySMB::SMB2::Packet::WriteRequest.new)
|
285
286
|
write_request.write_offset = offset
|
286
287
|
write_request.buffer = data
|
288
|
+
write_request.smb2_header.credit_charge = credit_charge
|
287
289
|
write_request
|
288
290
|
end
|
289
|
-
|
291
|
+
|
290
292
|
def send_recv_write(data:'', offset: 0)
|
291
293
|
pkt = write_packet(data: data, offset: offset)
|
292
|
-
raw_response = tree.client.send_recv(pkt)
|
294
|
+
raw_response = tree.client.send_recv(pkt, encrypt: @tree_connect_encrypt_data)
|
293
295
|
response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
|
294
296
|
unless response.valid?
|
295
297
|
raise RubySMB::Error::InvalidPacket.new(
|
@@ -299,31 +301,19 @@ module RubySMB
|
|
299
301
|
received_cmd: response.smb2_header.command
|
300
302
|
)
|
301
303
|
end
|
302
|
-
|
303
|
-
|
304
|
-
raw_response = tree.client.dispatcher.recv_packet
|
305
|
-
response = RubySMB::SMB2::Packet::WriteResponse.read(raw_response)
|
306
|
-
unless response.valid?
|
307
|
-
raise RubySMB::Error::InvalidPacket.new(
|
308
|
-
expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
309
|
-
expected_cmd: RubySMB::SMB2::Packet::WriteResponse::COMMAND,
|
310
|
-
received_proto: response.smb2_header.protocol,
|
311
|
-
received_cmd: response.smb2_header.command
|
312
|
-
)
|
313
|
-
end
|
314
|
-
elsif response.status_code != WindowsError::NTStatus::STATUS_SUCCESS
|
315
|
-
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
304
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
305
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code
|
316
306
|
end
|
317
307
|
response.write_count
|
318
308
|
end
|
319
|
-
|
309
|
+
|
320
310
|
# Rename a file
|
321
311
|
#
|
322
312
|
# @param new_file_name [String] the new name
|
323
313
|
# @return [WindowsError::ErrorCode] the NTStatus Response code
|
324
314
|
# @raise [RubySMB::Error::InvalidPacket] if the response is not a SetInfoResponse packet
|
325
315
|
def rename(new_file_name)
|
326
|
-
raw_response = tree.client.send_recv(rename_packet(new_file_name))
|
316
|
+
raw_response = tree.client.send_recv(rename_packet(new_file_name), encrypt: @tree_connect_encrypt_data)
|
327
317
|
response = RubySMB::SMB2::Packet::SetInfoResponse.read(raw_response)
|
328
318
|
unless response.valid?
|
329
319
|
raise RubySMB::Error::InvalidPacket.new(
|