ruby_smb 1.1.0 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (163) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +3 -5
  5. data/Gemfile +6 -2
  6. data/examples/anonymous_auth.rb +3 -3
  7. data/examples/append_file.rb +10 -8
  8. data/examples/authenticate.rb +9 -5
  9. data/examples/delete_file.rb +8 -6
  10. data/examples/enum_registry_key.rb +5 -4
  11. data/examples/enum_registry_values.rb +5 -4
  12. data/examples/list_directory.rb +8 -6
  13. data/examples/negotiate.rb +51 -8
  14. data/examples/negotiate_with_netbios_service.rb +9 -5
  15. data/examples/net_share_enum_all.rb +6 -4
  16. data/examples/pipes.rb +11 -12
  17. data/examples/query_service_status.rb +64 -0
  18. data/examples/read_file.rb +8 -6
  19. data/examples/read_file_encryption.rb +56 -0
  20. data/examples/read_registry_key_value.rb +6 -5
  21. data/examples/rename_file.rb +9 -7
  22. data/examples/tree_connect.rb +7 -5
  23. data/examples/write_file.rb +9 -7
  24. data/lib/ruby_smb.rb +4 -0
  25. data/lib/ruby_smb/client.rb +246 -26
  26. data/lib/ruby_smb/client/authentication.rb +32 -18
  27. data/lib/ruby_smb/client/echo.rb +2 -4
  28. data/lib/ruby_smb/client/encryption.rb +62 -0
  29. data/lib/ruby_smb/client/negotiation.rb +156 -16
  30. data/lib/ruby_smb/client/signing.rb +19 -0
  31. data/lib/ruby_smb/client/tree_connect.rb +6 -8
  32. data/lib/ruby_smb/client/utils.rb +24 -17
  33. data/lib/ruby_smb/client/winreg.rb +1 -1
  34. data/lib/ruby_smb/crypto.rb +30 -0
  35. data/lib/ruby_smb/dcerpc.rb +2 -0
  36. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  37. data/lib/ruby_smb/dcerpc/ndr.rb +209 -44
  38. data/lib/ruby_smb/dcerpc/request.rb +13 -0
  39. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  40. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  41. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  46. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  58. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  59. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  60. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  61. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  62. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  63. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  64. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  65. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  66. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  67. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  68. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  69. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  70. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  71. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  72. data/lib/ruby_smb/dispatcher/socket.rb +5 -4
  73. data/lib/ruby_smb/error.rb +49 -6
  74. data/lib/ruby_smb/field/stringz16.rb +17 -1
  75. data/lib/ruby_smb/generic_packet.rb +11 -1
  76. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  77. data/lib/ruby_smb/smb1/commands.rb +1 -1
  78. data/lib/ruby_smb/smb1/file.rb +13 -28
  79. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
  80. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
  81. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  82. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
  83. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
  84. data/lib/ruby_smb/smb1/pipe.rb +8 -8
  85. data/lib/ruby_smb/smb1/tree.rb +25 -12
  86. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  87. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  88. data/lib/ruby_smb/smb2/file.rb +59 -77
  89. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  90. data/lib/ruby_smb/smb2/packet.rb +2 -0
  91. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  92. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
  93. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
  94. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  95. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
  96. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
  97. data/lib/ruby_smb/smb2/pipe.rb +8 -20
  98. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  99. data/lib/ruby_smb/smb2/tree.rb +44 -28
  100. data/lib/ruby_smb/version.rb +1 -1
  101. data/ruby_smb.gemspec +3 -1
  102. data/spec/lib/ruby_smb/client_spec.rb +1408 -70
  103. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  104. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  105. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  106. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  107. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  108. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  109. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  110. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  111. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  112. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  113. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  114. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  115. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  116. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  117. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  118. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  119. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  120. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  121. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  122. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  123. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  124. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  125. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  126. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  127. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  128. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  129. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  130. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  131. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  132. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  133. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  134. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  135. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  136. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
  137. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
  138. data/spec/lib/ruby_smb/error_spec.rb +88 -0
  139. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  140. data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
  141. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  142. data/spec/lib/ruby_smb/smb1/file_spec.rb +1 -3
  143. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  144. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  145. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  146. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  147. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
  148. data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
  149. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  150. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  151. data/spec/lib/ruby_smb/smb2/file_spec.rb +147 -71
  152. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  153. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  154. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  155. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  156. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  157. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  158. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
  159. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -45
  160. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  161. data/spec/lib/ruby_smb/smb2/tree_spec.rb +111 -9
  162. metadata +194 -75
  163. metadata.gz.sig +2 -1
@@ -0,0 +1,27 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Svcctl
6
+
7
+ # [3.1.4.19 RStartServiceW (Opnum 19)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/d9be95a2-cf01-4bdc-b30f-6fe4b37ada16)
8
+ class StartServiceWRequest < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ sc_rpc_handle :h_service
14
+ uint32 :argc
15
+ ndr_lp_string_ptrsw :argv
16
+
17
+ def initialize_instance
18
+ super
19
+ @opnum = START_SERVICE_W
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+
27
+
@@ -0,0 +1,25 @@
1
+ require 'ruby_smb/dcerpc/ndr'
2
+
3
+ module RubySMB
4
+ module Dcerpc
5
+ module Svcctl
6
+
7
+ # [3.1.4.19 RStartServiceW (Opnum 19)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-scmr/d9be95a2-cf01-4bdc-b30f-6fe4b37ada16)
8
+ class StartServiceWResponse < BinData::Record
9
+ attr_reader :opnum
10
+
11
+ endian :little
12
+
13
+ uint32 :error_status
14
+
15
+ def initialize_instance
16
+ super
17
+ @opnum = START_SERVICE_W
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+
25
+
@@ -13,11 +13,13 @@ module RubySMB
13
13
  OPEN_HKPD = 0x03
14
14
  OPEN_HKU = 0x04
15
15
  REG_CLOSE_KEY = 0x05
16
+ REG_CREATE_KEY = 0x06
16
17
  REG_ENUM_KEY = 0x09
17
18
  REG_ENUM_VALUE = 0x0a
18
19
  REG_OPEN_KEY = 0x0f
19
20
  REG_QUERY_INFO_KEY = 0x10
20
21
  REG_QUERY_VALUE = 0x11
22
+ REG_SAVE_KEY = 0x14
21
23
  OPEN_HKCC = 0x1b
22
24
  OPEN_HKPT = 0x20
23
25
  OPEN_HKPN = 0x21
@@ -37,6 +39,10 @@ module RubySMB
37
39
  require 'ruby_smb/dcerpc/winreg/query_info_key_response'
38
40
  require 'ruby_smb/dcerpc/winreg/query_value_request'
39
41
  require 'ruby_smb/dcerpc/winreg/query_value_response'
42
+ require 'ruby_smb/dcerpc/winreg/create_key_request'
43
+ require 'ruby_smb/dcerpc/winreg/create_key_response'
44
+ require 'ruby_smb/dcerpc/winreg/save_key_request'
45
+ require 'ruby_smb/dcerpc/winreg/save_key_response'
40
46
 
41
47
  ROOT_KEY_MAP = {
42
48
  "HKEY_CLASSES_ROOT" => OPEN_HKCR,
@@ -125,7 +131,9 @@ module RubySMB
125
131
  # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
126
132
  def query_value(handle, value_name)
127
133
  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
134
+ query_value_request_packet.lp_type = 0
135
+ query_value_request_packet.lpcb_data = 0
136
+ query_value_request_packet.lpcb_len = 0
129
137
  response = dcerpc_request(query_value_request_packet)
130
138
  begin
131
139
  query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
@@ -137,9 +145,9 @@ module RubySMB
137
145
  "#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
138
146
  end
139
147
 
140
- query_value_request_packet = RubySMB::Dcerpc::Winreg::QueryValueRequest.new(hkey: handle, lp_value_name: value_name)
141
148
  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
149
+ query_value_request_packet.lp_data = []
150
+ query_value_request_packet.lp_data.referent.max_count = query_value_response.lpcb_data.referent
143
151
  response = dcerpc_request(query_value_request_packet)
144
152
  begin
145
153
  query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
@@ -185,6 +193,10 @@ module RubySMB
185
193
  # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
186
194
  def query_info_key(handle)
187
195
  query_info_key_request_packet = RubySMB::Dcerpc::Winreg::QueryInfoKeyRequest.new(hkey: handle)
196
+ query_info_key_request_packet.lp_class = ''
197
+ query_info_key_request_packet.lp_class.referent.actual_count = 0
198
+ query_info_key_request_packet.lp_class.maximum_length = 1024
199
+ query_info_key_request_packet.lp_class.buffer.referent.max_count = 1024 / 2
188
200
  response = dcerpc_request(query_info_key_request_packet)
189
201
  begin
190
202
  query_info_key_response = RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse.read(response)
@@ -209,7 +221,9 @@ module RubySMB
209
221
  def enum_key(handle, index)
210
222
  enum_key_request_packet = RubySMB::Dcerpc::Winreg::EnumKeyRequest.new(hkey: handle, dw_index: index)
211
223
  enum_key_request_packet.lpft_last_write_time = 0
212
- enum_key_request_packet.lp_class.referent.buffer = 0
224
+ enum_key_request_packet.lp_class = ''
225
+ enum_key_request_packet.lp_class.referent.buffer = :null
226
+ enum_key_request_packet.lp_name.buffer = ''
213
227
  enum_key_request_packet.lp_name.buffer.referent.max_count = 256
214
228
  response = dcerpc_request(enum_key_request_packet)
215
229
  begin
@@ -234,7 +248,7 @@ module RubySMB
234
248
  # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
235
249
  def enum_value(handle, index)
236
250
  enum_value_request_packet = RubySMB::Dcerpc::Winreg::EnumValueRequest.new(hkey: handle, dw_index: index)
237
- enum_value_request_packet.lp_data.referent_identifier = 0
251
+ enum_value_request_packet.lp_value_name.buffer = ''
238
252
  enum_value_request_packet.lp_value_name.buffer.referent.max_count = 256
239
253
  response = dcerpc_request(enum_value_request_packet)
240
254
  begin
@@ -250,13 +264,72 @@ module RubySMB
250
264
  enum_value_response.lp_value_name.to_s
251
265
  end
252
266
 
267
+ # Creates the specified registry key and returns a handle to the newly created key
268
+ #
269
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
270
+ # @param sub_key [String] the name of the key
271
+ # @param opts [Hash] options for the CreateKeyRequest
272
+ # @return [RubySMB::Dcerpc::Winreg::PrpcHkey] the handle to the opened or created key
273
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a CreateKeyResponse packet
274
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
275
+ def create_key(handle, sub_key, opts = {})
276
+ opts = {
277
+ hkey: handle,
278
+ lp_sub_key: sub_key,
279
+ lp_class: opts[:lp_class] || :null,
280
+ dw_options: opts[:dw_options] || RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
281
+ sam_desired: opts[:sam_desired] || RubySMB::Dcerpc::Winreg::Regsam.new(maximum: 1),
282
+ lp_security_attributes: opts[:lp_security_attributes] || RubySMB::Dcerpc::RpcSecurityAttributes.new,
283
+ lpdw_disposition: opts[:lpdw_disposition] || RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY,
284
+ }
285
+ create_key_request_packet = RubySMB::Dcerpc::Winreg::CreateKeyRequest.new(opts)
286
+ response = dcerpc_request(create_key_request_packet)
287
+ begin
288
+ create_key_response = RubySMB::Dcerpc::Winreg::CreateKeyResponse.read(response)
289
+ rescue IOError
290
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the CreateKey response"
291
+ end
292
+ unless create_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
293
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when creating key #{sub_key}: "\
294
+ "#{WindowsError::Win32.find_by_retval(create_key_response.error_status.value).join(',')}"
295
+ end
296
+
297
+ create_key_response.hkey
298
+ end
299
+
300
+ # Saves the specified key, subkeys, and values to a new file
301
+ #
302
+ # @param handle [Ndr::NdrContextHandle] the handle for the key
303
+ # @param file_name [String] the name of the registry file in which the specified key and subkeys are to be saved
304
+ # @param opts [Hash] options for the SaveKeyRequest
305
+ # @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a SaveKeyResponse packet
306
+ # @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
307
+ def save_key(handle, file_name, opts = {})
308
+ opts = {
309
+ hkey: handle,
310
+ lp_file: file_name,
311
+ lp_security_attributes: opts[:lp_security_attributes] || :null,
312
+ }
313
+ save_key_request_packet = RubySMB::Dcerpc::Winreg::SaveKeyRequest.new(opts)
314
+ response = dcerpc_request(save_key_request_packet)
315
+ begin
316
+ save_key_response = RubySMB::Dcerpc::Winreg::SaveKeyResponse.read(response)
317
+ rescue IOError
318
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the SaveKeyResponse response"
319
+ end
320
+ unless save_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
321
+ raise RubySMB::Dcerpc::Error::WinregError, "Error returned when saving key to #{file_name}: "\
322
+ "#{WindowsError::Win32.find_by_retval(save_key_response.error_status.value).join(',')}"
323
+ end
324
+ end
325
+
253
326
  # Checks if the specified registry key exists. It returns true if it
254
327
  # exists, false otherwise.
255
328
  #
256
329
  # @param key [String] the registry key to check
257
330
  # @return [Boolean]
258
- def has_registry_key?(key)
259
- bind(endpoint: RubySMB::Dcerpc::Winreg)
331
+ def has_registry_key?(key, bind: true)
332
+ bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
260
333
 
261
334
  root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
262
335
  begin
@@ -265,8 +338,10 @@ module RubySMB
265
338
  rescue RubySMB::Dcerpc::Error::WinregError
266
339
  return false
267
340
  end
268
- close_key(subkey_handle)
269
341
  return true
342
+ ensure
343
+ close_key(subkey_handle) if subkey_handle
344
+ close_key(root_key_handle) if root_key_handle
270
345
  end
271
346
 
272
347
  # Retrieve the data associated with the named value of a specified
@@ -275,15 +350,17 @@ module RubySMB
275
350
  # @param key [String] the registry key
276
351
  # @param value_name [String] the name of the value to read
277
352
  # @return [String] the data of the value entry
278
- def read_registry_key_value(key, value_name)
279
- bind(endpoint: RubySMB::Dcerpc::Winreg)
353
+ def read_registry_key_value(key, value_name, bind: true)
354
+ bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
280
355
 
281
356
  root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
282
357
  root_key_handle = open_root_key(root_key)
283
358
  subkey_handle = open_key(root_key_handle, sub_key)
284
359
  value = query_value(subkey_handle, value_name)
285
- close_key(subkey_handle)
286
360
  value
361
+ ensure
362
+ close_key(subkey_handle) if subkey_handle
363
+ close_key(root_key_handle) if root_key_handle
287
364
  end
288
365
 
289
366
  # Enumerate the subkeys of a specified registry key. If only a root key
@@ -291,8 +368,8 @@ module RubySMB
291
368
  #
292
369
  # @param key [String] the registry key
293
370
  # @return [Array<String>] the subkeys
294
- def enum_registry_key(key)
295
- bind(endpoint: RubySMB::Dcerpc::Winreg)
371
+ def enum_registry_key(key, bind: true)
372
+ bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
296
373
 
297
374
  root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
298
375
  root_key_handle = open_root_key(root_key)
@@ -307,16 +384,18 @@ module RubySMB
307
384
  key_count.times do |i|
308
385
  enum_result << enum_key(subkey_handle, i)
309
386
  end
310
- close_key(subkey_handle)
311
387
  enum_result
388
+ ensure
389
+ close_key(subkey_handle) if subkey_handle
390
+ close_key(root_key_handle) if root_key_handle && root_key_handle != subkey_handle
312
391
  end
313
392
 
314
393
  # Enumerate the values for the specified registry key.
315
394
  #
316
395
  # @param key [String] the registry key
317
396
  # @return [Array<String>] the values
318
- def enum_registry_values(key)
319
- bind(endpoint: RubySMB::Dcerpc::Winreg)
397
+ def enum_registry_values(key, bind: true)
398
+ bind(endpoint: RubySMB::Dcerpc::Winreg) if bind
320
399
 
321
400
  root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
322
401
  root_key_handle = open_root_key(root_key)
@@ -331,8 +410,10 @@ module RubySMB
331
410
  value_count.times do |i|
332
411
  enum_result << enum_value(subkey_handle, i)
333
412
  end
334
- close_key(subkey_handle)
335
413
  enum_result
414
+ ensure
415
+ close_key(subkey_handle) if subkey_handle
416
+ close_key(root_key_handle) if root_key_handle && root_key_handle != subkey_handle
336
417
  end
337
418
 
338
419
  end
@@ -0,0 +1,73 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Winreg
4
+
5
+ class RpcHkey < Ndr::NdrContextHandle; end
6
+
7
+ # This class represents a BaseRegCreateKey Request Packet as defined in
8
+ # [3.1.5.7 BaseRegCreateKey (Opnum 6)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/c7186ae2-1c82-45e9-933b-97d9873657e8)
9
+ class CreateKeyRequest < BinData::Record
10
+ # Options:
11
+ # bitwise OR of one of the key types (REG_KEY_TYPE_*), and any or none
12
+ # of the other options:
13
+ #
14
+ # This key is not volatile. The key and all its values MUST be
15
+ # persisted to the backing store and is preserved when the registry
16
+ # server loses context due to a computer restart, reboot, or shut down
17
+ # process.
18
+ REG_KEY_TYPE_NON_VOLATILE = 0x00000000
19
+ # This key is volatile. The key with all its subkeys and values MUST
20
+ # NOT be preserved when the registry server loses context due to a
21
+ # computer restart, reboot, or shut down process.
22
+ REG_KEY_TYPE_VOLATILE = 0x00000001
23
+ # This key is a symbolic link to another key.
24
+ REG_KEY_TYPE_SYMLINK = 0x00000002
25
+ # Indicates that the caller wishes to assert its backup and/or restore
26
+ # privileges.
27
+ REG_OPTION_BACKUP_RESTORE = 0x00000004
28
+ # Indicates that the caller wishes to open the targeted symlink source
29
+ # rather than the symlink target.
30
+ REG_OPTION_OPEN_LINK = 0x00000008
31
+ # Indicates that the caller wishes to disable limited user access
32
+ # virtualization for this operation.
33
+ REG_OPTION_DONT_VIRTUALIZE = 0x00000010
34
+
35
+
36
+ # Create disposition:
37
+ # The key did not exist and was created.
38
+ REG_CREATED_NEW_KEY = 0x00000001
39
+ # The key already existed and was opened without being changed.
40
+ REG_OPENED_EXISTING_KEY = 0x00000002
41
+
42
+ attr_reader :opnum
43
+
44
+ endian :little
45
+
46
+ rpc_hkey :hkey
47
+ rrp_unicode_string :lp_sub_key
48
+ string :pad1, length: -> { pad_length(self.lp_sub_key) }
49
+ rrp_unicode_string :lp_class
50
+ string :pad2, length: -> { pad_length(self.lp_class) }
51
+ uint32 :dw_options
52
+ regsam :sam_desired
53
+ prpc_security_attributes :lp_security_attributes
54
+ string :pad3, length: -> { pad_length(self.lp_security_attributes) }
55
+ ndr_lp_dword :lpdw_disposition
56
+
57
+ def initialize_instance
58
+ super
59
+ @opnum = REG_CREATE_KEY
60
+ end
61
+
62
+ # Determines the correct length for the padding, so that the next
63
+ # field is 4-byte aligned.
64
+ def pad_length(prev_element)
65
+ offset = (prev_element.abs_offset + prev_element.to_binary_s.length) % 4
66
+ (4 - offset) % 4
67
+ end
68
+ end
69
+
70
+ end
71
+ end
72
+ end
73
+
@@ -0,0 +1,36 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Winreg
4
+
5
+ class PrpcHkey < Ndr::NdrContextHandle; end
6
+
7
+ # This class represents a BaseRegCreateKey Response Packet as defined in
8
+ # [3.1.5.7 BaseRegCreateKey (Opnum 6)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/c7186ae2-1c82-45e9-933b-97d9873657e8)
9
+ class CreateKeyResponse < BinData::Record
10
+ # Create disposition
11
+ # The key did not exist and was created.
12
+ REG_CREATED_NEW_KEY = 0x00000001
13
+ # The key already existed and was opened without being changed.
14
+ REG_OPENED_EXISTING_KEY = 0x00000002
15
+
16
+ attr_reader :opnum
17
+
18
+ endian :little
19
+
20
+ prpc_hkey :hkey
21
+ ndr_lp_dword :lpdw_disposition
22
+ uint32 :error_status
23
+
24
+ def initialize_instance
25
+ super
26
+ @opnum = REG_CREATE_KEY
27
+ end
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+
34
+
35
+
36
+
@@ -13,7 +13,7 @@ module RubySMB
13
13
 
14
14
  rpc_hkey :hkey
15
15
  uint32 :dw_index
16
- rrp_unicode_string :lp_name
16
+ rrp_unicode_string :lp_name
17
17
  string :pad1, length: -> { pad_length1 }
18
18
  prrp_unicode_string :lp_class
19
19
  string :pad2, length: -> { pad_length2 }
@@ -16,7 +16,7 @@ module RubySMB
16
16
  rrp_unicode_string :lp_value_name
17
17
  string :pad, length: -> { pad_length }
18
18
  ndr_lp_dword :lp_type
19
- ndr_lp_byte :lp_data
19
+ ndr_lp_byte_array :lp_data
20
20
  ndr_lp_dword :lpcb_data
21
21
  ndr_lp_dword :lpcb_len
22
22
 
@@ -12,7 +12,7 @@ module RubySMB
12
12
  rrp_unicode_string :lp_value_name
13
13
  string :pad, length: -> { pad_length }
14
14
  ndr_lp_dword :lp_type
15
- ndr_lp_byte :lp_data
15
+ ndr_lp_byte_array :lp_data
16
16
  ndr_lp_dword :lpcb_data
17
17
  ndr_lp_dword :lpcb_len
18
18
  uint32 :error_status
@@ -4,10 +4,10 @@ module RubySMB
4
4
 
5
5
  # This class represents a PREGISTRY_SERVER_NAME structure as defined in
6
6
  # [2.2.2 PREGISTRY_SERVER_NAME](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/8bcd15fd-1aa5-44e2-8662-112ec3e9817b)
7
- class PRegistryServerName < Ndr::NdrTopLevelFullPointer
7
+ class PRegistryServerName < Ndr::NdrPointer
8
8
  endian :little
9
9
 
10
- string16 :referent, read_length: -> { 4 }
10
+ string16 :referent, onlyif: -> { self.referent_id != 0 }, read_length: -> { 4 }
11
11
  end
12
12
 
13
13
  # This class is a generic class that represents OpenXXX Request packet,
@@ -33,8 +33,8 @@ module RubySMB
33
33
  def initialize_instance
34
34
  super
35
35
  @opnum = get_parameter(:opnum) if has_parameter?(:opnum)
36
- p_registry_server_name.referent = "\0\0"
37
- sam_desired.maximum = 1 unless [OPEN_HKPD, OPEN_HKPT, OPEN_HKPN].include?(@opnum)
36
+ self.p_registry_server_name = :null
37
+ self.sam_desired.maximum = 1 unless [OPEN_HKPD, OPEN_HKPT, OPEN_HKPN].include?(@opnum)
38
38
  end
39
39
  end
40
40
 
@@ -12,7 +12,7 @@ module RubySMB
12
12
  endian :little
13
13
 
14
14
  rpc_hkey :hkey
15
- rrp_unicode_string :lp_class, initial_value: 0
15
+ rrp_unicode_string :lp_class
16
16
 
17
17
  def initialize_instance
18
18
  super