ruby_smb 2.0.12 → 2.0.13

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 (194) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.github/workflows/verify.yml +1 -1
  4. data/examples/dump_secrets_from_sid.rb +207 -0
  5. data/examples/enum_domain_users.rb +75 -0
  6. data/examples/get_computer_info.rb +42 -0
  7. data/examples/query_service_status.rb +42 -4
  8. data/lib/ruby_smb/client.rb +3 -14
  9. data/lib/ruby_smb/dcerpc/bind.rb +28 -20
  10. data/lib/ruby_smb/dcerpc/bind_ack.rb +29 -28
  11. data/lib/ruby_smb/dcerpc/client.rb +542 -0
  12. data/lib/ruby_smb/dcerpc/drsr/drs_bind_request.rb +24 -0
  13. data/lib/ruby_smb/dcerpc/drsr/drs_bind_response.rb +26 -0
  14. data/lib/ruby_smb/dcerpc/drsr/drs_crack_names_request.rb +57 -0
  15. data/lib/ruby_smb/dcerpc/drsr/drs_crack_names_response.rb +76 -0
  16. data/lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_request.rb +46 -0
  17. data/lib/ruby_smb/dcerpc/drsr/drs_domain_controller_info_response.rb +168 -0
  18. data/lib/ruby_smb/dcerpc/drsr/drs_extensions.rb +56 -0
  19. data/lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_request.rb +121 -0
  20. data/lib/ruby_smb/dcerpc/drsr/drs_get_nc_changes_response.rb +118 -0
  21. data/lib/ruby_smb/dcerpc/drsr/drs_unbind_request.rb +24 -0
  22. data/lib/ruby_smb/dcerpc/drsr/drs_unbind_response.rb +26 -0
  23. data/lib/ruby_smb/dcerpc/drsr.rb +909 -0
  24. data/lib/ruby_smb/dcerpc/epm/epm_ept_map_request.rb +26 -0
  25. data/lib/ruby_smb/dcerpc/epm/epm_ept_map_response.rb +25 -0
  26. data/lib/ruby_smb/dcerpc/epm/epm_twrt.rb +211 -0
  27. data/lib/ruby_smb/dcerpc/epm.rb +75 -0
  28. data/lib/ruby_smb/dcerpc/error.rb +17 -0
  29. data/lib/ruby_smb/dcerpc/ndr.rb +1159 -297
  30. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +3 -13
  31. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +3 -3
  32. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +3 -13
  33. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +1 -1
  34. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +3 -11
  35. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +1 -1
  36. data/lib/ruby_smb/dcerpc/netlogon.rb +5 -4
  37. data/lib/ruby_smb/dcerpc/p_syntax_id_t.rb +4 -3
  38. data/lib/ruby_smb/dcerpc/pdu_header.rb +7 -7
  39. data/lib/ruby_smb/dcerpc/ptypes.rb +1 -0
  40. data/lib/ruby_smb/dcerpc/request.rb +79 -32
  41. data/lib/ruby_smb/dcerpc/response.rb +45 -10
  42. data/lib/ruby_smb/dcerpc/rpc_auth3.rb +28 -0
  43. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +11 -11
  44. data/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string.rb +118 -0
  45. data/lib/ruby_smb/dcerpc/samr/rpc_sid.rb +150 -0
  46. data/lib/ruby_smb/dcerpc/samr/samr_close_handle_request.rb +23 -0
  47. data/lib/ruby_smb/dcerpc/samr/samr_close_handle_response.rb +24 -0
  48. data/lib/ruby_smb/dcerpc/samr/samr_connect_request.rb +32 -0
  49. data/lib/ruby_smb/dcerpc/samr/samr_connect_response.rb +23 -0
  50. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request.rb +26 -0
  51. data/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response.rb +55 -0
  52. data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_request.rb +48 -0
  53. data/lib/ruby_smb/dcerpc/samr/samr_get_alias_membership_response.rb +38 -0
  54. data/lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_request.rb +23 -0
  55. data/lib/ruby_smb/dcerpc/samr/samr_get_groups_for_user_response.rb +48 -0
  56. data/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request.rb +24 -0
  57. data/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/samr/samr_open_domain_request.rb +27 -0
  59. data/lib/ruby_smb/dcerpc/samr/samr_open_domain_response.rb +24 -0
  60. data/lib/ruby_smb/dcerpc/samr/samr_open_user_request.rb +26 -0
  61. data/lib/ruby_smb/dcerpc/samr/samr_open_user_response.rb +24 -0
  62. data/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request.rb +23 -0
  63. data/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response.rb +23 -0
  64. data/lib/ruby_smb/dcerpc/samr.rb +613 -0
  65. data/lib/ruby_smb/dcerpc/sec_trailer.rb +26 -0
  66. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +56 -79
  67. data/lib/ruby_smb/dcerpc/srvsvc.rb +27 -4
  68. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +13 -25
  69. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +2 -2
  70. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +1 -1
  71. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +1 -1
  72. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +1 -1
  73. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +4 -14
  74. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +1 -1
  75. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +3 -11
  76. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +1 -1
  77. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +1 -1
  78. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +12 -11
  79. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +1 -1
  80. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +9 -8
  81. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +3 -3
  82. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +1 -1
  83. data/lib/ruby_smb/dcerpc/svcctl.rb +1 -3
  84. data/lib/ruby_smb/dcerpc/uuid.rb +3 -0
  85. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +2 -2
  86. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +2 -13
  87. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +3 -3
  88. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +3 -20
  89. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +3 -20
  90. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +5 -14
  91. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +5 -14
  92. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +1 -9
  93. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +4 -3
  94. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +5 -6
  95. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +2 -2
  96. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +9 -18
  97. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +4 -14
  98. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +7 -15
  99. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +3 -1
  100. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +0 -9
  101. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +1 -1
  102. data/lib/ruby_smb/dcerpc/winreg.rb +10 -14
  103. data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request.rb +26 -0
  104. data/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response.rb +88 -0
  105. data/lib/ruby_smb/dcerpc/wkssvc.rb +65 -0
  106. data/lib/ruby_smb/dcerpc.rb +41 -11
  107. data/lib/ruby_smb/field/file_time.rb +1 -1
  108. data/lib/ruby_smb/field/string16.rb +5 -1
  109. data/lib/ruby_smb/ntlm.rb +18 -2
  110. data/lib/ruby_smb/smb1/pipe.rb +4 -0
  111. data/lib/ruby_smb/smb2/pipe.rb +4 -0
  112. data/lib/ruby_smb/version.rb +1 -1
  113. data/spec/lib/ruby_smb/client_spec.rb +1 -2
  114. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +69 -41
  115. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +75 -21
  116. data/spec/lib/ruby_smb/dcerpc/client_spec.rb +714 -0
  117. data/spec/lib/ruby_smb/dcerpc/drsr_spec.rb +2169 -0
  118. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +3792 -1373
  119. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +4 -4
  120. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +4 -4
  121. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +2 -2
  122. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +2 -2
  123. data/spec/lib/ruby_smb/dcerpc/p_syntax_id_t_spec.rb +18 -4
  124. data/spec/lib/ruby_smb/dcerpc/pdu_header_spec.rb +27 -1
  125. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +76 -11
  126. data/spec/lib/ruby_smb/dcerpc/response_spec.rb +99 -9
  127. data/spec/lib/ruby_smb/dcerpc/rpc_auth3_spec.rb +75 -0
  128. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +29 -28
  129. data/spec/lib/ruby_smb/dcerpc/rrp_rpc_unicode_string_spec.rb +340 -0
  130. data/spec/lib/ruby_smb/dcerpc/samr/rpc_sid_spec.rb +116 -0
  131. data/spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_request_spec.rb +40 -0
  132. data/spec/lib/ruby_smb/dcerpc/samr/samr_close_handle_response_spec.rb +48 -0
  133. data/spec/lib/ruby_smb/dcerpc/samr/samr_connect_request_spec.rb +56 -0
  134. data/spec/lib/ruby_smb/dcerpc/samr/samr_connect_response_spec.rb +47 -0
  135. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_request_spec.rb +63 -0
  136. data/spec/lib/ruby_smb/dcerpc/samr/samr_enumerate_users_in_domain_response_spec.rb +265 -0
  137. data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_request_spec.rb +52 -0
  138. data/spec/lib/ruby_smb/dcerpc/samr/samr_lookup_domain_in_sam_server_response_spec.rb +36 -0
  139. data/spec/lib/ruby_smb/dcerpc/samr/samr_open_domain_request_spec.rb +56 -0
  140. data/spec/lib/ruby_smb/dcerpc/samr/samr_open_domain_response_spec.rb +48 -0
  141. data/spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_request_spec.rb +48 -0
  142. data/spec/lib/ruby_smb/dcerpc/samr/samr_rid_to_sid_response_spec.rb +42 -0
  143. data/spec/lib/ruby_smb/dcerpc/samr_spec.rb +420 -0
  144. data/spec/lib/ruby_smb/dcerpc/sec_trailer_spec.rb +92 -0
  145. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +149 -110
  146. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +21 -17
  147. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +56 -79
  148. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +4 -4
  149. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +2 -2
  150. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +2 -2
  151. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +2 -2
  152. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +19 -29
  153. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +2 -2
  154. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +9 -15
  155. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +2 -2
  156. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +2 -2
  157. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +22 -22
  158. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +2 -2
  159. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +18 -14
  160. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +5 -4
  161. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +2 -2
  162. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +1 -5
  163. data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +15 -23
  164. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +2 -2
  165. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +4 -41
  166. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +4 -4
  167. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +4 -52
  168. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +4 -56
  169. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +10 -34
  170. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +10 -34
  171. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +2 -26
  172. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +2 -2
  173. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +17 -25
  174. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +2 -2
  175. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +20 -44
  176. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +8 -32
  177. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +10 -22
  178. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +4 -0
  179. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +0 -12
  180. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +2 -2
  181. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +18 -47
  182. data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_request_spec.rb +43 -0
  183. data/spec/lib/ruby_smb/dcerpc/wkssvc/netr_wksta_get_info_response_spec.rb +410 -0
  184. data/spec/lib/ruby_smb/dcerpc/wkssvc_spec.rb +70 -0
  185. data/spec/lib/ruby_smb/field/string16_spec.rb +22 -0
  186. data/spec/lib/ruby_smb/gss/provider/ntlm/os_version_spec.rb +1 -1
  187. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +18 -37
  188. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +18 -16
  189. data/spec/support/bin_helper.rb +9 -0
  190. data.tar.gz.sig +0 -0
  191. metadata +96 -5
  192. metadata.gz.sig +0 -0
  193. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +0 -38
  194. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +0 -135
@@ -0,0 +1,542 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+
4
+ # Represents DCERPC SMB client capable of talking to an RPC endpoint in stand-alone.
5
+ class Client
6
+ require 'bindata'
7
+ require 'windows_error'
8
+ require 'net/ntlm'
9
+ require 'ruby_smb/dcerpc'
10
+ require 'ruby_smb/gss'
11
+
12
+ include Epm
13
+
14
+ # The default maximum size of a RPC message that the Client accepts (in bytes)
15
+ MAX_BUFFER_SIZE = 64512
16
+ # The read timeout when receiving packets.
17
+ READ_TIMEOUT = 30
18
+ # The default Endpoint Mapper port
19
+ ENDPOINT_MAPPER_PORT = 135
20
+
21
+ # The domain you're trying to authenticate to
22
+ # @!attribute [rw] domain
23
+ # @return [String]
24
+ attr_accessor :domain
25
+
26
+ # The local workstation to pretend to be
27
+ # @!attribute [rw] local_workstation
28
+ # @return [String]
29
+ attr_accessor :local_workstation
30
+
31
+ # The NTLM client used for authentication
32
+ # @!attribute [rw] ntlm_client
33
+ # @return [String]
34
+ attr_accessor :ntlm_client
35
+
36
+ # The username to authenticate with
37
+ # @!attribute [rw] username
38
+ # @return [String]
39
+ attr_accessor :username
40
+
41
+ # The password to authenticate with
42
+ # @!attribute [rw] password
43
+ # @return [String]
44
+ attr_accessor :password
45
+
46
+ # The Netbios Name of the Peer/Server.
47
+ # @!attribute [rw] default_name
48
+ # @return [String]
49
+ attr_accessor :default_name
50
+
51
+ # The Netbios Domain of the Peer/Server.
52
+ # @!attribute [rw] default_domain
53
+ # @return [String]
54
+ attr_accessor :default_domain
55
+
56
+ # The Fully Qualified Domain Name (FQDN) of the computer.
57
+ # @!attribute [rw] dns_host_name
58
+ # @return [String]
59
+ attr_accessor :dns_host_name
60
+
61
+ # The Fully Qualified Domain Name (FQDN) of the domain.
62
+ # @!attribute [rw] dns_domain_name
63
+ # @return [String]
64
+ attr_accessor :dns_domain_name
65
+
66
+ # The Fully Qualified Domain Name (FQDN) of the forest.
67
+ # @!attribute [rw] dns_tree_name
68
+ # @return [String]
69
+ attr_accessor :dns_tree_name
70
+
71
+ # The OS version number (<major>.<minor>.<build>) of the Peer/Server.
72
+ # @!attribute [rw] os_version
73
+ # @return [String]
74
+ attr_accessor :os_version
75
+
76
+ # The maximum size SMB message that the Client accepts (in bytes)
77
+ # The default value is equal to {MAX_BUFFER_SIZE}.
78
+ # @!attribute [rw] max_buffer_size
79
+ # @return [Integer]
80
+ attr_accessor :max_buffer_size
81
+
82
+ # The TCP socket to connect to the remote host
83
+ # @!attribute [rw] tcp_socket
84
+ # @return [TcpSocket]
85
+ attr_accessor :tcp_socket
86
+
87
+
88
+ # @param host [String] The remote host
89
+ # @param endpoint [Module] A module endpoint that defines UUID, VER_MAJOR and
90
+ # VER_MINOR constants (e.g. Drsr)
91
+ # @param tcp_socket [TcpSocket] The socket to use. If not provided, a new
92
+ # socket will be created when calling #connect
93
+ # @param read_timeout [Integer] The read timeout value to use
94
+ # @param username [String] The username to authenticate with, if needed
95
+ # @param password [String] The password to authenticate with, if needed.
96
+ # Note that a NTLM hash can be used instead of a password.
97
+ # @param domain [String] The domain to authenticate to, if needed
98
+ # @param local_workstation [String] The workstation name to authenticate to, if needed
99
+ # @param ntlm_flags [Integer] The flags to pass to the Net:NTLM client
100
+ def initialize(host,
101
+ endpoint,
102
+ tcp_socket: nil,
103
+ read_timeout: READ_TIMEOUT,
104
+ username: '',
105
+ password: '',
106
+ domain: '.',
107
+ local_workstation: 'WORKSTATION',
108
+ ntlm_flags: NTLM::DEFAULT_CLIENT_FLAGS)
109
+
110
+ @endpoint = endpoint
111
+ extend @endpoint
112
+
113
+ @host = host
114
+ @tcp_socket = tcp_socket
115
+ @read_timeout = read_timeout
116
+ @domain = domain
117
+ @local_workstation = local_workstation
118
+ @username = username.encode('utf-8')
119
+ @password = password.encode('utf-8')
120
+ @max_buffer_size = MAX_BUFFER_SIZE
121
+ @call_id = 1
122
+ @ctx_id = 0
123
+ @auth_ctx_id_base = rand(0xFFFFFFFF)
124
+
125
+ unless username.empty? && password.empty?
126
+ @ntlm_client = Net::NTLM::Client.new(
127
+ @username,
128
+ @password,
129
+ workstation: @local_workstation,
130
+ domain: @domain,
131
+ flags: ntlm_flags
132
+ )
133
+ end
134
+ end
135
+
136
+ # Connect to the RPC endpoint. If a TCP socket was not provided, it takes
137
+ # care of asking the Enpoint Mapper Interface the port used by the given
138
+ # endpoint provided in #initialize and connect a TCP socket
139
+ #
140
+ # @param port [Integer] An optional port number to connect to. If
141
+ # provided, it will not ask the Enpoint Mapper Interface for a port
142
+ # number.
143
+ # @return [TcpSocket] The connected TCP socket
144
+ def connect(port: nil)
145
+ return if @tcp_socket
146
+ unless port
147
+ @tcp_socket = TCPSocket.new(@host, ENDPOINT_MAPPER_PORT)
148
+ bind(endpoint: Epm)
149
+ begin
150
+ host_port = get_host_port_from_ept_mapper(
151
+ uuid: @endpoint::UUID,
152
+ maj_ver: @endpoint::VER_MAJOR,
153
+ min_ver: @endpoint::VER_MINOR
154
+ )
155
+ rescue RubySMB::Dcerpc::Error::DcerpcError => e
156
+ e.message.prepend(
157
+ "Cannot resolve the remote port number for endpoint #{@endpoint::UUID}. "\
158
+ "Set @tcp_socket parameter to specify the service port number and bypass "\
159
+ "EPM port resolution. Error: "
160
+ )
161
+ raise e
162
+ end
163
+ port = host_port[:port]
164
+ @tcp_socket.close
165
+ @tcp_socket = nil
166
+ end
167
+ @tcp_socket = TCPSocket.new(@host, port)
168
+ end
169
+
170
+ # Close the TCP Socket
171
+ def close
172
+ @tcp_socket.close if @tcp_socket && !@tcp_socket.closed?
173
+ end
174
+
175
+ # Add the authentication verifier to the packet. This includes a sec
176
+ # trailer and the actual authentication data.
177
+ #
178
+ # @param req [BinData::Record] the request to be updated
179
+ # @param auth [String] the authentication data
180
+ # @param auth_type [Integer] the authentication type
181
+ # @param auth_level [Integer] the authentication level
182
+ def add_auth_verifier(req, auth, auth_type, auth_level)
183
+ req.sec_trailer = {
184
+ auth_type: auth_type,
185
+ auth_level: auth_level,
186
+ auth_context_id: @ctx_id + @auth_ctx_id_base
187
+ }
188
+ req.auth_value = auth
189
+ req.pdu_header.auth_length = auth.length
190
+
191
+ nil
192
+ end
193
+
194
+ def process_ntlm_type2(type2_message)
195
+ ntlmssp_offset = type2_message.index('NTLMSSP')
196
+ type2_blob = type2_message.slice(ntlmssp_offset..-1)
197
+ type2_b64_message = [type2_blob].pack('m')
198
+ type3_message = @ntlm_client.init_context(type2_b64_message)
199
+ auth3 = type3_message.serialize
200
+
201
+ @session_key = @ntlm_client.session_key
202
+ challenge_message = @ntlm_client.session.challenge_message
203
+ store_target_info(challenge_message.target_info) if challenge_message.has_flag?(:TARGET_INFO)
204
+ @os_version = extract_os_version(challenge_message.os_version.to_s) unless challenge_message.os_version.empty?
205
+ auth3
206
+ end
207
+
208
+ # Send a rpc_auth3 PDU that ends the authentication handshake.
209
+ #
210
+ # @param response [BindAck] the BindAck response packet
211
+ # @param auth_type [Integer] the authentication type
212
+ # @param auth_level [Integer] the authentication level
213
+ # @raise [ArgumentError] if `:auth_type` is unknown
214
+ # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
215
+ def send_auth3(response, auth_type, auth_level)
216
+ case auth_type
217
+ when RPC_C_AUTHN_NONE
218
+ when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
219
+ auth3 = process_ntlm_type2(response.auth_value)
220
+ when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
221
+ # TODO
222
+ raise NotImplementedError
223
+ else
224
+ raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
225
+ end
226
+
227
+ rpc_auth3 = RpcAuth3.new
228
+ add_auth_verifier(rpc_auth3, auth3, auth_type, auth_level)
229
+ rpc_auth3.pdu_header.call_id = @call_id
230
+
231
+ # The server should not respond
232
+ send_packet(rpc_auth3)
233
+ @call_id += 1
234
+
235
+ nil
236
+ end
237
+
238
+ # Bind to the remote server interface endpoint. It takes care of adding
239
+ # the necessary authentication verifier if `:auth_level` is set to
240
+ # anything different than RPC_C_AUTHN_LEVEL_NONE
241
+ #
242
+ # @param endpoint [Module] the endpoint to bind to. This must be a Dcerpc
243
+ # class with UUID, VER_MAJOR and VER_MINOR constants defined.
244
+ # @param auth_level [Integer] the authentication level
245
+ # @param auth_type [Integer] the authentication type
246
+ # @return [BindAck] the BindAck response packet
247
+ # @raise [Error::InvalidPacket] if an invalid packet is received
248
+ # @raise [Error::BindError] if the response is not a BindAck packet or if the Bind result code is not ACCEPTANCE
249
+ # @raise [ArgumentError] if `:auth_type` is unknown
250
+ # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
251
+ def bind(endpoint: @endpoint, auth_level: RPC_C_AUTHN_LEVEL_NONE, auth_type: nil)
252
+ bind_req = Bind.new(endpoint: endpoint)
253
+ bind_req.pdu_header.call_id = @call_id
254
+ # TODO: evasion: generate random UUIDs for bogus binds
255
+
256
+ if auth_level && auth_level != RPC_C_AUTHN_LEVEL_NONE
257
+ case auth_type
258
+ when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
259
+ raise ArgumentError, "NTLM Client not initialized. Username and password must be provided" unless @ntlm_client
260
+ type1_message = @ntlm_client.init_context
261
+ auth = type1_message.serialize
262
+ when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
263
+ when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL
264
+ # TODO
265
+ raise NotImplementedError
266
+ else
267
+ raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
268
+ end
269
+ add_auth_verifier(bind_req, auth, auth_type, auth_level)
270
+ end
271
+
272
+ send_packet(bind_req)
273
+ bindack_response = recv_struct(BindAck)
274
+ # TODO: see if BindNack response should be handled too
275
+
276
+ res_list = bindack_response.p_result_list
277
+ if res_list.n_results == 0 ||
278
+ res_list.p_results[0].result != BindAck::ACCEPTANCE
279
+ raise Error::BindError,
280
+ "Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
281
+ end
282
+
283
+ @max_buffer_size = bindack_response.max_xmit_frag
284
+ @call_id = bindack_response.pdu_header.call_id
285
+
286
+ if auth_level && auth_level != RPC_C_AUTHN_LEVEL_NONE
287
+ # The number of legs needed to build the security context is defined
288
+ # by the security provider
289
+ # (see [2.2.1.1.7 Security Providers](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-rpce/d4097450-c62f-484b-872f-ddf59a7a0d36))
290
+ case auth_type
291
+ when RPC_C_AUTHN_WINNT
292
+ send_auth3(bindack_response, auth_type, auth_level)
293
+ when RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE
294
+ # TODO
295
+ raise NotImplementedError
296
+ end
297
+ end
298
+
299
+ nil
300
+ end
301
+
302
+ # Extract and store useful information about the peer/server from the
303
+ # NTLM Type 2 (challenge) TargetInfo fields.
304
+ #
305
+ # @param target_info_str [String] the Target Info string
306
+ def store_target_info(target_info_str)
307
+ target_info = Net::NTLM::TargetInfo.new(target_info_str)
308
+ {
309
+ Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME => :@default_name,
310
+ Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME => :@default_domain,
311
+ Net::NTLM::TargetInfo::MSV_AV_DNS_COMPUTER_NAME => :@dns_host_name,
312
+ Net::NTLM::TargetInfo::MSV_AV_DNS_DOMAIN_NAME => :@dns_domain_name,
313
+ Net::NTLM::TargetInfo::MSV_AV_DNS_TREE_NAME => :@dns_tree_name
314
+ }.each do |constant, attribute|
315
+ if target_info.av_pairs[constant]
316
+ value = target_info.av_pairs[constant].dup
317
+ value.force_encoding('UTF-16LE')
318
+ instance_variable_set(attribute, value.encode('UTF-8'))
319
+ end
320
+ end
321
+ end
322
+
323
+ # Extract the peer/server version number from the NTLM Type 2 (challenge)
324
+ # Version field.
325
+ #
326
+ # @param version [String] the version number as a binary string
327
+ # @return [String] the formated version number (<major>.<minor>.<build>)
328
+ def extract_os_version(version)
329
+ #version.unpack('CCS').join('.')
330
+ begin
331
+ os_version = NTLM::OSVersion.read(version)
332
+ rescue IOError
333
+ return ''
334
+ end
335
+ return "#{os_version.major}.#{os_version.minor}.#{os_version.build}"
336
+ end
337
+
338
+ # Add the authentication verifier to a Request packet. This includes a
339
+ # sec trailer and the signature of the packet. This also encrypts the
340
+ # Request stub if privacy is required (`:auth_level` option is
341
+ # RPC_C_AUTHN_LEVEL_PKT_PRIVACY).
342
+ #
343
+ # @param dcerpc_req [Request] the Request packet to be updated
344
+ # @param opts [Hash] the authenticaiton options: `:auth_type` and `:auth_level`
345
+ # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
346
+ # @raise [ArgumentError] if `:auth_type` is unknown
347
+ def set_integrity_privacy(dcerpc_req, auth_level:, auth_type:)
348
+ dcerpc_req.sec_trailer = {
349
+ auth_type: auth_type,
350
+ auth_level: auth_level,
351
+ auth_context_id: @ctx_id + @auth_ctx_id_base
352
+ }
353
+ dcerpc_req.auth_value = ' ' * 16
354
+ dcerpc_req.pdu_header.auth_length = 16
355
+
356
+ data_to_sign = plain_stub = dcerpc_req.stub.to_binary_s + dcerpc_req.auth_pad.to_binary_s
357
+ if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
358
+ data_to_sign = dcerpc_req.to_binary_s[0..-(dcerpc_req.pdu_header.auth_length + 1)]
359
+ end
360
+
361
+ encrypted_stub = ''
362
+ if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
363
+ case auth_type
364
+ when RPC_C_AUTHN_NONE
365
+ when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
366
+ encrypted_stub = @ntlm_client.session.seal_message(plain_stub)
367
+ when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
368
+ # TODO
369
+ raise NotImplementedError
370
+ else
371
+ raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
372
+ end
373
+ end
374
+
375
+ signature = @ntlm_client.session.sign_message(data_to_sign)
376
+
377
+ unless encrypted_stub.empty?
378
+ pad_length = dcerpc_req.sec_trailer.auth_pad_length.to_i
379
+ dcerpc_req.enable_encrypted_stub
380
+ dcerpc_req.stub = encrypted_stub[0..-(pad_length + 1)]
381
+ dcerpc_req.auth_pad = encrypted_stub[-(pad_length)..-1]
382
+ end
383
+ dcerpc_req.auth_value = signature
384
+ dcerpc_req.pdu_header.auth_length = signature.size
385
+ end
386
+
387
+ # Send a DCERPC request with the provided stub packet.
388
+ #
389
+ # @param stub_packet [BinData::Record] the stub packet to be sent as
390
+ # part of a Request packet
391
+ # @param opts [Hash] the authenticaiton options: `:auth_type` and `:auth_level`
392
+ # @raise [Error::CommunicationError] if socket-related error occurs
393
+ def dcerpc_request(stub_packet, auth_level: nil, auth_type: nil)
394
+ stub_class = stub_packet.class.name.split('::')
395
+ #opts.merge!(endpoint: stub_class[-2])
396
+ values = {
397
+ opnum: stub_packet.opnum,
398
+ p_cont_id: @ctx_id
399
+ }
400
+ dcerpc_req = Request.new(values, { endpoint: stub_class[-2] })
401
+ dcerpc_req.pdu_header.call_id = @call_id
402
+ dcerpc_req.stub.read(stub_packet.to_binary_s)
403
+ # TODO: handle fragmentation
404
+ # We should fragment PDUs if:
405
+ # 1) Payload exceeds max_xmit_frag (@max_buffer_size) received during BIND response
406
+ # 2) We'e explicitly fragmenting packets with lower values
407
+
408
+ if auth_level &&
409
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
410
+ set_integrity_privacy(dcerpc_req, auth_level: auth_level, auth_type: auth_type)
411
+ end
412
+
413
+ send_packet(dcerpc_req)
414
+
415
+ dcerpc_res = recv_struct(Response)
416
+ unless dcerpc_res.pdu_header.pfc_flags.first_frag == 1
417
+ raise Error::InvalidPacket, "Not the first fragment"
418
+ end
419
+
420
+ if auth_level &&
421
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
422
+ handle_integrity_privacy(dcerpc_res, auth_level: auth_level, auth_type: auth_type)
423
+ end
424
+
425
+ raw_stub = dcerpc_res.stub.to_binary_s
426
+ loop do
427
+ break if dcerpc_res.pdu_header.pfc_flags.last_frag == 1
428
+ dcerpc_res = recv_struct(Response)
429
+
430
+ if auth_level &&
431
+ [RPC_C_AUTHN_LEVEL_PKT_INTEGRITY, RPC_C_AUTHN_LEVEL_PKT_PRIVACY].include?(auth_level)
432
+ handle_integrity_privacy(dcerpc_res, auth_level: auth_level, auth_type: auth_type)
433
+ end
434
+
435
+ raw_stub << dcerpc_res.stub.to_binary_s
436
+ end
437
+
438
+ raw_stub
439
+ end
440
+
441
+ # Send a packet to the remote host
442
+ #
443
+ # @param packet [BinData::Record] the packet to send
444
+ # @raise [Error::CommunicationError] if socket-related error occurs
445
+ def send_packet(packet)
446
+ data = packet.to_binary_s
447
+ bytes_written = 0
448
+ begin
449
+ loop do
450
+ break unless bytes_written < data.size
451
+ retval = @tcp_socket.write(data[bytes_written..-1])
452
+ bytes_written += retval
453
+ end
454
+
455
+ rescue IOError, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
456
+ raise Error::CommunicationError, "An error occurred writing to the Socket: #{e.message}"
457
+ end
458
+ nil
459
+ end
460
+
461
+ # Receive a packet from the remote host and parse it according to `struct`
462
+ #
463
+ # @param struct [Class] the structure class to parse the response with
464
+ # @raise [Error::CommunicationError] if socket-related error occurs
465
+ def recv_struct(struct)
466
+ raise Error::CommunicationError, 'Connection has already been closed' if @tcp_socket.closed?
467
+ if IO.select([@tcp_socket], nil, nil, @read_timeout).nil?
468
+ raise Error::CommunicationError, "Read timeout expired when reading from the Socket (timeout=#{@read_timeout})"
469
+ end
470
+
471
+ begin
472
+ response = struct.read(@tcp_socket)
473
+ rescue IOError
474
+ raise Error::InvalidPacket, "Error reading the #{struct} response"
475
+ end
476
+ unless response.pdu_header.ptype == struct::PTYPE
477
+ raise Error::InvalidPacket, "Not a #{struct} packet"
478
+ end
479
+
480
+ response
481
+ rescue Errno::EINVAL, Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE => e
482
+ raise Error::CommunicationError, "An error occurred reading from the Socket: #{e.message}"
483
+ end
484
+
485
+ # Process the security context received in a response. It decrypts the
486
+ # encrypted stub if `:auth_level` is set to anything different than
487
+ # RPC_C_AUTHN_LEVEL_PKT_PRIVACY. It also checks the packet signature and
488
+ # raises an InvalidPacket error if it fails. Note that the exception is
489
+ # disabled by default and can be enabled with the
490
+ # `:raise_signature_error` option
491
+ #
492
+ # @param dcerpc_response [Response] the Response packet
493
+ # containing the security context to process
494
+ # @param opts [Hash] the authenticaiton options: `:auth_type` and
495
+ # `:auth_level`. To enable errors when signature check fails, set the
496
+ # `:raise_signature_error` option to true
497
+ # @raise [NotImplementedError] if `:auth_type` is not implemented (yet)
498
+ # @raise [Error::CommunicationError] if socket-related error occurs
499
+ def handle_integrity_privacy(dcerpc_response, auth_level:, auth_type:, raise_signature_error: false)
500
+ decrypted_stub = ''
501
+ if auth_level == RPC_C_AUTHN_LEVEL_PKT_PRIVACY
502
+ encrypted_stub = dcerpc_response.stub.to_binary_s + dcerpc_response.auth_pad.to_binary_s
503
+ case auth_type
504
+ when RPC_C_AUTHN_NONE
505
+ when RPC_C_AUTHN_WINNT, RPC_C_AUTHN_DEFAULT
506
+ decrypted_stub = @ntlm_client.session.unseal_message(encrypted_stub)
507
+ when RPC_C_AUTHN_NETLOGON, RPC_C_AUTHN_GSS_NEGOTIATE, RPC_C_AUTHN_GSS_SCHANNEL, RPC_C_AUTHN_GSS_KERBEROS
508
+ # TODO
509
+ raise NotImplementedError
510
+ else
511
+ raise ArgumentError, "Unsupported Auth Type: #{auth_type}"
512
+ end
513
+ end
514
+
515
+ unless decrypted_stub.empty?
516
+ pad_length = dcerpc_response.sec_trailer.auth_pad_length.to_i
517
+ dcerpc_response.stub = decrypted_stub[0..-(pad_length + 1)]
518
+ dcerpc_response.auth_pad = decrypted_stub[-(pad_length)..-1]
519
+ end
520
+
521
+ signature = dcerpc_response.auth_value
522
+ data_to_check = dcerpc_response.stub.to_binary_s
523
+ if @ntlm_client.flags & NTLM::NEGOTIATE_FLAGS[:EXTENDED_SECURITY] != 0
524
+ data_to_check = dcerpc_response.to_binary_s[0..-(dcerpc_response.pdu_header.auth_length + 1)]
525
+ end
526
+ unless @ntlm_client.session.verify_signature(signature, data_to_check)
527
+ if raise_signature_error
528
+ raise Error::InvalidPacket.new(
529
+ "Wrong packet signature received (set `raise_signature_error` to false to ignore)"
530
+ )
531
+ end
532
+ end
533
+
534
+ @call_id += 1
535
+
536
+ nil
537
+ end
538
+
539
+ end
540
+ end
541
+ end
542
+
@@ -0,0 +1,24 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Drsr
4
+
5
+ # [4.1.3 IDL_DRSBind (Opnum 0)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/605b1ea1-9cdc-428f-ab7a-70120e020a3d)
6
+ class DrsBindRequest < BinData::Record
7
+ attr_reader :opnum
8
+
9
+ endian :little
10
+
11
+ uuid_ptr :puuid_client_dsa, initial_value: NTSAPI_CLIENT_GUID
12
+ drs_extensions_ptr :pext_client
13
+
14
+ def initialize_instance
15
+ super
16
+ @opnum = DRS_BIND
17
+ end
18
+ end
19
+
20
+ end
21
+ end
22
+ end
23
+
24
+
@@ -0,0 +1,26 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Drsr
4
+
5
+ # [4.1.3 IDL_DRSBind (Opnum 0)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/605b1ea1-9cdc-428f-ab7a-70120e020a3d)
6
+ class DrsBindResponse < BinData::Record
7
+ attr_reader :opnum
8
+
9
+ endian :little
10
+
11
+ drs_extensions_ptr :ppext_server
12
+ drs_handle :ph_drs
13
+ ndr_uint32 :error_status
14
+
15
+ def initialize_instance
16
+ super
17
+ @opnum = DRS_BIND
18
+ end
19
+ end
20
+
21
+ end
22
+ end
23
+ end
24
+
25
+
26
+
@@ -0,0 +1,57 @@
1
+ module RubySMB
2
+ module Dcerpc
3
+ module Drsr
4
+
5
+ class DrsNameArrayPtr < Ndr::NdrConfArray
6
+ default_parameters type: :ndr_wide_stringz_ptr
7
+ extend Ndr::PointerClassPlugin
8
+ end
9
+
10
+ #[4.1.4.1.2 DRS_MSG_CRACKREQ_V1](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/b47debc0-59ee-40e4-ad0f-4bc9f96043b2)
11
+ class DrsMsgCrackreqV1 < Ndr::NdrStruct
12
+ default_parameter byte_align: 4
13
+ endian :little
14
+
15
+ ndr_uint32 :code_page
16
+ ndr_uint32 :locale_id
17
+ ndr_uint32 :dw_flags
18
+ ndr_uint32 :format_offered
19
+ ndr_uint32 :format_desired
20
+ ndr_uint32 :c_names, initial_value: -> { rp_names.size }
21
+ drs_name_array_ptr :rp_names
22
+ end
23
+
24
+ # [4.1.4.1.1 DRS_MSG_CRACKREQ](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/f2d5166e-09f6-4788-a391-66471b2f7d6d)
25
+ class DrsMsgCrackreq < Ndr::NdrStruct
26
+ default_parameter byte_align: 4
27
+ endian :little
28
+
29
+ ndr_uint32 :switch_type, initial_value: 1
30
+ choice :msg_crack, selection: :switch_type, byte_align: 4 do
31
+ drs_msg_crackreq_v1 1
32
+ end
33
+ end
34
+
35
+ # [4.1.4 IDL_DRSCrackNames (Opnum 12)](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-drsr/9b4bfb44-6656-4404-bcc8-dc88111658b3)
36
+ class DrsCrackNamesRequest < BinData::Record
37
+ attr_reader :opnum
38
+
39
+ endian :little
40
+
41
+ drs_handle :h_drs
42
+ ndr_uint32 :dw_in_version, initial_value: 1
43
+ drs_msg_crackreq :pmsg_in
44
+
45
+ def initialize_instance
46
+ super
47
+ @opnum = DRS_CRACK_NAMES
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
54
+
55
+
56
+
57
+