ruby_smb 1.0.0 → 1.1.0

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.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.travis.yml +4 -1
  4. data/README.md +35 -47
  5. data/examples/enum_registry_key.rb +28 -0
  6. data/examples/enum_registry_values.rb +30 -0
  7. data/examples/pipes.rb +2 -1
  8. data/examples/read_registry_key_value.rb +32 -0
  9. data/lib/ruby_smb/client/authentication.rb +43 -25
  10. data/lib/ruby_smb/client/echo.rb +20 -2
  11. data/lib/ruby_smb/client/negotiation.rb +27 -12
  12. data/lib/ruby_smb/client/tree_connect.rb +20 -14
  13. data/lib/ruby_smb/client/utils.rb +2 -2
  14. data/lib/ruby_smb/client/winreg.rb +46 -0
  15. data/lib/ruby_smb/client.rb +28 -4
  16. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  17. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  18. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  19. data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
  20. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  21. data/lib/ruby_smb/dcerpc/request.rb +28 -9
  22. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
  23. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  24. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  25. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  26. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  27. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  28. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  29. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  30. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  31. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  32. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  33. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  34. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  35. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  36. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  37. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
  38. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  39. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  40. data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
  41. data/lib/ruby_smb/dcerpc.rb +38 -0
  42. data/lib/ruby_smb/dispatcher/socket.rb +3 -1
  43. data/lib/ruby_smb/error.rb +40 -1
  44. data/lib/ruby_smb/generic_packet.rb +33 -4
  45. data/lib/ruby_smb/smb1/file.rb +67 -11
  46. data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
  47. data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
  48. data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
  49. data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
  50. data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
  51. data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
  52. data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
  53. data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
  54. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
  55. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
  56. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
  57. data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
  58. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
  59. data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
  60. data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
  61. data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
  62. data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
  63. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
  64. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
  65. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -1
  66. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
  67. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
  68. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
  69. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
  70. data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
  71. data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
  72. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
  73. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
  74. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
  75. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
  76. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
  77. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
  78. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
  79. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
  80. data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
  81. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
  82. data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
  83. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
  84. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
  85. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
  86. data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
  87. data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
  88. data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
  89. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +2 -5
  90. data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
  91. data/lib/ruby_smb/smb1/pipe.rb +86 -5
  92. data/lib/ruby_smb/smb1/tree.rb +40 -2
  93. data/lib/ruby_smb/smb2/file.rb +97 -1
  94. data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
  95. data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
  96. data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
  97. data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
  98. data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
  99. data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
  100. data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
  101. data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
  102. data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
  103. data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
  104. data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
  105. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +2 -5
  106. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
  107. data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
  108. data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
  109. data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
  110. data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
  111. data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
  112. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
  113. data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
  114. data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
  115. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +2 -5
  116. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
  117. data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
  118. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
  119. data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
  120. data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
  121. data/lib/ruby_smb/smb2/pipe.rb +98 -11
  122. data/lib/ruby_smb/smb2/tree.rb +44 -6
  123. data/lib/ruby_smb/version.rb +1 -1
  124. data/lib/ruby_smb.rb +0 -1
  125. data/ruby_smb.gemspec +3 -3
  126. data/spec/lib/ruby_smb/client_spec.rb +271 -11
  127. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  128. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  129. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
  130. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  131. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
  132. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  133. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  134. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  135. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  136. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
  137. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  138. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  139. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  140. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  141. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  142. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
  143. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  144. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
  145. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  146. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  147. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
  148. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  149. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
  150. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  151. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +3 -1
  152. data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
  153. data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
  154. data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
  155. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
  156. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
  157. data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
  158. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
  159. data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
  160. data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
  161. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +78 -0
  162. data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
  163. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
  164. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +322 -145
  165. data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
  166. data.tar.gz.sig +0 -0
  167. metadata +70 -11
  168. metadata.gz.sig +0 -0
  169. data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
  170. data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
  171. data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
@@ -0,0 +1,340 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Winreg
4
+
5
+ UUID = '338CD001-2244-31F1-AAAA-900038001003'
6
+ VER_MAJOR = 1
7
+ VER_MINOR = 0
8
+
9
+ # Operation numbers
10
+ OPEN_HKCR = 0x00
11
+ OPEN_HKCU = 0x01
12
+ OPEN_HKLM = 0x02
13
+ OPEN_HKPD = 0x03
14
+ OPEN_HKU = 0x04
15
+ REG_CLOSE_KEY = 0x05
16
+ REG_ENUM_KEY = 0x09
17
+ REG_ENUM_VALUE = 0x0a
18
+ REG_OPEN_KEY = 0x0f
19
+ REG_QUERY_INFO_KEY = 0x10
20
+ REG_QUERY_VALUE = 0x11
21
+ OPEN_HKCC = 0x1b
22
+ OPEN_HKPT = 0x20
23
+ OPEN_HKPN = 0x21
24
+
25
+ require 'ruby_smb/dcerpc/winreg/regsam'
26
+ require 'ruby_smb/dcerpc/winreg/open_root_key_request'
27
+ require 'ruby_smb/dcerpc/winreg/open_root_key_response'
28
+ require 'ruby_smb/dcerpc/winreg/close_key_request'
29
+ require 'ruby_smb/dcerpc/winreg/close_key_response'
30
+ require 'ruby_smb/dcerpc/winreg/enum_key_request'
31
+ require 'ruby_smb/dcerpc/winreg/enum_key_response'
32
+ require 'ruby_smb/dcerpc/winreg/enum_value_request'
33
+ require 'ruby_smb/dcerpc/winreg/enum_value_response'
34
+ require 'ruby_smb/dcerpc/winreg/open_key_request'
35
+ require 'ruby_smb/dcerpc/winreg/open_key_response'
36
+ require 'ruby_smb/dcerpc/winreg/query_info_key_request'
37
+ require 'ruby_smb/dcerpc/winreg/query_info_key_response'
38
+ require 'ruby_smb/dcerpc/winreg/query_value_request'
39
+ require 'ruby_smb/dcerpc/winreg/query_value_response'
40
+
41
+ ROOT_KEY_MAP = {
42
+ "HKEY_CLASSES_ROOT" => OPEN_HKCR,
43
+ "HKCR" => OPEN_HKCR,
44
+ "HKEY_CURRENT_USER" => OPEN_HKCU,
45
+ "HKCU" => OPEN_HKCU,
46
+ "HKEY_LOCAL_MACHINE" => OPEN_HKLM,
47
+ "HKLM" => OPEN_HKLM,
48
+ "HKEY_PERFORMANCE_DATA" => OPEN_HKPD,
49
+ "HKPD" => OPEN_HKPD,
50
+ "HKEY_USERS" => OPEN_HKU,
51
+ "HKU" => OPEN_HKU,
52
+ "HKEY_CURRENT_CONFIG" => OPEN_HKCC,
53
+ "HKCC" => OPEN_HKCC,
54
+ "HKEY_PERFORMANCE_TEXT" => OPEN_HKPT,
55
+ "HKPT" => OPEN_HKPT,
56
+ "HKEY_PERFORMANCE_NLS_TEXT" => OPEN_HKPN,
57
+ "HKPN" => OPEN_HKPN
58
+ }
59
+
60
+ # Open the registry root key and return a handle for it. The key can be
61
+ # either a long format (e.g. HKEY_LOCAL_MACHINE) or a short format
62
+ # (e.g. HKLM)
63
+ #
64
+ # @param root_key [String] the root key to open
65
+ # @return [Ndr::NdrContextHandle] the RPC context handle for the root key
66
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenRootKeyResponse packet
67
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
68
+ def open_root_key(root_key)
69
+ root_key_opnum = RubySMB::Dcerpc::Winreg::ROOT_KEY_MAP[root_key]
70
+ raise ArgumentError, "Unknown Root Key: #{root_key}" unless root_key_opnum
71
+
72
+ root_key_request_packet = OpenRootKeyRequest.new(opnum: root_key_opnum)
73
+ response = dcerpc_request(root_key_request_packet)
74
+
75
+ begin
76
+ root_key_response_packet = OpenRootKeyResponse.read(response)
77
+ rescue IOError
78
+ raise RubySMB::Dcerpc::Error::InvalidPacket,
79
+ "Error reading OpenRootKeyResponse (command = #{root_key_opnum})"
80
+ end
81
+ unless root_key_response_packet.error_status == WindowsError::Win32::ERROR_SUCCESS
82
+ raise RubySMB::Dcerpc::Error::WinregError,
83
+ "Error returned when opening root key #{root_key}: "\
84
+ "#{WindowsError::Win32.find_by_retval(root_key_response_packet.error_status.value).join(',')}"
85
+ end
86
+
87
+ root_key_response_packet.ph_key
88
+ end
89
+
90
+ # Open the registry key specified by a root key handle (previously open
91
+ # with #open_root_key) and a subkey. It returns a handle for the key.
92
+ #
93
+ # @param handle [Ndr::NdrContextHandle] the handle for the root key
94
+ # @param sub_key [String] the subkey to open
95
+ # @return [Ndr::NdrContextHandle] the RPC context handle for the key
96
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenKeyResponse packet
97
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
98
+ def open_key(handle, sub_key)
99
+ openkey_request_packet = RubySMB::Dcerpc::Winreg::OpenKeyRequest.new(hkey: handle, lp_sub_key: sub_key)
100
+ openkey_request_packet.sam_desired.read_control = 1
101
+ openkey_request_packet.sam_desired.key_query_value = 1
102
+ openkey_request_packet.sam_desired.key_enumerate_sub_keys = 1
103
+ openkey_request_packet.sam_desired.key_notify = 1
104
+ response = dcerpc_request(openkey_request_packet)
105
+ begin
106
+ open_key_response = RubySMB::Dcerpc::Winreg::OpenKeyResponse.read(response)
107
+ rescue IOError
108
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the OpenKey response"
109
+ end
110
+ unless open_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
111
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when opening subkey #{sub_key}: "\
112
+ "#{WindowsError::Win32.find_by_retval(open_key_response.error_status.value).join(',')}"
113
+ end
114
+
115
+ open_key_response.phk_result
116
+ end
117
+
118
+ # Retrieve the data associated with the named value of a specified
119
+ # registry open key.
120
+ #
121
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
122
+ # @param value_name [String] the name of the value
123
+ # @return [String] the data of the value entry
124
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryValueResponse packet
125
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
126
+ def query_value(handle, value_name)
127
+ query_value_request_packet = RubySMB::Dcerpc::Winreg::QueryValueRequest.new(hkey: handle, lp_value_name: value_name)
128
+ query_value_request_packet.lp_data.referent_identifier = 0
129
+ response = dcerpc_request(query_value_request_packet)
130
+ begin
131
+ query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
132
+ rescue IOError
133
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the QueryValue response"
134
+ end
135
+ unless query_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
136
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when reading value #{value_name}: "\
137
+ "#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
138
+ end
139
+
140
+ query_value_request_packet = RubySMB::Dcerpc::Winreg::QueryValueRequest.new(hkey: handle, lp_value_name: value_name)
141
+ query_value_request_packet.lpcb_data = query_value_response.lpcb_data
142
+ query_value_request_packet.lp_data.max_count = query_value_response.lpcb_data.referent
143
+ response = dcerpc_request(query_value_request_packet)
144
+ begin
145
+ query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
146
+ rescue IOError
147
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the QueryValue response"
148
+ end
149
+ unless query_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
150
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when reading value #{value_name}: "\
151
+ "#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
152
+ end
153
+
154
+ query_value_response.data
155
+ end
156
+
157
+ # Close the handle to the registry key.
158
+ #
159
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
160
+ # @return [WindowsError::Win32] the response error status
161
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a CloseKeyResponse packet
162
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
163
+ def close_key(handle)
164
+ close_key_request_packet = RubySMB::Dcerpc::Winreg::CloseKeyRequest.new(hkey: handle)
165
+ response = dcerpc_request(close_key_request_packet)
166
+ begin
167
+ close_key_response = RubySMB::Dcerpc::Winreg::CloseKeyResponse.read(response)
168
+ rescue IOError
169
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the CloseKey response"
170
+ end
171
+ unless close_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
172
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when closing the key: "\
173
+ "#{WindowsError::Win32.find_by_retval(close_key_response.error_status.value).join(',')}"
174
+ end
175
+
176
+ close_key_response.error_status
177
+ end
178
+
179
+ # Retrive relevant information on the key that corresponds to the
180
+ # specified key handle.
181
+ #
182
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
183
+ # @return [RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse] the QueryInfoKeyResponse packet
184
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryInfoKeyResponse packet
185
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
186
+ def query_info_key(handle)
187
+ query_info_key_request_packet = RubySMB::Dcerpc::Winreg::QueryInfoKeyRequest.new(hkey: handle)
188
+ response = dcerpc_request(query_info_key_request_packet)
189
+ begin
190
+ query_info_key_response = RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse.read(response)
191
+ rescue IOError
192
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the query_infoKey response"
193
+ end
194
+ unless query_info_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
195
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when querying information: "\
196
+ "#{WindowsError::Win32.find_by_retval(query_info_key_response.error_status.value).join(',')}"
197
+ end
198
+
199
+ query_info_key_response
200
+ end
201
+
202
+ # Enumerate the subkey at the specified index.
203
+ #
204
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
205
+ # @param index [Numeric] the index of the subkey
206
+ # @return [String] the subkey name
207
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a EnumKeyResponse packet
208
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
209
+ def enum_key(handle, index)
210
+ enum_key_request_packet = RubySMB::Dcerpc::Winreg::EnumKeyRequest.new(hkey: handle, dw_index: index)
211
+ enum_key_request_packet.lpft_last_write_time = 0
212
+ enum_key_request_packet.lp_class.referent.buffer = 0
213
+ enum_key_request_packet.lp_name.buffer.referent.max_count = 256
214
+ response = dcerpc_request(enum_key_request_packet)
215
+ begin
216
+ enum_key_response = RubySMB::Dcerpc::Winreg::EnumKeyResponse.read(response)
217
+ rescue IOError
218
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the EnumKey response"
219
+ end
220
+ unless enum_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
221
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when enumerating the key: "\
222
+ "#{WindowsError::Win32.find_by_retval(enum_key_response.error_status.value).join(',')}"
223
+ end
224
+
225
+ enum_key_response.lp_name.to_s
226
+ end
227
+
228
+ # Enumerate the value at the specified index for the specified registry key.
229
+ #
230
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
231
+ # @param index [Numeric] the index of the subkey
232
+ # @return [String] the data of the value entry
233
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a EnumValueResponse packet
234
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
235
+ def enum_value(handle, index)
236
+ enum_value_request_packet = RubySMB::Dcerpc::Winreg::EnumValueRequest.new(hkey: handle, dw_index: index)
237
+ enum_value_request_packet.lp_data.referent_identifier = 0
238
+ enum_value_request_packet.lp_value_name.buffer.referent.max_count = 256
239
+ response = dcerpc_request(enum_value_request_packet)
240
+ begin
241
+ enum_value_response = RubySMB::Dcerpc::Winreg::EnumValueResponse.read(response)
242
+ rescue IOError
243
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the Enumvalue response"
244
+ end
245
+ unless enum_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
246
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when enumerating values: "\
247
+ "#{WindowsError::Win32.find_by_retval(enum_value_response.error_status.value).join(',')}"
248
+ end
249
+
250
+ enum_value_response.lp_value_name.to_s
251
+ end
252
+
253
+ # Checks if the specified registry key exists. It returns true if it
254
+ # exists, false otherwise.
255
+ #
256
+ # @param key [String] the registry key to check
257
+ # @return [Boolean]
258
+ def has_registry_key?(key)
259
+ bind(endpoint: RubySMB::Dcerpc::Winreg)
260
+
261
+ root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
262
+ begin
263
+ root_key_handle = open_root_key(root_key)
264
+ subkey_handle = open_key(root_key_handle, sub_key)
265
+ rescue RubySMB::Dcerpc::Error::WinregError
266
+ return false
267
+ end
268
+ close_key(subkey_handle)
269
+ return true
270
+ end
271
+
272
+ # Retrieve the data associated with the named value of a specified
273
+ # registry key.
274
+ #
275
+ # @param key [String] the registry key
276
+ # @param value_name [String] the name of the value to read
277
+ # @return [String] the data of the value entry
278
+ def read_registry_key_value(key, value_name)
279
+ bind(endpoint: RubySMB::Dcerpc::Winreg)
280
+
281
+ root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
282
+ root_key_handle = open_root_key(root_key)
283
+ subkey_handle = open_key(root_key_handle, sub_key)
284
+ value = query_value(subkey_handle, value_name)
285
+ close_key(subkey_handle)
286
+ value
287
+ end
288
+
289
+ # Enumerate the subkeys of a specified registry key. If only a root key
290
+ # is provided, it enumerates its subkeys.
291
+ #
292
+ # @param key [String] the registry key
293
+ # @return [Array<String>] the subkeys
294
+ def enum_registry_key(key)
295
+ bind(endpoint: RubySMB::Dcerpc::Winreg)
296
+
297
+ root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
298
+ root_key_handle = open_root_key(root_key)
299
+ subkey_handle = if sub_key.nil? || sub_key.empty?
300
+ root_key_handle
301
+ else
302
+ open_key(root_key_handle, sub_key)
303
+ end
304
+ query_info_key_response = query_info_key(subkey_handle)
305
+ key_count = query_info_key_response.lpc_sub_keys.to_i
306
+ enum_result = []
307
+ key_count.times do |i|
308
+ enum_result << enum_key(subkey_handle, i)
309
+ end
310
+ close_key(subkey_handle)
311
+ enum_result
312
+ end
313
+
314
+ # Enumerate the values for the specified registry key.
315
+ #
316
+ # @param key [String] the registry key
317
+ # @return [Array<String>] the values
318
+ def enum_registry_values(key)
319
+ bind(endpoint: RubySMB::Dcerpc::Winreg)
320
+
321
+ root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
322
+ root_key_handle = open_root_key(root_key)
323
+ subkey_handle = if sub_key.nil? || sub_key.empty?
324
+ root_key_handle
325
+ else
326
+ open_key(root_key_handle, sub_key)
327
+ end
328
+ query_info_key_response = query_info_key(subkey_handle)
329
+ value_count = query_info_key_response.lpc_values.to_i
330
+ enum_result = []
331
+ value_count.times do |i|
332
+ enum_result << enum_value(subkey_handle, i)
333
+ end
334
+ close_key(subkey_handle)
335
+ enum_result
336
+ end
337
+
338
+ end
339
+ end
340
+ end
@@ -1,15 +1,53 @@
1
1
  module RubySMB
2
2
  module Dcerpc
3
+ MAX_XMIT_FRAG = 4280
4
+ MAX_RECV_FRAG = 4280
5
+
6
+ require 'windows_error/win32'
3
7
  require 'ruby_smb/dcerpc/error'
4
8
  require 'ruby_smb/dcerpc/uuid'
5
9
  require 'ruby_smb/dcerpc/ndr'
6
10
  require 'ruby_smb/dcerpc/ptypes'
7
11
  require 'ruby_smb/dcerpc/p_syntax_id_t'
12
+ require 'ruby_smb/dcerpc/rrp_unicode_string'
8
13
  require 'ruby_smb/dcerpc/pdu_header'
9
14
  require 'ruby_smb/dcerpc/srvsvc'
15
+ require 'ruby_smb/dcerpc/winreg'
10
16
  require 'ruby_smb/dcerpc/request'
11
17
  require 'ruby_smb/dcerpc/response'
12
18
  require 'ruby_smb/dcerpc/bind'
13
19
  require 'ruby_smb/dcerpc/bind_ack'
20
+
21
+
22
+ # Bind to the remote server interface endpoint.
23
+ #
24
+ # @param options [Hash] the options to pass to the Bind request packet. At least, :endpoint must but provided with an existing Dcerpc class
25
+ # @return [RubySMB::Dcerpc::BindAck] the BindAck response packet
26
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if an invalid packet is received
27
+ # @raise [RubySMB::Dcerpc::Error::BindError] if the response is not a BindAck packet or if the Bind result code is not ACCEPTANCE
28
+ def bind(options={})
29
+ bind_req = RubySMB::Dcerpc::Bind.new(options)
30
+ write(data: bind_req.to_binary_s)
31
+ @size = 1024
32
+ dcerpc_raw_response = read()
33
+ begin
34
+ dcerpc_response = RubySMB::Dcerpc::BindAck.read(dcerpc_raw_response)
35
+ rescue IOError
36
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
37
+ end
38
+ unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::BIND_ACK
39
+ raise RubySMB::Dcerpc::Error::BindError, "Not a BindAck packet"
40
+ end
41
+
42
+ res_list = dcerpc_response.p_result_list
43
+ if res_list.n_results == 0 ||
44
+ res_list.p_results[0].result != RubySMB::Dcerpc::BindAck::ACCEPTANCE
45
+ raise RubySMB::Dcerpc::Error::BindError,
46
+ "Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
47
+ end
48
+ @tree.client.max_buffer_size = dcerpc_response.max_xmit_frag
49
+ dcerpc_response
50
+ end
51
+
14
52
  end
15
53
  end
@@ -66,7 +66,9 @@ module RubySMB
66
66
  end
67
67
 
68
68
  begin
69
- nbss_header = RubySMB::Nbss::SessionHeader.read(@tcp_socket)
69
+ nbss_data = @tcp_socket.read(4)
70
+ raise IOError if nbss_data.nil?
71
+ nbss_header = RubySMB::Nbss::SessionHeader.read(nbss_data)
70
72
  rescue IOError
71
73
  raise ::RubySMB::Error::NetBiosSessionService, 'NBSS Header is missing'
72
74
  end
@@ -15,7 +15,42 @@ module RubySMB
15
15
 
16
16
  # Raised when trying to parse raw binary into a Packet and the data
17
17
  # is invalid.
18
- class InvalidPacket < RubySMBError; end
18
+ class InvalidPacket < RubySMBError
19
+ def initialize(args = nil)
20
+ if args.nil?
21
+ super
22
+ elsif args.is_a? String
23
+ super(args)
24
+ 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[:received_proto] ? translate_protocol(args[:received_proto]) : "???"
28
+ received_cmd = args[:received_cmd] || "???"
29
+ super(
30
+ "Expecting #{expected_proto} protocol "\
31
+ "with command=#{expected_cmd}"\
32
+ "#{(" (" + args[:expected_custom] + ")") if args[:expected_custom]}, "\
33
+ "got #{received_proto} protocol "\
34
+ "with command=#{received_cmd}"\
35
+ "#{(" (" + args[:received_custom] + ")") if args[:received_custom]}"
36
+ )
37
+ else
38
+ raise ArgumentError, "InvalidPacket expects a String or a Hash, got a #{args.class}"
39
+ end
40
+ end
41
+
42
+ def translate_protocol(proto)
43
+ case proto
44
+ when RubySMB::SMB1::SMB_PROTOCOL_ID
45
+ 'SMB1'
46
+ when RubySMB::SMB2::SMB2_PROTOCOL_ID
47
+ 'SMB2'
48
+ else
49
+ raise ArgumentError, 'Unknown SMB protocol'
50
+ end
51
+ end
52
+ private :translate_protocol
53
+ end
19
54
 
20
55
  # Raised when a response packet has a NTStatus code that was unexpected.
21
56
  class UnexpectedStatusCode < RubySMBError; end
@@ -26,5 +61,9 @@ module RubySMB
26
61
  # Raised when Protocol Negotiation fails, possibly due to an
27
62
  # unsupported protocol.
28
63
  class NegotiationFailure < RubySMBError; end
64
+
65
+ # Raised when trying to parse raw binary into a BitField and the data
66
+ # is invalid.
67
+ class InvalidBitField < RubySMBError; end
29
68
  end
30
69
  end
@@ -45,14 +45,16 @@ module RubySMB
45
45
  rescue IOError => e
46
46
  case self.to_s
47
47
  when /EmptyPacket|ErrorPacket/
48
- raise e
48
+ raise RubySMB::Error::InvalidPacket, 'Not a valid SMB packet'
49
49
  when /SMB1/
50
- RubySMB::SMB1::Packet::EmptyPacket.read(val)
50
+ packet = RubySMB::SMB1::Packet::EmptyPacket.read(val)
51
51
  when /SMB2/
52
- RubySMB::SMB2::Packet::ErrorPacket.read(val)
52
+ packet = RubySMB::SMB2::Packet::ErrorPacket.read(val)
53
53
  else
54
- raise e
54
+ raise RubySMB::Error::InvalidPacket, 'Not a valid SMB packet'
55
55
  end
56
+ packet.original_command = self::COMMAND
57
+ packet
56
58
  end
57
59
  end
58
60
 
@@ -72,6 +74,33 @@ module RubySMB
72
74
  status_code
73
75
  end
74
76
 
77
+ # Validates the packet protocol ID and the SMB command
78
+ #
79
+ # @return [TrueClass, FalseClass] true if the packet is valid, false otherwise
80
+ def valid?
81
+ case packet_smb_version
82
+ when 'SMB1'
83
+ return smb_header.protocol == RubySMB::SMB1::SMB_PROTOCOL_ID &&
84
+ smb_header.command == self.class::COMMAND
85
+ when 'SMB2'
86
+ return smb2_header.protocol == RubySMB::SMB2::SMB2_PROTOCOL_ID &&
87
+ smb2_header.command == self.class::COMMAND
88
+ end
89
+ end
90
+
91
+ def initialize_instance
92
+ super
93
+
94
+ unless [RubySMB::SMB1::Packet::EmptyPacket, RubySMB::SMB2::Packet::ErrorPacket].any? {|klass| self.is_a? klass}
95
+ case packet_smb_version
96
+ when 'SMB1'
97
+ smb_header.command = self.class::COMMAND
98
+ when 'SMB2'
99
+ smb2_header.command = self.class::COMMAND
100
+ end
101
+ end
102
+ end
103
+
75
104
  # Returns an array of hashes representing the
76
105
  # fields for this record.
77
106
  #
@@ -76,14 +76,19 @@ module RubySMB
76
76
  # Closes the handle to the remote file.
77
77
  #
78
78
  # @return [WindowsError::ErrorCode] the NTStatus code returned by the operation
79
- # @raise [RubySMB::Error::InvalidPacket] if the response command is not SMB_COM_CLOSE
79
+ # @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
80
80
  # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
81
81
  def close
82
82
  close_request = set_header_fields(RubySMB::SMB1::Packet::CloseRequest.new)
83
83
  raw_response = @tree.client.send_recv(close_request)
84
84
  response = RubySMB::SMB1::Packet::CloseResponse.read(raw_response)
85
- unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_CLOSE
86
- raise RubySMB::Error::InvalidPacket, 'Not a CloseResponse packet'
85
+ unless response.valid?
86
+ raise RubySMB::Error::InvalidPacket.new(
87
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
88
+ expected_cmd: RubySMB::SMB1::Packet::CloseResponse::COMMAND,
89
+ received_proto: response.smb_header.protocol,
90
+ received_cmd: response.smb_header.command
91
+ )
87
92
  end
88
93
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
89
94
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
@@ -98,7 +103,7 @@ module RubySMB
98
103
  # @param bytes [Integer] the number of bytes to read
99
104
  # @param offset [Integer] the byte offset in the file to start reading from
100
105
  # @return [String] the data read from the file
101
- # @raise [RubySMB::Error::InvalidPacket] if the response command is not SMB_COM_READ_ANDX
106
+ # @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
102
107
  # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
103
108
  def read(bytes: @size, offset: 0)
104
109
  atomic_read_size = if bytes > @tree.client.max_buffer_size
@@ -113,8 +118,13 @@ module RubySMB
113
118
  read_request = read_packet(read_length: atomic_read_size, offset: offset)
114
119
  raw_response = @tree.client.send_recv(read_request)
115
120
  response = RubySMB::SMB1::Packet::ReadAndxResponse.read(raw_response)
116
- unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_READ_ANDX
117
- raise RubySMB::Error::InvalidPacket, 'Not a ReadAndxResponse packet'
121
+ unless response.valid?
122
+ raise RubySMB::Error::InvalidPacket.new(
123
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
124
+ expected_cmd: RubySMB::SMB1::Packet::ReadAndxResponse::COMMAND,
125
+ received_proto: response.smb_header.protocol,
126
+ received_cmd: response.smb_header.command
127
+ )
118
128
  end
119
129
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
120
130
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
@@ -146,23 +156,47 @@ module RubySMB
146
156
  def read_packet(read_length: 0, offset: 0)
147
157
  read_request = set_header_fields(RubySMB::SMB1::Packet::ReadAndxRequest.new)
148
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
149
161
  read_request.parameter_block.offset = offset
150
162
  read_request
151
163
  end
152
-
164
+
153
165
  def send_recv_read(read_length: 0, offset: 0)
154
166
  read_request = read_packet(read_length: read_length, offset: offset)
155
167
  raw_response = tree.client.send_recv(read_request)
168
+
156
169
  response = RubySMB::SMB1::Packet::ReadAndxResponse.read(raw_response)
170
+ unless response.valid?
171
+ raise RubySMB::Error::InvalidPacket.new(
172
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
173
+ expected_cmd: RubySMB::SMB1::Packet::ReadAndxResponse::COMMAND,
174
+ received_proto: response.smb_header.protocol,
175
+ received_cmd: response.smb_header.command
176
+ )
177
+ end
178
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
179
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
180
+ end
181
+
157
182
  response.data_block.data.to_binary_s
158
183
  end
159
184
 
160
185
  # Delete a file on close
161
186
  #
162
187
  # @return [WindowsError::ErrorCode] the NTStatus Response code
188
+ # @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
163
189
  def delete
164
190
  raw_response = @tree.client.send_recv(delete_packet)
165
191
  response = RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse.read(raw_response)
192
+ unless response.valid?
193
+ raise RubySMB::Error::InvalidPacket.new(
194
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
195
+ expected_cmd: RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse::COMMAND,
196
+ received_proto: response.smb_header.protocol,
197
+ received_cmd: response.smb_header.command
198
+ )
199
+ end
166
200
  response.status_code
167
201
  end
168
202
 
@@ -185,7 +219,7 @@ module RubySMB
185
219
  # @param data [String] the data to write to the file
186
220
  # @param offset [Integer] the offset in the file to start writing from
187
221
  # @return [Integer] the count of bytes written
188
- # @raise [RubySMB::Error::InvalidPacket] if the response command is not SMB_COM_WRITE_ANDX
222
+ # @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
189
223
  # @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
190
224
  def write(data:, offset: 0)
191
225
  buffer = data.dup
@@ -201,8 +235,13 @@ module RubySMB
201
235
  write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset)
202
236
  raw_response = @tree.client.send_recv(write_request)
203
237
  response = RubySMB::SMB1::Packet::WriteAndxResponse.read(raw_response)
204
- unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_WRITE_ANDX
205
- raise RubySMB::Error::InvalidPacket, 'Not a WriteAndxResponse packet'
238
+ unless response.valid?
239
+ raise RubySMB::Error::InvalidPacket.new(
240
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
241
+ expected_cmd: RubySMB::SMB1::Packet::WriteAndxResponse::COMMAND,
242
+ received_proto: response.smb_header.protocol,
243
+ received_cmd: response.smb_header.command
244
+ )
206
245
  end
207
246
  unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
208
247
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
@@ -230,12 +269,20 @@ module RubySMB
230
269
  write_request.parameter_block.remaining = write_request.parameter_block.data_length
231
270
  write_request
232
271
  end
233
-
272
+
234
273
  def send_recv_write(data:'', offset: 0)
235
274
  pkt = write_packet(data: data, offset: offset)
236
275
  pkt.set_64_bit_offset(true)
237
276
  raw_response = @tree.client.send_recv(pkt)
238
277
  response = RubySMB::SMB1::Packet::WriteAndxResponse.read(raw_response)
278
+ unless response.valid?
279
+ raise RubySMB::Error::InvalidPacket.new(
280
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
281
+ expected_cmd: RubySMB::SMB1::Packet::WriteAndxResponse::COMMAND,
282
+ received_proto: response.smb_header.protocol,
283
+ received_cmd: response.smb_header.command
284
+ )
285
+ end
239
286
  response.parameter_block.count_low
240
287
  end
241
288
 
@@ -243,9 +290,18 @@ module RubySMB
243
290
  #
244
291
  # @param new_file_name [String] the new name
245
292
  # @return [WindowsError::ErrorCode] the NTStatus Response code
293
+ # @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
246
294
  def rename(new_file_name)
247
295
  raw_response = tree.client.send_recv(rename_packet(new_file_name))
248
296
  response = RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse.read(raw_response)
297
+ unless response.valid?
298
+ raise RubySMB::Error::InvalidPacket.new(
299
+ expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
300
+ expected_cmd: RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse::COMMAND,
301
+ received_proto: response.smb_header.protocol,
302
+ received_cmd: response.smb_header.command
303
+ )
304
+ end
249
305
  response.status_code
250
306
  end
251
307