ruby_smb 1.0.3 → 2.0.1

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 (200) 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 -2
  5. data/Gemfile +6 -2
  6. data/README.md +35 -47
  7. data/examples/enum_registry_key.rb +28 -0
  8. data/examples/enum_registry_values.rb +30 -0
  9. data/examples/negotiate.rb +51 -8
  10. data/examples/pipes.rb +2 -1
  11. data/examples/read_file_encryption.rb +56 -0
  12. data/examples/read_registry_key_value.rb +32 -0
  13. data/lib/ruby_smb.rb +4 -1
  14. data/lib/ruby_smb/client.rb +233 -22
  15. data/lib/ruby_smb/client/authentication.rb +70 -33
  16. data/lib/ruby_smb/client/echo.rb +20 -2
  17. data/lib/ruby_smb/client/encryption.rb +62 -0
  18. data/lib/ruby_smb/client/negotiation.rb +172 -24
  19. data/lib/ruby_smb/client/signing.rb +19 -0
  20. data/lib/ruby_smb/client/tree_connect.rb +24 -18
  21. data/lib/ruby_smb/client/utils.rb +8 -7
  22. data/lib/ruby_smb/client/winreg.rb +46 -0
  23. data/lib/ruby_smb/crypto.rb +30 -0
  24. data/lib/ruby_smb/dcerpc.rb +38 -0
  25. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  26. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  27. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  28. data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
  29. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  30. data/lib/ruby_smb/dcerpc/request.rb +28 -9
  31. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
  32. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  33. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  34. data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
  35. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  36. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  37. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  38. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  39. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  40. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  41. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  42. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  43. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  44. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  45. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  46. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  47. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
  48. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  49. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  50. data/lib/ruby_smb/dispatcher/socket.rb +4 -3
  51. data/lib/ruby_smb/error.rb +68 -2
  52. data/lib/ruby_smb/generic_packet.rb +33 -4
  53. data/lib/ruby_smb/smb1/commands.rb +1 -1
  54. data/lib/ruby_smb/smb1/file.rb +66 -15
  55. data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
  56. data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
  57. data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
  58. data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
  59. data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
  60. data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
  61. data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
  62. data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
  63. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
  64. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
  65. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
  66. data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
  67. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
  68. data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
  69. data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
  70. data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
  71. data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
  72. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
  73. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
  74. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +3 -2
  75. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
  76. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +3 -2
  77. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
  78. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
  79. data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
  80. data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
  81. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
  82. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
  83. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
  84. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
  85. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
  86. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
  87. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
  88. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
  89. data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
  90. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
  91. data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
  92. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
  93. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
  94. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
  95. data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
  96. data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
  97. data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
  98. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +3 -6
  99. data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
  100. data/lib/ruby_smb/smb1/pipe.rb +87 -6
  101. data/lib/ruby_smb/smb1/tree.rb +50 -3
  102. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  103. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  104. data/lib/ruby_smb/smb2/file.rb +103 -25
  105. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  106. data/lib/ruby_smb/smb2/packet.rb +2 -0
  107. data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
  108. data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
  109. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  110. data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
  111. data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
  112. data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
  113. data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
  114. data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
  115. data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
  116. data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
  117. data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
  118. data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
  119. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -17
  120. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +52 -5
  121. data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
  122. data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
  123. data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
  124. data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
  125. data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
  126. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
  127. data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
  128. data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
  129. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  130. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +93 -10
  131. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +10 -22
  132. data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
  133. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
  134. data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
  135. data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
  136. data/lib/ruby_smb/smb2/pipe.rb +86 -12
  137. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  138. data/lib/ruby_smb/smb2/tree.rb +65 -21
  139. data/lib/ruby_smb/version.rb +1 -1
  140. data/ruby_smb.gemspec +5 -3
  141. data/spec/lib/ruby_smb/client_spec.rb +1612 -108
  142. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  143. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  144. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  145. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
  146. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  147. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
  148. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  149. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  150. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  151. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  152. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
  153. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  154. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  155. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  156. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  157. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  158. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
  159. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  160. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
  161. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  162. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  163. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
  164. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  165. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
  166. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  167. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +2 -2
  168. data/spec/lib/ruby_smb/error_spec.rb +59 -0
  169. data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
  170. data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
  171. data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
  172. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  173. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  174. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  175. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  176. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
  177. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
  178. data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
  179. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
  180. data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
  181. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  182. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  183. data/spec/lib/ruby_smb/smb2/file_spec.rb +323 -6
  184. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  185. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  186. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +78 -0
  187. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  188. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  189. data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
  190. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  191. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  192. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -22
  193. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +286 -149
  194. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  195. data/spec/lib/ruby_smb/smb2/tree_spec.rb +261 -2
  196. metadata +191 -83
  197. metadata.gz.sig +0 -0
  198. data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
  199. data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
  200. data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
@@ -5,6 +5,10 @@ module RubySMB
5
5
  #https://msdn.microsoft.com/en-us/library/cc247293.aspx
6
6
 
7
7
  class NetShareEnumAll < BinData::Record
8
+ attr_reader :opnum
9
+
10
+ mandatory_parameter :host
11
+
8
12
  endian :little
9
13
 
10
14
  uint32 :referent_id, initial_value: 0x00000001
@@ -27,6 +31,11 @@ module RubySMB
27
31
  uint32 :resume_referent_id, initial_value: 0x00000001
28
32
  uint32 :resume_handle, initial_value: 0
29
33
 
34
+ def initialize_instance
35
+ super
36
+ @opnum = NET_SHARE_ENUM_ALL
37
+ end
38
+
30
39
  def pad_length
31
40
  offset = (server_unc.abs_offset + server_unc.to_binary_s.length) % 4
32
41
  (4 - offset) % 4
@@ -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
@@ -0,0 +1,24 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Winreg
4
+
5
+ class RpcHkey < Ndr::NdrContextHandle; end
6
+
7
+ # This class represents a BaseRegCloseKey Request Packet as defined in
8
+ # [3.1.5.6 BaseRegCloseKey (Opnum 5)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/bc7545ff-0a54-4465-a95a-396b5c2995df)
9
+ class CloseKeyRequest < BinData::Record
10
+ attr_reader :opnum
11
+
12
+ endian :little
13
+
14
+ rpc_hkey :hkey
15
+
16
+ def initialize_instance
17
+ super
18
+ @opnum = REG_CLOSE_KEY
19
+ end
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Winreg
4
+
5
+ class RpcHkey < Ndr::NdrContextHandle; end
6
+
7
+ # This class represents a BaseRegCloseKey Response Packet as defined in
8
+ # [3.1.5.6 BaseRegCloseKey (Opnum 5)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/bc7545ff-0a54-4465-a95a-396b5c2995df)
9
+ class CloseKeyResponse < BinData::Record
10
+ attr_reader :opnum
11
+
12
+ endian :little
13
+
14
+ rpc_hkey :hkey
15
+ uint32 :error_status
16
+
17
+ def initialize_instance
18
+ super
19
+ @opnum = REG_CLOSE_KEY
20
+ end
21
+ end
22
+
23
+ end
24
+ end
25
+ end
26
+
27
+
@@ -0,0 +1,45 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Winreg
4
+
5
+ class RpcHkey < Ndr::NdrContextHandle; end
6
+
7
+ # This class represents a BaseRegEnumKey Request Packet as defined in
8
+ # [3.1.5.10 BaseRegEnumKey (Opnum 9)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rrp/668627e9-e0eb-4ab1-911f-0af589beeac3)
9
+ class EnumKeyRequest < BinData::Record
10
+ attr_reader :opnum
11
+
12
+ endian :little
13
+
14
+ rpc_hkey :hkey
15
+ uint32 :dw_index
16
+ rrp_unicode_string :lp_name
17
+ string :pad1, length: -> { pad_length1 }
18
+ prrp_unicode_string :lp_class
19
+ string :pad2, length: -> { pad_length2 }
20
+ ndr_lp_file_time :lpft_last_write_time
21
+
22
+ def initialize_instance
23
+ super
24
+ @opnum = REG_ENUM_KEY
25
+ end
26
+
27
+ # Determines the correct length for the padding in front of
28
+ # #lp_class. It should always force a 4-byte alignment.
29
+ def pad_length1
30
+ offset = (lp_name.abs_offset + lp_name.to_binary_s.length) % 4
31
+ (4 - offset) % 4
32
+ end
33
+
34
+ # Determines the correct length for the padding in front of
35
+ # #lpft_last_write_time. It should always force a 4-byte alignment.
36
+ def pad_length2
37
+ offset = (lp_class.abs_offset + lp_class.to_binary_s.length) % 4
38
+ (4 - offset) % 4
39
+ end
40
+ end
41
+
42
+ end
43
+ end
44
+ end
45
+