ruby_smb 2.0.12 → 2.0.13

Sign up to get free protection for your applications and to get access to all the features.
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,2169 @@
1
+ require 'ruby_smb/dcerpc/client'
2
+
3
+ RSpec.describe RubySMB::Dcerpc::Drsr do
4
+ def random_str(nb = 8)
5
+ nb.times.map { rand('a'.ord..'z'.ord).chr }.join
6
+ end
7
+
8
+ let(:drsr) do
9
+ RubySMB::Dcerpc::Client.new('1.2.3.4', RubySMB::Dcerpc::Drsr)
10
+ end
11
+
12
+ describe described_class::DrsHandle do
13
+ subject(:packet) { described_class.new }
14
+
15
+ it 'is a Ndr::NdrContextHandle' do
16
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrContextHandle
17
+ end
18
+ it 'reads itself' do
19
+ value = {
20
+ context_handle_attributes: rand(0xFFFFFFFF),
21
+ context_handle_uuid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003'
22
+ }
23
+ new_struct = described_class.new
24
+ new_struct.set(value)
25
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
26
+ end
27
+ end
28
+
29
+ describe described_class::DrsConfStringz16 do
30
+ subject(:packet) { described_class.new }
31
+
32
+ it 'is a Ndr::NdrConfArray' do
33
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrConfArray
34
+ end
35
+ it 'has elements of type RubySMB::Dcerpc::Ndr::NdrWideChar' do
36
+ expect(packet[0]).to be_a RubySMB::Dcerpc::Ndr::NdrWideChar
37
+ end
38
+ it 'reads itself' do
39
+ value = 'Test String'.encode('utf-16le').chars
40
+ new_struct = described_class.new(value)
41
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
42
+ end
43
+ end
44
+
45
+ describe described_class::DsName do
46
+ subject(:packet) { described_class.new }
47
+
48
+ it { is_expected.to respond_to :struct_len }
49
+ it { is_expected.to respond_to :sid_len }
50
+ it { is_expected.to respond_to :guid }
51
+ it { is_expected.to respond_to :sid }
52
+ it { is_expected.to respond_to :name_len }
53
+ it { is_expected.to respond_to :string_name }
54
+
55
+ it 'is a Ndr::NdrStruct' do
56
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
57
+ end
58
+ it 'is little endian' do
59
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
60
+ end
61
+ describe '#struct_len' do
62
+ it 'is a NdrUint32 structure' do
63
+ expect(packet.struct_len).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
64
+ end
65
+ it 'defaults to the size of the structure' do
66
+ expect(packet.struct_len).to eq(packet.num_bytes)
67
+ end
68
+ end
69
+ describe '#sid_len' do
70
+ it 'is a NdrUint32 structure' do
71
+ expect(packet.sid_len).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
72
+ end
73
+ end
74
+ describe '#guid' do
75
+ it 'is a Uuid structure' do
76
+ expect(packet.guid).to be_a RubySMB::Dcerpc::Uuid
77
+ end
78
+ end
79
+ describe '#sid' do
80
+ it 'is a String' do
81
+ expect(packet.sid).to be_a BinData::String
82
+ end
83
+ it 'is always 28 bytes long' do
84
+ expect(packet.sid.size).to eq(28)
85
+ packet.sid = 'AAA'
86
+ expect(packet.sid.size).to eq(28)
87
+ end
88
+ end
89
+ describe '#name_len' do
90
+ it 'is a NdrUint32 structure' do
91
+ expect(packet.name_len).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
92
+ end
93
+ it 'is the length of #string_name without the null terminator' do
94
+ packet.string_name = "Test123\x00".encode('utf-16le').chars
95
+ expect(packet.name_len).to eq('Test123'.size)
96
+ end
97
+ end
98
+ describe '#string_name' do
99
+ it 'is a DrsConfStringz16 structure' do
100
+ expect(packet.string_name).to be_a RubySMB::Dcerpc::Drsr::DrsConfStringz16
101
+ end
102
+ end
103
+ it 'reads itself' do
104
+ value = {
105
+ struct_len: 30,
106
+ sid_len: 4,
107
+ guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
108
+ sid: 'A' * 28,
109
+ string_name: 'Test string'.encode('utf-16le').chars
110
+ }
111
+ new_struct = described_class.new(value)
112
+ expect(packet.read(new_struct.to_binary_s)).to eq(value.merge(name_len: value[:string_name].size - 1))
113
+ end
114
+ end
115
+
116
+ describe described_class::DsNamePtr do
117
+ subject(:packet) { described_class.new }
118
+
119
+ it 'is a DsName' do
120
+ expect(described_class).to be < RubySMB::Dcerpc::Drsr::DsName
121
+ end
122
+ it 'is a NdrPointer' do
123
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
124
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
125
+ end
126
+ it 'has a referent which is 4-bytes aligned' do
127
+ expect(packet.eval_parameter(:referent_byte_align)).to eq(4)
128
+ end
129
+ it 'reads itself' do
130
+ value = {
131
+ struct_len: rand(0xFFFFFFFF),
132
+ sid_len: rand(0xFFFFFFFF),
133
+ guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
134
+ sid: 'A' * 28,
135
+ string_name: 'Test string'.encode('utf-16le').chars
136
+ }
137
+ new_struct = described_class.new(value)
138
+ expect(packet.read(new_struct.to_binary_s)).to eq(value.merge(name_len: value[:string_name].size - 1))
139
+ end
140
+ end
141
+
142
+ describe described_class::Usn do
143
+ subject(:packet) { described_class.new }
144
+
145
+ it 'is a BinData::Int64le' do
146
+ expect(described_class).to be < BinData::Int64le
147
+ end
148
+ it 'is 8-bytes aligned' do
149
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
150
+ end
151
+ it 'reads itself' do
152
+ value = rand(0xFFFFFFFF)
153
+ new_struct = described_class.new(value)
154
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
155
+ end
156
+ end
157
+
158
+ describe described_class::UsnVector do
159
+ subject(:packet) { described_class.new }
160
+
161
+ it { is_expected.to respond_to :usn_high_obj_update }
162
+ it { is_expected.to respond_to :usn_reserved }
163
+ it { is_expected.to respond_to :usn_high_prop_update }
164
+
165
+ it 'is a Ndr::NdrStruct' do
166
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
167
+ end
168
+ it 'is 8-bytes aligned' do
169
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
170
+ end
171
+ describe '#usn_high_obj_update' do
172
+ it 'is a Usn structure' do
173
+ expect(packet.usn_high_obj_update).to be_a RubySMB::Dcerpc::Drsr::Usn
174
+ end
175
+ end
176
+ describe '#usn_reserved' do
177
+ it 'is a Usn structure' do
178
+ expect(packet.usn_reserved).to be_a RubySMB::Dcerpc::Drsr::Usn
179
+ end
180
+ end
181
+ describe '#usn_high_prop_update' do
182
+ it 'is a Usn structure' do
183
+ expect(packet.usn_high_prop_update).to be_a RubySMB::Dcerpc::Drsr::Usn
184
+ end
185
+ end
186
+ it 'reads itself' do
187
+ value = {
188
+ usn_high_obj_update: rand(0xFFFFFFFF),
189
+ usn_reserved: rand(0xFFFFFFFF),
190
+ usn_high_prop_update:rand(0xFFFFFFFF)
191
+ }
192
+ new_struct = described_class.new(value)
193
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
194
+ end
195
+ end
196
+
197
+ describe described_class::UptodateCursorV1 do
198
+ subject(:packet) { described_class.new }
199
+
200
+ it { is_expected.to respond_to :uuid_dsa }
201
+ it { is_expected.to respond_to :usn_high_prop_update }
202
+
203
+ it 'is a Ndr::NdrStruct' do
204
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
205
+ end
206
+ it 'is 8-bytes aligned' do
207
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
208
+ end
209
+ describe '#uuid_dsa' do
210
+ it 'is a Uuid structure' do
211
+ expect(packet.uuid_dsa).to be_a RubySMB::Dcerpc::Uuid
212
+ end
213
+ end
214
+ describe '#usn_high_prop_update' do
215
+ it 'is a Usn structure' do
216
+ expect(packet.usn_high_prop_update).to be_a RubySMB::Dcerpc::Drsr::Usn
217
+ end
218
+ end
219
+ it 'reads itself' do
220
+ value = {
221
+ uuid_dsa:'ee1ecfe6-109d-11ec-82a8-0242ac130003',
222
+ usn_high_prop_update: rand(0xFFFFFFFF)
223
+ }
224
+ new_struct = described_class.new(value)
225
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
226
+ end
227
+ end
228
+
229
+ describe described_class::UptodateVectorV1Ext do
230
+ subject(:packet) { described_class.new }
231
+
232
+ it { is_expected.to respond_to :dw_version }
233
+ it { is_expected.to respond_to :dw_reserved1 }
234
+ it { is_expected.to respond_to :c_num_cursors }
235
+ it { is_expected.to respond_to :dw_reserved2 }
236
+ it { is_expected.to respond_to :rg_cursors }
237
+
238
+ it 'is a Ndr::NdrStruct' do
239
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
240
+ end
241
+ it 'is 8-bytes aligned' do
242
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
243
+ end
244
+ describe '#dw_version' do
245
+ it 'is a NdrUint32 structure' do
246
+ expect(packet.dw_version).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
247
+ end
248
+ end
249
+ describe '#dw_reserved1' do
250
+ it 'is a NdrUint32 structure' do
251
+ expect(packet.dw_reserved1).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
252
+ end
253
+ end
254
+ describe '#c_num_cursors' do
255
+ it 'is a NdrUint32 structure' do
256
+ expect(packet.c_num_cursors).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
257
+ end
258
+ end
259
+ describe '#dw_reserved2' do
260
+ it 'is a NdrUint32 structure' do
261
+ expect(packet.dw_reserved2).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
262
+ end
263
+ end
264
+ describe '#rg_cursors' do
265
+ it 'is a NdrConfArray structure' do
266
+ expect(packet.rg_cursors).to be_a RubySMB::Dcerpc::Ndr::NdrConfArray
267
+ end
268
+ it 'has elements of type UptodateCursorV1' do
269
+ expect(packet.rg_cursors[0]).to be_a RubySMB::Dcerpc::Drsr::UptodateCursorV1
270
+ end
271
+ end
272
+ it 'reads itself' do
273
+ value = {
274
+ dw_version: rand(0xFFFFFFFF),
275
+ dw_reserved1: rand(0xFFFFFFFF),
276
+ c_num_cursors: rand(0xFFFFFFFF),
277
+ dw_reserved2: rand(0xFFFFFFFF),
278
+ rg_cursors: [{
279
+ uuid_dsa:'ee1ecfe6-109d-11ec-82a8-0242ac130003',
280
+ usn_high_prop_update: rand(0xFFFFFFFF)
281
+ }]
282
+ }
283
+ new_struct = described_class.new(value)
284
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
285
+ end
286
+ end
287
+
288
+ describe described_class::UptodateVectorV1ExtPtr do
289
+ subject(:packet) { described_class.new }
290
+
291
+ it 'is a UptodateVectorV1Ext' do
292
+ expect(described_class).to be < RubySMB::Dcerpc::Drsr::UptodateVectorV1Ext
293
+ end
294
+ it 'is a NdrPointer' do
295
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
296
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
297
+ end
298
+ it 'has a referent which is 8-bytes aligned' do
299
+ expect(packet.eval_parameter(:referent_byte_align)).to eq(8)
300
+ end
301
+ it 'reads itself' do
302
+ value = {
303
+ dw_version: rand(0xFFFFFFFF),
304
+ dw_reserved1: rand(0xFFFFFFFF),
305
+ c_num_cursors: rand(0xFFFFFFFF),
306
+ dw_reserved2: rand(0xFFFFFFFF),
307
+ rg_cursors: [{
308
+ uuid_dsa:'ee1ecfe6-109d-11ec-82a8-0242ac130003',
309
+ usn_high_prop_update: rand(0xFFFFFFFF)
310
+ }]
311
+ }
312
+ new_struct = described_class.new(value)
313
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
314
+ end
315
+ end
316
+
317
+ describe described_class::AttrtypRequestPlugin do
318
+ let(:test_struct) do
319
+ Class.new(BinData::Record) do
320
+ include RubySMB::Dcerpc::Drsr::AttrtypRequestPlugin
321
+ partial_attr_vector_v1_ext_ptr :p_partial_attr_set
322
+ schema_prefix_table :prefix_table_dest
323
+ end.new
324
+ end
325
+
326
+ describe '#add_attrtyp_from_oid' do
327
+ it 'correctly adds ATTRYP from OID' do
328
+ oid = '1.2.840.113556.1.2.1'
329
+ expected_struct = {
330
+ p_partial_attr_set: {
331
+ dw_version: 1,
332
+ dw_reserved1: 0,
333
+ c_attrs: 1,
334
+ rg_partial_attr: [1]
335
+ },
336
+ prefix_table_dest: {
337
+ prefix_count: 1,
338
+ p_prefix_entry: [{ ndx: 0, prefix: {oid_length: 8, elements: [42, 134, 72, 134, 247, 20, 1, 2]}}]
339
+ }
340
+ }
341
+ test_struct.add_attrtyp_from_oid(oid)
342
+ expect(test_struct).to eq(expected_struct)
343
+ end
344
+ end
345
+ end
346
+
347
+ describe described_class::AttrtypResponsePlugin do
348
+ let(:test_struct) do
349
+ values = {
350
+ prefix_table_src: {
351
+ p_prefix_entry: [
352
+ { ndx: 1, prefix: {elements: [96, 134, 72, 1, 101, 2, 1, 4]}},
353
+ { ndx: 2, prefix: {elements: [42, 134, 72, 134, 247, 20, 1, 2]}}
354
+ ]
355
+ }
356
+ }
357
+ Class.new(BinData::Record) do
358
+ include RubySMB::Dcerpc::Drsr::AttrtypResponsePlugin
359
+ schema_prefix_table :prefix_table_src
360
+ end.new(values)
361
+ end
362
+
363
+ describe '#oid_from_attid' do
364
+ it 'correctly converts ATTRYP to OID' do
365
+ attr_typ = 131073
366
+ oid = '1.2.840.113556.1.2.1'
367
+ expect(test_struct.oid_from_attid(attr_typ)).to eq(oid)
368
+ end
369
+ end
370
+ end
371
+
372
+ describe described_class::Attrtyp do
373
+ it 'is a Ndr::NdrUint32' do
374
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrUint32
375
+ end
376
+ end
377
+
378
+ describe described_class::PartialAttrVectorV1Ext do
379
+ subject(:packet) { described_class.new }
380
+
381
+ it { is_expected.to respond_to :dw_version }
382
+ it { is_expected.to respond_to :dw_reserved1 }
383
+ it { is_expected.to respond_to :c_attrs }
384
+ it { is_expected.to respond_to :rg_partial_attr }
385
+
386
+ it 'is a Ndr::NdrStruct' do
387
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
388
+ end
389
+ describe '#dw_version' do
390
+ it 'is a NdrUint32 structure' do
391
+ expect(packet.dw_version).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
392
+ end
393
+ it 'defaults to 1' do
394
+ expect(packet.dw_version).to eq(1)
395
+ end
396
+ end
397
+ describe '#dw_reserved1' do
398
+ it 'is a NdrUint32 structure' do
399
+ expect(packet.dw_reserved1).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
400
+ end
401
+ end
402
+ describe '#c_attrs' do
403
+ it 'is a NdrUint32 structure' do
404
+ expect(packet.c_attrs).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
405
+ end
406
+ it 'defaults to #rg_partial_attr max_count value' do
407
+ packet.rg_partial_attr = [1,2,3]
408
+ expect(packet.c_attrs).to eq(3)
409
+ end
410
+ end
411
+ describe '#rg_partial_attr' do
412
+ it 'is a Ndr::NdrConfArray' do
413
+ expect(packet.rg_partial_attr).to be_a RubySMB::Dcerpc::Ndr::NdrConfArray
414
+ end
415
+ it 'has elements of type Attrtyp' do
416
+ expect(packet.rg_partial_attr[0]).to be_a RubySMB::Dcerpc::Drsr::Attrtyp
417
+ end
418
+ end
419
+ it 'reads itself' do
420
+ value = {
421
+ dw_version: rand(0xFFFFFFFF),
422
+ dw_reserved1: rand(0xFFFFFFFF),
423
+ c_attrs: 3,
424
+ rg_partial_attr: [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)]
425
+ }
426
+ new_struct = described_class.new(value)
427
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
428
+ end
429
+ end
430
+
431
+ describe described_class::PartialAttrVectorV1ExtPtr do
432
+ subject(:packet) { described_class.new }
433
+
434
+ it 'is a PartialAttrVectorV1Ext' do
435
+ expect(described_class).to be < RubySMB::Dcerpc::Drsr::PartialAttrVectorV1Ext
436
+ end
437
+ it 'is a NdrPointer' do
438
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
439
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
440
+ end
441
+ it 'has a referent which is 4-bytes aligned' do
442
+ expect(packet.eval_parameter(:referent_byte_align)).to eq(4)
443
+ end
444
+ it 'reads itself' do
445
+ value = {
446
+ dw_version: rand(0xFFFFFFFF),
447
+ dw_reserved1: rand(0xFFFFFFFF),
448
+ c_attrs: 3,
449
+ rg_partial_attr: [rand(0xFFFFFFFF), rand(0xFFFFFFFF), rand(0xFFFFFFFF)]
450
+ }
451
+ new_struct = described_class.new(value)
452
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
453
+ end
454
+ end
455
+
456
+ describe described_class::DrsByteArrayPtr do
457
+ subject(:packet) { described_class.new }
458
+
459
+ it 'is a Ndr::NdrConfArray' do
460
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrConfArray
461
+ end
462
+ it 'is a NdrPointer' do
463
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
464
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
465
+ end
466
+ it 'has elements of type Ndr::NdrUint8' do
467
+ expect(packet[0]).to be_a RubySMB::Dcerpc::Ndr::NdrUint8
468
+ end
469
+ it 'reads itself' do
470
+ value = [rand(0xFF), rand(0xFF), rand(0xFF)]
471
+ new_struct = described_class.new(value)
472
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
473
+ end
474
+ end
475
+
476
+ describe described_class::OidT do
477
+ subject(:packet) { described_class.new }
478
+
479
+ it { is_expected.to respond_to :oid_length }
480
+ it { is_expected.to respond_to :elements }
481
+
482
+ it 'is a Ndr::NdrStruct' do
483
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
484
+ end
485
+ describe '#oid_length' do
486
+ it 'is a NdrUint32 structure' do
487
+ expect(packet.oid_length).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
488
+ end
489
+ it 'defaults to the size of #drs_byte_array_ptr' do
490
+ packet.elements = [1,2,3,4]
491
+ expect(packet.oid_length).to eq(4)
492
+ end
493
+ end
494
+ describe '#elements' do
495
+ it 'is a DrsByteArrayPtr' do
496
+ expect(packet.elements).to be_a RubySMB::Dcerpc::Drsr::DrsByteArrayPtr
497
+ end
498
+ end
499
+ it 'reads itself' do
500
+ value = {
501
+ oid_length: 3,
502
+ elements: [rand(0xFF), rand(0xFF), rand(0xFF)]
503
+ }
504
+ new_struct = described_class.new(value)
505
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
506
+ end
507
+ end
508
+
509
+ describe described_class::PrefixTableEntry do
510
+ subject(:packet) { described_class.new }
511
+
512
+ it { is_expected.to respond_to :ndx }
513
+ it { is_expected.to respond_to :prefix }
514
+
515
+ it 'is a Ndr::NdrStruct' do
516
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
517
+ end
518
+ describe '#ndx' do
519
+ it 'is a NdrUint32 structure' do
520
+ expect(packet.ndx).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
521
+ end
522
+ end
523
+ describe '#prefix' do
524
+ it 'is a OidT' do
525
+ expect(packet.prefix).to be_a RubySMB::Dcerpc::Drsr::OidT
526
+ end
527
+ end
528
+ it 'reads itself' do
529
+ value = {
530
+ ndx: rand(0xFFFFFFFF),
531
+ prefix: {oid_length: 3, elements: [rand(0xFF), rand(0xFF), rand(0xFF)]}
532
+ }
533
+ new_struct = described_class.new(value)
534
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
535
+ end
536
+ end
537
+
538
+ describe described_class::PrefixTableEntryArrayPtr do
539
+ subject(:packet) { described_class.new }
540
+
541
+ it 'is a Ndr::NdrConfArray' do
542
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrConfArray
543
+ end
544
+ it 'is a NdrPointer' do
545
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
546
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
547
+ end
548
+ it 'has elements of type PrefixTableEntry' do
549
+ expect(packet[0]).to be_a RubySMB::Dcerpc::Drsr::PrefixTableEntry
550
+ end
551
+ it 'reads itself' do
552
+ value = [{
553
+ ndx: rand(0xFFFFFFFF),
554
+ prefix: {oid_length: 3, elements: [rand(0xFF), rand(0xFF), rand(0xFF)]}
555
+ }]
556
+ new_struct = described_class.new(value)
557
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
558
+ end
559
+ end
560
+
561
+ describe described_class::SchemaPrefixTable do
562
+ subject(:packet) { described_class.new }
563
+
564
+ it { is_expected.to respond_to :prefix_count }
565
+ it { is_expected.to respond_to :p_prefix_entry }
566
+
567
+ it 'is a Ndr::NdrStruct' do
568
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
569
+ end
570
+ it 'is 4-bytes aligned' do
571
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
572
+ end
573
+ describe '#prefix_count' do
574
+ it 'is a NdrUint32 structure' do
575
+ expect(packet.prefix_count).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
576
+ end
577
+ it 'defaults to the size #p_prefix_entry max_count' do
578
+ packet.p_prefix_entry.max_count = 3
579
+ expect(packet.prefix_count).to eq(3)
580
+ end
581
+ end
582
+ describe '#p_prefix_entry' do
583
+ it 'is a PrefixTableEntryArrayPtr' do
584
+ expect(packet.p_prefix_entry).to be_a RubySMB::Dcerpc::Drsr::PrefixTableEntryArrayPtr
585
+ end
586
+ end
587
+ it 'reads itself' do
588
+ value = {
589
+ prefix_count: 5,
590
+ p_prefix_entry: [{
591
+ ndx: rand(0xFFFFFFFF),
592
+ prefix: {oid_length: 3, elements: [rand(0xFF), rand(0xFF), rand(0xFF)]}
593
+ }]
594
+ }
595
+ new_struct = described_class.new(value)
596
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
597
+ end
598
+ end
599
+
600
+ describe described_class::DrsConfStringz do
601
+ subject(:packet) { described_class.new }
602
+
603
+ it 'is a Ndr::NdrConfArray' do
604
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrConfArray
605
+ end
606
+ it 'has elements of type RubySMB::Dcerpc::Ndr::NdrChar' do
607
+ expect(packet[0]).to be_a RubySMB::Dcerpc::Ndr::NdrChar
608
+ end
609
+ it 'reads itself' do
610
+ value = 'Test String'.chars
611
+ new_struct = described_class.new(value)
612
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
613
+ end
614
+ end
615
+
616
+ describe described_class::MtxAddr do
617
+ subject(:packet) { described_class.new }
618
+
619
+ it { is_expected.to respond_to :mtx_name_len }
620
+ it { is_expected.to respond_to :mtx_name }
621
+
622
+ it 'is a Ndr::NdrStruct' do
623
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
624
+ end
625
+ it 'is 4-bytes aligned' do
626
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
627
+ end
628
+ describe '#mtx_name_len' do
629
+ it 'is a NdrUint32 structure' do
630
+ expect(packet.mtx_name_len).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
631
+ end
632
+ it 'defaults to the length of #mtx_name including the terminating null character' do
633
+ packet.mtx_name = ['A', 'B', 'C', "\x00"]
634
+ expect(packet.mtx_name_len).to eq(4)
635
+ end
636
+ end
637
+ describe '#mtx_name' do
638
+ it 'is a DrsConfStringz' do
639
+ expect(packet.mtx_name).to be_a RubySMB::Dcerpc::Drsr::DrsConfStringz
640
+ end
641
+ end
642
+ it 'reads itself' do
643
+ value = {
644
+ mtx_name_len: 4,
645
+ mtx_name: ['A', 'B', 'C', "\x00"]
646
+ }
647
+ new_struct = described_class.new(value)
648
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
649
+ end
650
+ end
651
+
652
+ describe described_class::MtxAddrPtr do
653
+ subject(:packet) { described_class.new }
654
+
655
+ it 'is a MtxAddr' do
656
+ expect(described_class).to be < RubySMB::Dcerpc::Drsr::MtxAddr
657
+ end
658
+ it 'is a NdrPointer' do
659
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
660
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
661
+ end
662
+ it 'has a referent which is 4-bytes aligned' do
663
+ expect(packet.eval_parameter(:referent_byte_align)).to eq(4)
664
+ end
665
+ it 'reads itself' do
666
+ value = {
667
+ mtx_name_len: 4,
668
+ mtx_name: ['A', 'B', 'C', "\x00"]
669
+ }
670
+ new_struct = described_class.new(value)
671
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
672
+ end
673
+ end
674
+
675
+ describe described_class::VarSizeBufferWithVersion do
676
+ subject(:packet) { described_class.new }
677
+
678
+ it { is_expected.to respond_to :ul_version }
679
+ it { is_expected.to respond_to :cb_byte_buffer }
680
+ it { is_expected.to respond_to :ul_padding }
681
+ it { is_expected.to respond_to :rg_buffer }
682
+
683
+ it 'is a Ndr::NdrStruct' do
684
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
685
+ end
686
+ it 'is 8-bytes aligned' do
687
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
688
+ end
689
+ describe '#ul_version' do
690
+ it 'is a NdrUint32 structure' do
691
+ expect(packet.ul_version).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
692
+ end
693
+ end
694
+ describe '#cb_byte_buffer' do
695
+ it 'is a NdrUint32 structure' do
696
+ expect(packet.cb_byte_buffer).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
697
+ end
698
+ it 'defaults to the length of #rg_buffer' do
699
+ packet.rg_buffer = [rand(0xFF)] * 4
700
+ expect(packet.cb_byte_buffer).to eq(4)
701
+ end
702
+ end
703
+ describe '#ul_padding' do
704
+ it 'is a NdrUint64 structure' do
705
+ expect(packet.ul_padding).to be_a RubySMB::Dcerpc::Ndr::NdrUint64
706
+ end
707
+ end
708
+ describe '#rg_buffer' do
709
+ it 'is a NdrConfArray structure' do
710
+ expect(packet.rg_buffer).to be_a RubySMB::Dcerpc::Ndr::NdrConfArray
711
+ end
712
+ it 'has elements of type Ndr::NdrUint8' do
713
+ expect(packet.rg_buffer[0]).to be_a RubySMB::Dcerpc::Ndr::NdrUint8
714
+ end
715
+ end
716
+ it 'reads itself' do
717
+ value = {
718
+ ul_version: rand(0xFFFFFFFF),
719
+ cb_byte_buffer: rand(0xFFFFFFFF),
720
+ ul_padding: rand(0xFFFFFFFFFFFFFFFF),
721
+ rg_buffer: [rand(0xFF)] * 4
722
+ }
723
+ new_struct = described_class.new(value)
724
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
725
+ end
726
+ end
727
+
728
+ describe described_class::VarSizeBufferWithVersionPtr do
729
+ subject(:packet) { described_class.new }
730
+
731
+ it 'is a VarSizeBufferWithVersion' do
732
+ expect(described_class).to be < RubySMB::Dcerpc::Drsr::VarSizeBufferWithVersion
733
+ end
734
+ it 'is a NdrPointer' do
735
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
736
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
737
+ end
738
+ it 'has a referent which is 8-bytes aligned' do
739
+ expect(packet.eval_parameter(:referent_byte_align)).to eq(8)
740
+ end
741
+ it 'reads itself' do
742
+ value = {
743
+ ul_version: rand(0xFFFFFFFF),
744
+ cb_byte_buffer: rand(0xFFFFFFFF),
745
+ ul_padding: rand(0xFFFFFFFFFFFFFFFF),
746
+ rg_buffer: [rand(0xFF)] * 4
747
+ }
748
+ new_struct = described_class.new(value)
749
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
750
+ end
751
+ end
752
+
753
+ describe described_class::Attrval do
754
+ subject(:packet) { described_class.new }
755
+
756
+ it { is_expected.to respond_to :val_len }
757
+ it { is_expected.to respond_to :p_val }
758
+
759
+ it 'is a Ndr::NdrStruct' do
760
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
761
+ end
762
+ it 'is 4-bytes aligned' do
763
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
764
+ end
765
+ describe '#val_len' do
766
+ it 'is a NdrUint32 structure' do
767
+ expect(packet.val_len).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
768
+ end
769
+ it 'defaults to the length of #p_val in bytes' do
770
+ packet.p_val = [rand(0xFF)] * 4
771
+ expect(packet.val_len).to eq(4)
772
+ end
773
+ end
774
+ describe '#p_val' do
775
+ it 'is a DrsByteArrayPtr structure' do
776
+ expect(packet.p_val).to be_a RubySMB::Dcerpc::Drsr::DrsByteArrayPtr
777
+ end
778
+ end
779
+ it 'reads itself' do
780
+ value = {
781
+ val_len: rand(0xFFFFFFFF),
782
+ p_val: [rand(0xFF)] * 4
783
+ }
784
+ new_struct = described_class.new(value)
785
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
786
+ end
787
+ end
788
+
789
+ describe described_class::AttrvalArrayPtr do
790
+ subject(:packet) { described_class.new }
791
+
792
+ it 'is a Ndr::NdrConfArray' do
793
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrConfArray
794
+ end
795
+ it 'is a NdrPointer' do
796
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
797
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
798
+ end
799
+ it 'has elements of type Attrval' do
800
+ expect(packet[0]).to be_a RubySMB::Dcerpc::Drsr::Attrval
801
+ end
802
+ it 'reads itself' do
803
+ value = [{
804
+ val_len: rand(0xFFFFFFFF),
805
+ p_val: [rand(0xFF)] * 4
806
+ }]
807
+ new_struct = described_class.new(value)
808
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
809
+ end
810
+ end
811
+
812
+ describe described_class::Attrvalblock do
813
+ subject(:packet) { described_class.new }
814
+
815
+ it { is_expected.to respond_to :val_count }
816
+ it { is_expected.to respond_to :p_aval }
817
+
818
+ it 'is a Ndr::NdrStruct' do
819
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
820
+ end
821
+ it 'is 4-bytes aligned' do
822
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
823
+ end
824
+ describe '#val_count' do
825
+ it 'is a NdrUint32' do
826
+ expect(packet.val_count).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
827
+ end
828
+ it 'defaults to the size of #p_aval' do
829
+ packet.p_aval = [{p_val: [rand(0xFF)] * 4}] * 6
830
+ expect(packet.val_count).to eq(6)
831
+ end
832
+ end
833
+ describe '#p_aval' do
834
+ it 'is a AttrvalArrayPtr structure' do
835
+ expect(packet.p_aval).to be_a RubySMB::Dcerpc::Drsr::AttrvalArrayPtr
836
+ end
837
+ end
838
+ it 'reads itself' do
839
+ value = {
840
+ val_count: rand(0xFFFFFFFF),
841
+ p_aval: [{val_len: 4, p_val: [rand(0xFF)] * 4}] * 6
842
+ }
843
+ new_struct = described_class.new(value)
844
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
845
+ end
846
+ end
847
+
848
+ describe described_class::Attr do
849
+ subject(:packet) { described_class.new }
850
+
851
+ it { is_expected.to respond_to :attr_typ }
852
+ it { is_expected.to respond_to :attr_val }
853
+
854
+ it 'is a Ndr::NdrStruct' do
855
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
856
+ end
857
+ it 'is 4-bytes aligned' do
858
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
859
+ end
860
+ describe '#attr_typ' do
861
+ it 'is a Attrtyp structure' do
862
+ expect(packet.attr_typ).to be_a RubySMB::Dcerpc::Drsr::Attrtyp
863
+ end
864
+ end
865
+ describe '#attr_val' do
866
+ it 'is a Attrvalblock structure' do
867
+ expect(packet.attr_val).to be_a RubySMB::Dcerpc::Drsr::Attrvalblock
868
+ end
869
+ end
870
+ it 'reads itself' do
871
+ value = {
872
+ attr_typ: rand(0xFFFFFFFF),
873
+ attr_val: {
874
+ val_count: rand(0xFFFFFFFF),
875
+ p_aval: [{val_len: 4, p_val: [rand(0xFF)] * 4}] * 6
876
+ }
877
+ }
878
+ new_struct = described_class.new(value)
879
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
880
+ end
881
+ end
882
+
883
+ describe described_class::AttrArrayPtr do
884
+ subject(:packet) { described_class.new }
885
+
886
+ it 'is a Ndr::NdrConfArray' do
887
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrConfArray
888
+ end
889
+ it 'is a NdrPointer' do
890
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
891
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
892
+ end
893
+ it 'has elements of type Attr' do
894
+ expect(packet[0]).to be_a RubySMB::Dcerpc::Drsr::Attr
895
+ end
896
+ it 'reads itself' do
897
+ value = [{
898
+ attr_typ: rand(0xFFFFFFFF),
899
+ attr_val: {
900
+ val_count: rand(0xFFFFFFFF),
901
+ p_aval: [{val_len: 4, p_val: [rand(0xFF)] * 4}] * 6
902
+ }
903
+ }]
904
+ new_struct = described_class.new(value)
905
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
906
+ end
907
+ end
908
+
909
+ describe described_class::Attrblock do
910
+ subject(:packet) { described_class.new }
911
+
912
+ it { is_expected.to respond_to :attr_count }
913
+ it { is_expected.to respond_to :p_attr }
914
+
915
+ it 'is a Ndr::NdrStruct' do
916
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
917
+ end
918
+ it 'is 4-bytes aligned' do
919
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
920
+ end
921
+ describe '#attr_count' do
922
+ it 'is a NdrUint32' do
923
+ expect(packet.attr_count).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
924
+ end
925
+ it 'defaults to the size of #p_attr' do
926
+ packet.p_attr = [{ attr_typ: rand(0xFFFFFFFF) }] * 6
927
+ expect(packet.attr_count).to eq(6)
928
+ end
929
+ end
930
+ describe '#p_attr' do
931
+ it 'is a AttrArrayPtr structure' do
932
+ expect(packet.p_attr).to be_a RubySMB::Dcerpc::Drsr::AttrArrayPtr
933
+ end
934
+ end
935
+ it 'reads itself' do
936
+ value = {
937
+ attr_count: rand(0xFFFFFFFF),
938
+ p_attr: [{
939
+ attr_typ: rand(0xFFFFFFFF),
940
+ attr_val: {
941
+ val_count: rand(0xFFFFFFFF),
942
+ p_aval: [{val_len: 4, p_val: [rand(0xFF)] * 4}] * 6
943
+ }
944
+ }]
945
+ }
946
+ new_struct = described_class.new(value)
947
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
948
+ end
949
+ end
950
+
951
+ describe described_class::Entinf do
952
+ subject(:packet) { described_class.new }
953
+
954
+ it { is_expected.to respond_to :p_name }
955
+ it { is_expected.to respond_to :ul_flags }
956
+ it { is_expected.to respond_to :attr_block }
957
+
958
+ it 'is a Ndr::NdrStruct' do
959
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
960
+ end
961
+ it 'is 4-bytes aligned' do
962
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
963
+ end
964
+ describe '#p_name' do
965
+ it 'is a DsNamePtr' do
966
+ expect(packet.p_name).to be_a RubySMB::Dcerpc::Drsr::DsNamePtr
967
+ end
968
+ end
969
+ describe '#ul_flags' do
970
+ it 'is a NdrUint32' do
971
+ expect(packet.ul_flags).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
972
+ end
973
+ end
974
+ describe '#attr_block' do
975
+ it 'is a Attrblock structure' do
976
+ expect(packet.attr_block).to be_a RubySMB::Dcerpc::Drsr::Attrblock
977
+ end
978
+ end
979
+ it 'reads itself' do
980
+ value = {
981
+ p_name: {
982
+ struct_len: rand(0xFFFFFFFF),
983
+ sid_len: rand(0xFFFFFFFF),
984
+ guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
985
+ sid: 'A' * 28,
986
+ name_len: 10,
987
+ string_name: 'Test string'.encode('utf-16le').chars
988
+ },
989
+ ul_flags: rand(0xFFFFFFFF),
990
+ attr_block: {
991
+ attr_count: rand(0xFFFFFFFF),
992
+ p_attr: [{
993
+ attr_typ: rand(0xFFFFFFFF),
994
+ attr_val: {
995
+ val_count: rand(0xFFFFFFFF),
996
+ p_aval: [{val_len: 4, p_val: [rand(0xFF)] * 4}] * 6
997
+ }
998
+ }]
999
+ }
1000
+ }
1001
+ new_struct = described_class.new(value)
1002
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1003
+ end
1004
+ end
1005
+
1006
+ describe described_class::Dstime do
1007
+ subject(:packet) { described_class.new }
1008
+
1009
+ it 'is a BinData::Int64le' do
1010
+ expect(described_class).to be < BinData::Int64le
1011
+ end
1012
+ it 'is 8-bytes aligned' do
1013
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1014
+ end
1015
+ it 'reads itself' do
1016
+ value = rand(0xFFFFFFFF)
1017
+ new_struct = described_class.new(value)
1018
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1019
+ end
1020
+ end
1021
+
1022
+ describe described_class::PropertyMetaDataExt do
1023
+ subject(:packet) { described_class.new }
1024
+
1025
+ it { is_expected.to respond_to :dw_version }
1026
+ it { is_expected.to respond_to :time_changed }
1027
+ it { is_expected.to respond_to :uuid_dsa_originating }
1028
+ it { is_expected.to respond_to :usn_originating }
1029
+
1030
+ it 'is a Ndr::NdrStruct' do
1031
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1032
+ end
1033
+ it 'is 8-bytes aligned' do
1034
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1035
+ end
1036
+ describe '#dw_version' do
1037
+ it 'is a NdrUint32' do
1038
+ expect(packet.dw_version).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1039
+ end
1040
+ end
1041
+ describe '#time_changed' do
1042
+ it 'is a Dstime structure' do
1043
+ expect(packet.time_changed).to be_a RubySMB::Dcerpc::Drsr::Dstime
1044
+ end
1045
+ end
1046
+ describe '#uuid_dsa_originating' do
1047
+ it 'is a Uuid structure' do
1048
+ expect(packet.uuid_dsa_originating).to be_a RubySMB::Dcerpc::Uuid
1049
+ end
1050
+ end
1051
+ describe '#usn_originating' do
1052
+ it 'is a Usn structure' do
1053
+ expect(packet.usn_originating).to be_a RubySMB::Dcerpc::Drsr::Usn
1054
+ end
1055
+ end
1056
+ it 'reads itself' do
1057
+ value = {
1058
+ dw_version: rand(0xFFFFFFFF),
1059
+ time_changed: rand(0xFFFFFFFF),
1060
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1061
+ usn_originating: rand(0xFFFFFFFF),
1062
+ }
1063
+ new_struct = described_class.new(value)
1064
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1065
+ end
1066
+ end
1067
+
1068
+ describe described_class::PropertyMetaDataExtVector do
1069
+ subject(:packet) { described_class.new }
1070
+
1071
+ it { is_expected.to respond_to :c_num_props }
1072
+ it { is_expected.to respond_to :rg_meta_data }
1073
+
1074
+ it 'is a Ndr::NdrStruct' do
1075
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1076
+ end
1077
+ it 'is 8-bytes aligned' do
1078
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1079
+ end
1080
+ describe '#c_num_props' do
1081
+ it 'is a NdrUint32' do
1082
+ expect(packet.c_num_props).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1083
+ end
1084
+ it 'defaults to the size of #rg_meta_data' do
1085
+ packet.rg_meta_data = [RubySMB::Dcerpc::Drsr::PropertyMetaDataExt.new] * 4
1086
+ expect(packet.c_num_props).to eq(4)
1087
+ end
1088
+ end
1089
+ describe '#rg_meta_data' do
1090
+ it 'is a NdrConfArray structure' do
1091
+ expect(packet.rg_meta_data).to be_a RubySMB::Dcerpc::Ndr::NdrConfArray
1092
+ end
1093
+ it 'has elements of type PropertyMetaDataExt' do
1094
+ expect(packet.rg_meta_data[0]).to be_a RubySMB::Dcerpc::Drsr::PropertyMetaDataExt
1095
+ end
1096
+ end
1097
+ it 'reads itself' do
1098
+ value = {
1099
+ c_num_props: rand(0xFFFFFFFF),
1100
+ rg_meta_data: [{
1101
+ dw_version: rand(0xFFFFFFFF),
1102
+ time_changed: rand(0xFFFFFFFF),
1103
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1104
+ usn_originating: rand(0xFFFFFFFF),
1105
+ }]
1106
+ }
1107
+ new_struct = described_class.new(value)
1108
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1109
+ end
1110
+ end
1111
+
1112
+ describe described_class::PropertyMetaDataExtVectorPtr do
1113
+ subject(:packet) { described_class.new }
1114
+
1115
+ it 'is a PropertyMetaDataExtVector' do
1116
+ expect(described_class).to be < RubySMB::Dcerpc::Drsr::PropertyMetaDataExtVector
1117
+ end
1118
+ it 'is a NdrPointer' do
1119
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
1120
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
1121
+ end
1122
+ it 'has a referent which is 8-bytes aligned' do
1123
+ expect(packet.eval_parameter(:referent_byte_align)).to eq(8)
1124
+ end
1125
+ it 'reads itself' do
1126
+ value = {
1127
+ c_num_props: rand(0xFFFFFFFF),
1128
+ rg_meta_data: [{
1129
+ dw_version: rand(0xFFFFFFFF),
1130
+ time_changed: rand(0xFFFFFFFF),
1131
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1132
+ usn_originating: rand(0xFFFFFFFF),
1133
+ }]
1134
+ }
1135
+ new_struct = described_class.new(value)
1136
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1137
+ end
1138
+ end
1139
+
1140
+ describe described_class::ReplentinflistPtr do
1141
+ subject(:packet) { described_class.new }
1142
+
1143
+ it { is_expected.to respond_to :p_next_ent_inf }
1144
+ it { is_expected.to respond_to :entinf }
1145
+ it { is_expected.to respond_to :f_is_nc_prefix }
1146
+ it { is_expected.to respond_to :p_parent_guid }
1147
+ it { is_expected.to respond_to :p_meta_data_ext }
1148
+
1149
+ it 'is a Ndr::NdrStruct' do
1150
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1151
+ end
1152
+ it 'is a NdrPointer' do
1153
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
1154
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
1155
+ end
1156
+ it 'is 4-bytes aligned' do
1157
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
1158
+ end
1159
+ it 'has a referent which is 4-bytes aligned' do
1160
+ expect(packet.eval_parameter(:referent_byte_align)).to eq(4)
1161
+ end
1162
+ describe '#p_next_ent_inf' do
1163
+ it 'is a ReplentinflistPtr structure' do
1164
+ expect(packet.p_next_ent_inf).to be_a RubySMB::Dcerpc::Drsr::ReplentinflistPtr
1165
+ end
1166
+ end
1167
+ describe '#entinf' do
1168
+ it 'is a Entinf structure' do
1169
+ expect(packet.entinf).to be_a RubySMB::Dcerpc::Drsr::Entinf
1170
+ end
1171
+ end
1172
+ describe '#f_is_nc_prefix' do
1173
+ it 'is a Ndr::NdrBoolean structure' do
1174
+ expect(packet.f_is_nc_prefix).to be_a RubySMB::Dcerpc::Ndr::NdrBoolean
1175
+ end
1176
+ end
1177
+ describe '#p_parent_guid' do
1178
+ it 'is a UuidPtr structure' do
1179
+ expect(packet.p_parent_guid).to be_a RubySMB::Dcerpc::Ndr::UuidPtr
1180
+ end
1181
+ end
1182
+ describe '#p_meta_data_ext' do
1183
+ it 'is a PropertyMetaDataExtVector structure' do
1184
+ expect(packet.p_meta_data_ext).to be_a RubySMB::Dcerpc::Drsr::PropertyMetaDataExtVector
1185
+ end
1186
+ end
1187
+ it 'reads itself' do
1188
+ value = {
1189
+ p_next_ent_inf: :null,
1190
+ entinf: {
1191
+ p_name: {
1192
+ struct_len: rand(0xFFFFFFFF),
1193
+ sid_len: rand(0xFFFFFFFF),
1194
+ guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1195
+ sid: 'A' * 28,
1196
+ name_len: 10,
1197
+ string_name: 'Test string'.encode('utf-16le').chars
1198
+ },
1199
+ ul_flags: rand(0xFFFFFFFF),
1200
+ attr_block: {
1201
+ attr_count: rand(0xFFFFFFFF),
1202
+ p_attr: [{
1203
+ attr_typ: rand(0xFFFFFFFF),
1204
+ attr_val: {
1205
+ val_count: rand(0xFFFFFFFF),
1206
+ p_aval: [{val_len: 4, p_val: [rand(0xFF)] * 4}] * 6
1207
+ }
1208
+ }]
1209
+ }
1210
+ },
1211
+ f_is_nc_prefix: true,
1212
+ p_parent_guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1213
+ p_meta_data_ext: {
1214
+ c_num_props: rand(0xFFFFFFFF),
1215
+ rg_meta_data: [{
1216
+ dw_version: rand(0xFFFFFFFF),
1217
+ time_changed: rand(0xFFFFFFFF),
1218
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1219
+ usn_originating: rand(0xFFFFFFFF),
1220
+ }]
1221
+ }
1222
+ }
1223
+ new_struct = described_class.new(value)
1224
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1225
+ end
1226
+ end
1227
+
1228
+ describe described_class::DrsCompressedBlob do
1229
+ subject(:packet) { described_class.new }
1230
+
1231
+ it { is_expected.to respond_to :cb_uncompressed_size }
1232
+ it { is_expected.to respond_to :cb_compressed_size }
1233
+ it { is_expected.to respond_to :pb_compressed_data }
1234
+
1235
+ it 'is a Ndr::NdrStruct' do
1236
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1237
+ end
1238
+ it 'is 4-bytes aligned' do
1239
+ expect(packet.eval_parameter(:byte_align)).to eq(4)
1240
+ end
1241
+ describe '#cb_uncompressed_size' do
1242
+ it 'is a Ndr::NdrUint32 structure' do
1243
+ expect(packet.cb_uncompressed_size).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1244
+ end
1245
+ end
1246
+ describe '#cb_compressed_size' do
1247
+ it 'is a Ndr::NdrUint32 structure' do
1248
+ expect(packet.cb_compressed_size).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1249
+ end
1250
+ end
1251
+ describe '#pb_compressed_data' do
1252
+ it 'is a Ndr::NdrConfArray' do
1253
+ expect(packet.pb_compressed_data).to be_a RubySMB::Dcerpc::Ndr::NdrConfArray
1254
+ end
1255
+ it 'has elements of type Ndr::NdrUint8' do
1256
+ expect(packet.pb_compressed_data[0]).to be_a RubySMB::Dcerpc::Ndr::NdrUint8
1257
+ end
1258
+ end
1259
+ it 'reads itself' do
1260
+ value = {
1261
+ cb_uncompressed_size: rand(0xFFFFFFFF),
1262
+ cb_compressed_size: rand(0xFFFFFFFF),
1263
+ pb_compressed_data: [rand(0xFF)] * 4
1264
+ }
1265
+ new_struct = described_class.new(value)
1266
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1267
+ end
1268
+ end
1269
+
1270
+ describe described_class::ValueMetaDataExtV1 do
1271
+ subject(:packet) { described_class.new }
1272
+
1273
+ it { is_expected.to respond_to :time_created }
1274
+ it { is_expected.to respond_to :meta_data }
1275
+
1276
+ it 'is a Ndr::NdrStruct' do
1277
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1278
+ end
1279
+ it 'is 8-bytes aligned' do
1280
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1281
+ end
1282
+ describe '#time_created' do
1283
+ it 'is a Dstime' do
1284
+ expect(packet.time_created).to be_a RubySMB::Dcerpc::Drsr::Dstime
1285
+ end
1286
+ end
1287
+ describe '#meta_data' do
1288
+ it 'is a PropertyMetaDataExt' do
1289
+ expect(packet.meta_data).to be_a RubySMB::Dcerpc::Drsr::PropertyMetaDataExt
1290
+ end
1291
+ end
1292
+ it 'reads itself' do
1293
+ value = {
1294
+ time_created: rand(0xFFFFFFFF),
1295
+ meta_data: {
1296
+ dw_version: rand(0xFFFFFFFF),
1297
+ time_changed: rand(0xFFFFFFFF),
1298
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1299
+ usn_originating: rand(0xFFFFFFFF),
1300
+ }
1301
+ }
1302
+ new_struct = described_class.new(value)
1303
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1304
+ end
1305
+ end
1306
+
1307
+ describe described_class::ReplvalinfV1 do
1308
+ subject(:packet) { described_class.new }
1309
+
1310
+ it { is_expected.to respond_to :p_object }
1311
+ it { is_expected.to respond_to :attr_typ }
1312
+ it { is_expected.to respond_to :aval }
1313
+ it { is_expected.to respond_to :f_is_present }
1314
+ it { is_expected.to respond_to :meta_data }
1315
+
1316
+ it 'is a Ndr::NdrStruct' do
1317
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1318
+ end
1319
+ it 'is 8-bytes aligned' do
1320
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1321
+ end
1322
+ describe '#p_object' do
1323
+ it 'is a DsNamePtr structure' do
1324
+ expect(packet.p_object).to be_a RubySMB::Dcerpc::Drsr::DsNamePtr
1325
+ end
1326
+ end
1327
+ describe '#attr_typ' do
1328
+ it 'is a Attrtyp structure' do
1329
+ expect(packet.attr_typ).to be_a RubySMB::Dcerpc::Drsr::Attrtyp
1330
+ end
1331
+ end
1332
+ describe '#aval' do
1333
+ it 'is a Attrval structure' do
1334
+ expect(packet.aval).to be_a RubySMB::Dcerpc::Drsr::Attrval
1335
+ end
1336
+ end
1337
+ describe '#f_is_present' do
1338
+ it 'is a Ndr::NdrBoolean structure' do
1339
+ expect(packet.f_is_present).to be_a RubySMB::Dcerpc::Ndr::NdrBoolean
1340
+ end
1341
+ end
1342
+ describe '#meta_data' do
1343
+ it 'is a ValueMetaDataExtV1 structure' do
1344
+ expect(packet.meta_data).to be_a RubySMB::Dcerpc::Drsr::ValueMetaDataExtV1
1345
+ end
1346
+ end
1347
+ it 'reads itself' do
1348
+ value = {
1349
+ p_object: {
1350
+ struct_len: rand(0xFFFFFFFF),
1351
+ sid_len: rand(0xFFFFFFFF),
1352
+ guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1353
+ sid: 'A' * 28,
1354
+ name_len: 10,
1355
+ string_name: 'Test string'.encode('utf-16le').chars
1356
+ },
1357
+ attr_typ: rand(0xFFFFFFFF),
1358
+ aval: {
1359
+ val_len: rand(0xFFFFFFFF),
1360
+ p_val: [rand(0xFF)] * 4
1361
+ },
1362
+ f_is_present: true,
1363
+ meta_data: {
1364
+ time_created: rand(0xFFFFFFFF),
1365
+ meta_data: {
1366
+ dw_version: rand(0xFFFFFFFF),
1367
+ time_changed: rand(0xFFFFFFFF),
1368
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1369
+ usn_originating: rand(0xFFFFFFFF),
1370
+ }
1371
+ }
1372
+ }
1373
+ new_struct = described_class.new(value)
1374
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1375
+ end
1376
+ end
1377
+
1378
+ describe described_class::ReplvalinfV1ArrayPtr do
1379
+ subject(:packet) { described_class.new }
1380
+
1381
+ it 'is a Ndr::NdrConfArray' do
1382
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrConfArray
1383
+ end
1384
+ it 'is a NdrPointer' do
1385
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
1386
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
1387
+ end
1388
+ it 'has elements of type ReplvalinfV1' do
1389
+ expect(packet[0]).to be_a RubySMB::Dcerpc::Drsr::ReplvalinfV1
1390
+ end
1391
+ it 'reads itself' do
1392
+ value = [{
1393
+ p_object: {
1394
+ struct_len: rand(0xFFFFFFFF),
1395
+ sid_len: rand(0xFFFFFFFF),
1396
+ guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1397
+ sid: 'A' * 28,
1398
+ name_len: 10,
1399
+ string_name: 'Test string'.encode('utf-16le').chars
1400
+ },
1401
+ attr_typ: rand(0xFFFFFFFF),
1402
+ aval: {
1403
+ val_len: rand(0xFFFFFFFF),
1404
+ p_val: [rand(0xFF)] * 4
1405
+ },
1406
+ f_is_present: true,
1407
+ meta_data: {
1408
+ time_created: rand(0xFFFFFFFF),
1409
+ meta_data: {
1410
+ dw_version: rand(0xFFFFFFFF),
1411
+ time_changed: rand(0xFFFFFFFF),
1412
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1413
+ usn_originating: rand(0xFFFFFFFF),
1414
+ }
1415
+ }
1416
+ }]
1417
+ new_struct = described_class.new(value)
1418
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1419
+ end
1420
+ end
1421
+
1422
+ describe described_class::DrsCompAlgType do
1423
+ it 'is a Ndr::NdrUint32' do
1424
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrUint32
1425
+ end
1426
+ end
1427
+
1428
+ describe described_class::ValueMetaDataExtV3 do
1429
+ subject(:packet) { described_class.new }
1430
+
1431
+ it { is_expected.to respond_to :time_created }
1432
+ it { is_expected.to respond_to :meta_data }
1433
+ it { is_expected.to respond_to :unused1 }
1434
+ it { is_expected.to respond_to :unused2 }
1435
+ it { is_expected.to respond_to :unused3 }
1436
+ it { is_expected.to respond_to :time_expired }
1437
+
1438
+ it 'is a Ndr::NdrStruct' do
1439
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1440
+ end
1441
+ it 'is 8-bytes aligned' do
1442
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1443
+ end
1444
+ describe '#time_created' do
1445
+ it 'is a Dstime'do
1446
+ expect(packet.time_created).to be_a RubySMB::Dcerpc::Drsr::Dstime
1447
+ end
1448
+ end
1449
+ describe '#meta_data' do
1450
+ it 'is a PropertyMetaDataExt structure' do
1451
+ expect(packet.meta_data).to be_a RubySMB::Dcerpc::Drsr::PropertyMetaDataExt
1452
+ end
1453
+ end
1454
+ describe '#unused1' do
1455
+ it 'is a Ndr::NdrUint32 structure' do
1456
+ expect(packet.unused1).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1457
+ end
1458
+ end
1459
+ describe '#unused2' do
1460
+ it 'is a Ndr::NdrUint32 structure' do
1461
+ expect(packet.unused2).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1462
+ end
1463
+ end
1464
+ describe '#unused3' do
1465
+ it 'is a Ndr::NdrUint32 structure' do
1466
+ expect(packet.unused3).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1467
+ end
1468
+ end
1469
+ describe '#time_expired' do
1470
+ it 'is a Dstime'do
1471
+ expect(packet.time_expired).to be_a RubySMB::Dcerpc::Drsr::Dstime
1472
+ end
1473
+ end
1474
+ it 'reads itself' do
1475
+ value = {
1476
+ time_created: rand(0xFFFFFFFF),
1477
+ meta_data: {
1478
+ dw_version: rand(0xFFFFFFFF),
1479
+ time_changed: rand(0xFFFFFFFF),
1480
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1481
+ usn_originating: rand(0xFFFFFFFF),
1482
+ },
1483
+ unused1: rand(0xFFFFFFFF),
1484
+ unused2: rand(0xFFFFFFFF),
1485
+ unused3: rand(0xFFFFFFFF),
1486
+ time_expired: rand(0xFFFFFFFF)
1487
+ }
1488
+ new_struct = described_class.new(value)
1489
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1490
+ end
1491
+ end
1492
+
1493
+ describe described_class::ReplvalinfV3 do
1494
+ subject(:packet) { described_class.new }
1495
+
1496
+ it { is_expected.to respond_to :p_object }
1497
+ it { is_expected.to respond_to :attr_typ }
1498
+ it { is_expected.to respond_to :aval }
1499
+ it { is_expected.to respond_to :f_is_present }
1500
+ it { is_expected.to respond_to :meta_data }
1501
+
1502
+ it 'is a Ndr::NdrStruct' do
1503
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1504
+ end
1505
+ it 'is 8-bytes aligned' do
1506
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1507
+ end
1508
+ describe '#p_object' do
1509
+ it 'is a DsNamePtr structure' do
1510
+ expect(packet.p_object).to be_a RubySMB::Dcerpc::Drsr::DsNamePtr
1511
+ end
1512
+ end
1513
+ describe '#attr_typ' do
1514
+ it 'is a Attrtyp structure' do
1515
+ expect(packet.attr_typ).to be_a RubySMB::Dcerpc::Drsr::Attrtyp
1516
+ end
1517
+ end
1518
+ describe '#aval' do
1519
+ it 'is a Attrval structure' do
1520
+ expect(packet.aval).to be_a RubySMB::Dcerpc::Drsr::Attrval
1521
+ end
1522
+ end
1523
+ describe '#f_is_present' do
1524
+ it 'is a Ndr::NdrBoolean structure' do
1525
+ expect(packet.f_is_present).to be_a RubySMB::Dcerpc::Ndr::NdrBoolean
1526
+ end
1527
+ end
1528
+ describe '#meta_data' do
1529
+ it 'is a ValueMetaDataExtV3 structure' do
1530
+ expect(packet.meta_data).to be_a RubySMB::Dcerpc::Drsr::ValueMetaDataExtV3
1531
+ end
1532
+ end
1533
+ it 'reads itself' do
1534
+ value = {
1535
+ p_object: {
1536
+ struct_len: rand(0xFFFFFFFF),
1537
+ sid_len: rand(0xFFFFFFFF),
1538
+ guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1539
+ sid: 'A' * 28,
1540
+ name_len: 10,
1541
+ string_name: 'Test string'.encode('utf-16le').chars
1542
+ },
1543
+ attr_typ: rand(0xFFFFFFFF),
1544
+ aval: {
1545
+ val_len: rand(0xFFFFFFFF),
1546
+ p_val: [rand(0xFF)] * 4
1547
+ },
1548
+ f_is_present: true,
1549
+ meta_data: {
1550
+ time_created: rand(0xFFFFFFFF),
1551
+ meta_data: {
1552
+ dw_version: rand(0xFFFFFFFF),
1553
+ time_changed: rand(0xFFFFFFFF),
1554
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1555
+ usn_originating: rand(0xFFFFFFFF),
1556
+ },
1557
+ unused1: rand(0xFFFFFFFF),
1558
+ unused2: rand(0xFFFFFFFF),
1559
+ unused3: rand(0xFFFFFFFF),
1560
+ time_expired: rand(0xFFFFFFFF)
1561
+ }
1562
+ }
1563
+ new_struct = described_class.new(value)
1564
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1565
+ end
1566
+ end
1567
+
1568
+ describe described_class::ReplvalinfV3ArrayPtr do
1569
+ subject(:packet) { described_class.new }
1570
+
1571
+ it 'is a Ndr::NdrConfArray' do
1572
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrConfArray
1573
+ end
1574
+ it 'is a NdrPointer' do
1575
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
1576
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
1577
+ end
1578
+ it 'has elements of type ReplvalinfV3' do
1579
+ expect(packet[0]).to be_a RubySMB::Dcerpc::Drsr::ReplvalinfV3
1580
+ end
1581
+ it 'reads itself' do
1582
+ value = [{
1583
+ p_object: {
1584
+ struct_len: rand(0xFFFFFFFF),
1585
+ sid_len: rand(0xFFFFFFFF),
1586
+ guid: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1587
+ sid: 'A' * 28,
1588
+ name_len: 10,
1589
+ string_name: 'Test string'.encode('utf-16le').chars
1590
+ },
1591
+ attr_typ: rand(0xFFFFFFFF),
1592
+ aval: {
1593
+ val_len: rand(0xFFFFFFFF),
1594
+ p_val: [rand(0xFF)] * 4
1595
+ },
1596
+ f_is_present: true,
1597
+ meta_data: {
1598
+ time_created: rand(0xFFFFFFFF),
1599
+ meta_data: {
1600
+ dw_version: rand(0xFFFFFFFF),
1601
+ time_changed: rand(0xFFFFFFFF),
1602
+ uuid_dsa_originating: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1603
+ usn_originating: rand(0xFFFFFFFF),
1604
+ },
1605
+ unused1: rand(0xFFFFFFFF),
1606
+ unused2: rand(0xFFFFFFFF),
1607
+ unused3: rand(0xFFFFFFFF),
1608
+ time_expired: rand(0xFFFFFFFF)
1609
+ }
1610
+ }]
1611
+ new_struct = described_class.new(value)
1612
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1613
+ end
1614
+ end
1615
+
1616
+ describe described_class::UptodateCursorV2 do
1617
+ subject(:packet) { described_class.new }
1618
+
1619
+ it { is_expected.to respond_to :uuid_dsa }
1620
+ it { is_expected.to respond_to :usn_high_prop_update }
1621
+ it { is_expected.to respond_to :time_last_sync_success }
1622
+
1623
+ it 'is a Ndr::NdrStruct' do
1624
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1625
+ end
1626
+ it 'is 8-bytes aligned' do
1627
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1628
+ end
1629
+ describe '#uuid_dsa' do
1630
+ it 'is a Uuid structure' do
1631
+ expect(packet.uuid_dsa).to be_a RubySMB::Dcerpc::Uuid
1632
+ end
1633
+ end
1634
+ describe '#usn_high_prop_update' do
1635
+ it 'is a Usn structure' do
1636
+ expect(packet.usn_high_prop_update).to be_a RubySMB::Dcerpc::Drsr::Usn
1637
+ end
1638
+ end
1639
+ describe '#time_last_sync_success' do
1640
+ it 'is a Dstime structure' do
1641
+ expect(packet.time_last_sync_success).to be_a RubySMB::Dcerpc::Drsr::Dstime
1642
+ end
1643
+ end
1644
+ it 'reads itself' do
1645
+ value = {
1646
+ uuid_dsa: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1647
+ usn_high_prop_update: rand(0xFFFFFFFF),
1648
+ time_last_sync_success: rand(0xFFFFFFFF)
1649
+ }
1650
+ new_struct = described_class.new(value)
1651
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1652
+ end
1653
+ end
1654
+
1655
+ describe described_class::UptodateVectorV2Ext do
1656
+ subject(:packet) { described_class.new }
1657
+
1658
+ it { is_expected.to respond_to :dw_version }
1659
+ it { is_expected.to respond_to :dw_reserved1 }
1660
+ it { is_expected.to respond_to :c_num_cursors }
1661
+ it { is_expected.to respond_to :dw_reserved2 }
1662
+ it { is_expected.to respond_to :rg_cursors }
1663
+
1664
+ it 'is a Ndr::NdrStruct' do
1665
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrStruct
1666
+ end
1667
+ it 'is 8-bytes aligned' do
1668
+ expect(packet.eval_parameter(:byte_align)).to eq(8)
1669
+ end
1670
+ describe '#dw_version' do
1671
+ it 'is a NdrUint32 structure' do
1672
+ expect(packet.dw_version).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1673
+ end
1674
+ end
1675
+ describe '#dw_reserved1' do
1676
+ it 'is a NdrUint32 structure' do
1677
+ expect(packet.dw_reserved1).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1678
+ end
1679
+ end
1680
+ describe '#c_num_cursors' do
1681
+ it 'is a NdrUint32 structure' do
1682
+ expect(packet.c_num_cursors).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1683
+ end
1684
+ end
1685
+ describe '#dw_reserved2' do
1686
+ it 'is a NdrUint32 structure' do
1687
+ expect(packet.dw_reserved2).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
1688
+ end
1689
+ end
1690
+ describe '#rg_cursors' do
1691
+ it 'is a NdrConfArray structure' do
1692
+ expect(packet.rg_cursors).to be_a RubySMB::Dcerpc::Ndr::NdrConfArray
1693
+ end
1694
+ it 'has elements of type UptodateCursorV2' do
1695
+ expect(packet.rg_cursors[0]).to be_a RubySMB::Dcerpc::Drsr::UptodateCursorV2
1696
+ end
1697
+ end
1698
+ it 'reads itself' do
1699
+ value = {
1700
+ dw_version: rand(0xFFFFFFFF),
1701
+ dw_reserved1: rand(0xFFFFFFFF),
1702
+ c_num_cursors: rand(0xFFFFFFFF),
1703
+ dw_reserved2: rand(0xFFFFFFFF),
1704
+ rg_cursors: [{
1705
+ uuid_dsa: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1706
+ usn_high_prop_update: rand(0xFFFFFFFF),
1707
+ time_last_sync_success: rand(0xFFFFFFFF)
1708
+ }]
1709
+ }
1710
+ new_struct = described_class.new(value)
1711
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1712
+ end
1713
+ end
1714
+
1715
+ describe described_class::UptodateVectorV2ExtPtr do
1716
+ subject(:packet) { described_class.new }
1717
+
1718
+ it 'is a UptodateVectorV2Ext' do
1719
+ expect(described_class).to be < RubySMB::Dcerpc::Drsr::UptodateVectorV2Ext
1720
+ end
1721
+ it 'is a NdrPointer' do
1722
+ expect(described_class).to be_a(RubySMB::Dcerpc::Ndr::PointerClassPlugin)
1723
+ expect(packet).to be_a(RubySMB::Dcerpc::Ndr::PointerPlugin)
1724
+ end
1725
+ it 'has a referent which is 8-bytes aligned' do
1726
+ expect(packet.eval_parameter(:referent_byte_align)).to eq(8)
1727
+ end
1728
+ it 'reads itself' do
1729
+ value = {
1730
+ dw_version: rand(0xFFFFFFFF),
1731
+ dw_reserved1: rand(0xFFFFFFFF),
1732
+ c_num_cursors: rand(0xFFFFFFFF),
1733
+ dw_reserved2: rand(0xFFFFFFFF),
1734
+ rg_cursors: [{
1735
+ uuid_dsa: 'ee1ecfe6-109d-11ec-82a8-0242ac130003',
1736
+ usn_high_prop_update: rand(0xFFFFFFFF),
1737
+ time_last_sync_success: rand(0xFFFFFFFF)
1738
+ }]
1739
+ }
1740
+ new_struct = described_class.new(value)
1741
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
1742
+ end
1743
+ end
1744
+
1745
+ describe '#drs_bind' do
1746
+ let(:args) { [:drs_bind] }
1747
+ let(:request_struct) { described_class::DrsBindRequest }
1748
+ let(:response_struct) { described_class::DrsBindResponse }
1749
+ let(:values) do
1750
+ {
1751
+ pext_client: {
1752
+ dw_flags: described_class::DRS_EXT_GETCHGREQ_V6 |
1753
+ described_class::DRS_EXT_GETCHGREPLY_V6 |
1754
+ described_class::DRS_EXT_GETCHGREQ_V8 |
1755
+ described_class::DRS_EXT_STRONG_ENCRYPTION,
1756
+ dw_ext_caps: 0xFFFFFFFF
1757
+ }
1758
+ }
1759
+ end
1760
+ let(:request) { request_struct.new(values) }
1761
+ let(:response) { response_struct.new }
1762
+ before :example do
1763
+ allow(drsr).to receive(:dcerpc_request).and_return(response.to_binary_s)
1764
+ allow(response_struct).to receive(:read).and_return(response)
1765
+ end
1766
+
1767
+ it 'sends the correct request packet with authentication parameters' do
1768
+ drsr.send(*args)
1769
+ expect(drsr).to have_received(:dcerpc_request).with(
1770
+ request,
1771
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
1772
+ auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
1773
+ )
1774
+ end
1775
+ it 'receives the expected response' do
1776
+ drsr.send(*args)
1777
+ expect(response_struct).to have_received(:read).with(response.to_binary_s)
1778
+ end
1779
+ context 'with an invalid response' do
1780
+ it 'raise an InvalidPacket exception' do
1781
+ allow(response_struct).to receive(:read).and_raise(IOError)
1782
+ expect { drsr.send(*args) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
1783
+ end
1784
+ end
1785
+ context 'when the response status is not STATUS_SUCCESS' do
1786
+ it 'raise an DrsrError exception' do
1787
+ response.error_status = WindowsError::NTStatus::STATUS_ACCESS_DENIED.value
1788
+ expect { drsr.send(*args) }.to raise_error(RubySMB::Dcerpc::Error::DrsrError)
1789
+ end
1790
+ end
1791
+ it 'returns the correct handle' do
1792
+ handle = {context_handle_attributes: rand(0xFF), context_handle_uuid: '57800405-0301-3330-5566-040023007000'}
1793
+ response.ph_drs = handle
1794
+ expect(drsr.send(*args)).to eq(handle)
1795
+ end
1796
+ context 'with a different epoch in the response' do
1797
+ before :example do
1798
+ drs_ext = described_class::DrsExtensionsInt.new(dw_repl_epoch: 444)
1799
+ response.ppext_server = drs_ext
1800
+ end
1801
+
1802
+ it 'calls DRSBind again with the correct epoch' do
1803
+
1804
+ drs_ext2 = described_class::DrsExtensionsInt.new(
1805
+ dw_flags: described_class::DRS_EXT_GETCHGREQ_V6 |
1806
+ described_class::DRS_EXT_GETCHGREPLY_V6 |
1807
+ described_class::DRS_EXT_GETCHGREQ_V8 |
1808
+ described_class::DRS_EXT_STRONG_ENCRYPTION,
1809
+ dw_ext_caps: 0xFFFFFFFF,
1810
+ dw_repl_epoch: 444
1811
+ )
1812
+ request2 = request_struct.new(values)
1813
+ request2.pext_client = drs_ext2
1814
+
1815
+ expect(drsr).to receive(:dcerpc_request).with(
1816
+ request,
1817
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
1818
+ auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
1819
+ ).ordered
1820
+ expect(drsr).to receive(:dcerpc_request).once.with(
1821
+ request2,
1822
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
1823
+ auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
1824
+ ).ordered
1825
+
1826
+ drsr.send(*args)
1827
+ end
1828
+ it 'returns the correct handle' do
1829
+ handle = {context_handle_attributes: rand(0xFF), context_handle_uuid: '57800405-0301-3330-5566-040023007000'}
1830
+ second = false
1831
+ allow(described_class::DrsBindResponse).to receive(:read) do
1832
+ response.ph_drs = handle if second
1833
+ second = true
1834
+ response
1835
+ end
1836
+ expect(drsr.send(*args)).to eq(handle)
1837
+ end
1838
+ end
1839
+ end
1840
+
1841
+ describe '#drs_unbind' do
1842
+ let(:ph_drs) { handle = {context_handle_attributes: rand(0xFF), context_handle_uuid: '57800405-0301-3330-5566-040023007000'} }
1843
+ let(:args) { [:drs_unbind, ph_drs] }
1844
+ let(:request_struct) { described_class::DrsUnbindRequest }
1845
+ let(:response_struct) { described_class::DrsUnbindResponse }
1846
+ let(:values) { { ph_drs: ph_drs } }
1847
+ let(:request) { request_struct.new(values) }
1848
+ let(:response) { response_struct.new }
1849
+ before :example do
1850
+ allow(drsr).to receive(:dcerpc_request).and_return(response.to_binary_s)
1851
+ allow(response_struct).to receive(:read).and_return(response)
1852
+ end
1853
+
1854
+ it 'sends the correct request packet with authentication parameters' do
1855
+ drsr.send(*args)
1856
+ expect(drsr).to have_received(:dcerpc_request).with(
1857
+ request,
1858
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
1859
+ auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
1860
+ )
1861
+ end
1862
+ it 'receives the expected response' do
1863
+ drsr.send(*args)
1864
+ expect(response_struct).to have_received(:read).with(response.to_binary_s)
1865
+ end
1866
+ context 'with an invalid response' do
1867
+ it 'raise an InvalidPacket exception' do
1868
+ allow(response_struct).to receive(:read).and_raise(IOError)
1869
+ expect { drsr.send(*args) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
1870
+ end
1871
+ end
1872
+ context 'when the response status is not STATUS_SUCCESS' do
1873
+ it 'raise an DrsrError exception' do
1874
+ response.error_status = WindowsError::NTStatus::STATUS_ACCESS_DENIED.value
1875
+ expect { drsr.send(*args) }.to raise_error(RubySMB::Dcerpc::Error::DrsrError)
1876
+ end
1877
+ end
1878
+ end
1879
+
1880
+ describe '#drs_domain_controller_info' do
1881
+ let(:h_drs) { handle = {context_handle_attributes: rand(0xFF), context_handle_uuid: '57800405-0301-3330-5566-040023007000'} }
1882
+ let(:domain) { 'rubysmb.local' }
1883
+ let(:args) { [:drs_domain_controller_info, h_drs, domain] }
1884
+ let(:request_struct) { described_class::DrsDomainControllerInfoRequest }
1885
+ let(:response_struct) { described_class::DrsDomainControllerInfoResponse }
1886
+ let(:values) do
1887
+ {
1888
+ h_drs: h_drs,
1889
+ pmsg_in: {
1890
+ switch_type: 1,
1891
+ msg_dcinfo: {
1892
+ domain: domain,
1893
+ info_level: 2
1894
+ }
1895
+ }
1896
+ }
1897
+ end
1898
+ let(:request) { request_struct.new(values) }
1899
+ let(:response) { response_struct.new(pmsg_out: {switch_type: 2}) }
1900
+ before :example do
1901
+ allow(drsr).to receive(:dcerpc_request).and_return(response.to_binary_s)
1902
+ allow(response_struct).to receive(:read).and_return(response)
1903
+ end
1904
+
1905
+ it 'sends the correct request packet with authentication parameters' do
1906
+ drsr.send(*args)
1907
+ expect(drsr).to have_received(:dcerpc_request).with(
1908
+ request,
1909
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
1910
+ auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
1911
+ )
1912
+ end
1913
+ it 'receives the expected response' do
1914
+ drsr.send(*args)
1915
+ expect(response_struct).to have_received(:read).with(response.to_binary_s)
1916
+ end
1917
+ context 'with an invalid response' do
1918
+ it 'raise an InvalidPacket exception' do
1919
+ allow(response_struct).to receive(:read).and_raise(IOError)
1920
+ expect { drsr.send(*args) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
1921
+ end
1922
+ end
1923
+ context 'when the response status is not STATUS_SUCCESS' do
1924
+ it 'raise an DrsrError exception' do
1925
+ response.error_status = WindowsError::NTStatus::STATUS_ACCESS_DENIED.value
1926
+ expect { drsr.send(*args) }.to raise_error(RubySMB::Dcerpc::Error::DrsrError)
1927
+ end
1928
+ end
1929
+ it 'returns the correct array of domain controller infos' do
1930
+ info_array = [
1931
+ described_class::DsDomainControllerInfo2w.new(computer_object_name: random_str),
1932
+ described_class::DsDomainControllerInfo2w.new(computer_object_name: random_str),
1933
+ described_class::DsDomainControllerInfo2w.new(computer_object_name: random_str)
1934
+ ]
1935
+ response.pmsg_out.msg_dcinfo.r_items = info_array
1936
+ expect(drsr.send(*args)).to be_a ::Array
1937
+ expect(drsr.send(*args)).to eq(info_array)
1938
+ end
1939
+ end
1940
+
1941
+ describe '#drs_crack_names' do
1942
+ let(:h_drs) { handle = {context_handle_attributes: rand(0xFF), context_handle_uuid: '57800405-0301-3330-5566-040023007000'} }
1943
+ let(:domain) { 'rubysmb.local' }
1944
+ let(:args) { [ :drs_crack_names, h_drs ] }
1945
+ let(:request_struct) { described_class::DrsCrackNamesRequest }
1946
+ let(:response_struct) { described_class::DrsCrackNamesResponse }
1947
+ let(:flags) { 0 }
1948
+ let(:format_offered) { described_class::DS_SID_OR_SID_HISTORY_NAME }
1949
+ let(:format_desired) { described_class::DS_UNIQUE_ID_NAME }
1950
+ let(:rp_names) { [] }
1951
+ let(:values) do
1952
+ {
1953
+ h_drs: h_drs,
1954
+ pmsg_in: {
1955
+ switch_type: 1,
1956
+ msg_crack: {
1957
+ dw_flags: flags,
1958
+ format_offered: format_offered,
1959
+ format_desired: format_desired,
1960
+ rp_names: rp_names
1961
+ }
1962
+ }
1963
+ }
1964
+ end
1965
+ let(:request) { request_struct.new(values) }
1966
+ let(:response) { response_struct.new(pmsg_out: {switch_type: 1}) }
1967
+ before :example do
1968
+ allow(drsr).to receive(:dcerpc_request).and_return(response.to_binary_s)
1969
+ allow(response_struct).to receive(:read).and_return(response)
1970
+ end
1971
+
1972
+ it 'sends the correct request packet with authentication parameters' do
1973
+ drsr.send(*args)
1974
+ expect(drsr).to have_received(:dcerpc_request).with(
1975
+ request,
1976
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
1977
+ auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
1978
+ )
1979
+ end
1980
+ context 'when passing specific values as arguments' do
1981
+ let(:flags) { rand(0xFF) }
1982
+ let(:format_offered) { described_class::DS_USER_PRINCIPAL_NAME }
1983
+ let(:format_desired) { described_class::DS_USER_PRINCIPAL_NAME }
1984
+ let(:rp_names) { ['Test1', 'Test2'] }
1985
+ it 'sends the correct request packet with authentication parameters' do
1986
+ kwargs = {flags: flags, format_offered: format_offered, format_desired: format_desired, rp_names: rp_names}
1987
+ drsr.send(*args, **kwargs)
1988
+ expect(drsr).to have_received(:dcerpc_request).with(
1989
+ request,
1990
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
1991
+ auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
1992
+ )
1993
+ end
1994
+ end
1995
+ it 'receives the expected response' do
1996
+ drsr.send(*args)
1997
+ expect(response_struct).to have_received(:read).with(response.to_binary_s)
1998
+ end
1999
+ context 'with an invalid response' do
2000
+ it 'raise an InvalidPacket exception' do
2001
+ allow(response_struct).to receive(:read).and_raise(IOError)
2002
+ expect { drsr.send(*args) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
2003
+ end
2004
+ end
2005
+ context 'when the response status is not STATUS_SUCCESS' do
2006
+ it 'raise an DrsrError exception' do
2007
+ response.error_status = WindowsError::NTStatus::STATUS_ACCESS_DENIED.value
2008
+ expect { drsr.send(*args) }.to raise_error(RubySMB::Dcerpc::Error::DrsrError)
2009
+ end
2010
+ end
2011
+ it 'returns the correct array of translated names' do
2012
+ name_array = [
2013
+ described_class::DsNameResultItemw.new(p_domain: random_str),
2014
+ described_class::DsNameResultItemw.new(p_domain: random_str),
2015
+ described_class::DsNameResultItemw.new(p_domain: random_str)
2016
+ ]
2017
+ response.pmsg_out.msg_crack.p_result.r_items = name_array
2018
+ expect(drsr.send(*args)).to be_a ::Array
2019
+ expect(drsr.send(*args)).to eq(name_array)
2020
+ end
2021
+ end
2022
+
2023
+ describe described_class::EncryptedPayload do
2024
+ subject(:packet) { described_class.new }
2025
+
2026
+ it 'is a BinData::Record' do
2027
+ expect(described_class).to be < BinData::Record
2028
+ end
2029
+ it 'is little endian' do
2030
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
2031
+ end
2032
+
2033
+ it { is_expected.to respond_to :salt }
2034
+ it { is_expected.to respond_to :check_sum }
2035
+ it { is_expected.to respond_to :encrypted_data }
2036
+
2037
+ describe '#salt' do
2038
+ it 'is a Uint8Array structure' do
2039
+ expect(packet.salt).to be_a BinData::Uint8Array
2040
+ end
2041
+ end
2042
+ describe '#check_sum' do
2043
+ it 'is a BinData::Uint32le structure' do
2044
+ expect(packet.check_sum).to be_a BinData::Uint32le
2045
+ end
2046
+ end
2047
+ describe '#encrypted_data' do
2048
+ it 'is a Uint8Array structure' do
2049
+ expect(packet.encrypted_data).to be_a BinData::Uint8Array
2050
+ end
2051
+ end
2052
+ it 'reads itself' do
2053
+ value = {
2054
+ salt: [rand(0xFF)] * 16,
2055
+ check_sum: rand(0xFF),
2056
+ encrypted_data: [rand(0xFF)] * rand(40)
2057
+ }
2058
+ new_struct = described_class.new(value)
2059
+ expect(packet.read(new_struct.to_binary_s)).to eq(value)
2060
+ end
2061
+ end
2062
+
2063
+ describe '#decrypt_attribute_value' do
2064
+ it 'correctly decrypts the attribute value' do
2065
+ drsr.instance_variable_set(:@session_key, 'fd96e4fee462a67f8db319d72fcf818b'.unhexlify)
2066
+ attribute = '2302d5755f87896fab6e1dcd63e3b1e7ed4d8e8ebfb29e2bc36580c98d919356d340d442'.unhexlify
2067
+ decrypted = '7997edef91334c0182ee1cb5a9757769'.unhexlify
2068
+ expect(drsr.decrypt_attribute_value(attribute)).to eq(decrypted)
2069
+ end
2070
+ context 'when the session key is empty' do
2071
+ it 'raise an EncryptionError' do
2072
+ expect { drsr.decrypt_attribute_value('AAA') }.to raise_error(RubySMB::Error::EncryptionError)
2073
+ end
2074
+ end
2075
+ end
2076
+
2077
+ describe '#transform_key' do
2078
+ it 'correctly transforms the key' do
2079
+ input_key = '51040000510400'.unhexlify
2080
+ transformed = '5082000004881000'.unhexlify
2081
+ expect(drsr.transform_key(input_key)).to eq(transformed)
2082
+ end
2083
+ end
2084
+
2085
+ describe '#derive_key' do
2086
+ it 'correctly derives an unsigned integer into two keys' do
2087
+ base_key = 1105
2088
+ derived = ['5082000004881000'.unhexlify, '0028408000024408'.unhexlify]
2089
+ expect(drsr.derive_key(base_key)).to eq(derived)
2090
+ end
2091
+ end
2092
+
2093
+ describe '#remove_des_layer' do
2094
+ it 'correctly decrypts the hash' do
2095
+ crypted_hash = '7997edef91334c0182ee1cb5a9757769'.unhexlify
2096
+ rid = 1105
2097
+ decrypted = '32ed87bdb5fdc5e9cba88547376818d4'.unhexlify
2098
+ expect(drsr.remove_des_layer(crypted_hash, rid)).to eq(decrypted)
2099
+ end
2100
+ end
2101
+
2102
+ describe '#drs_get_nc_changes' do
2103
+ let(:h_drs) { handle = {context_handle_attributes: rand(0xFF), context_handle_uuid: '57800405-0301-3330-5566-040023007000'} }
2104
+ let(:nc_guid) { 'ee1ecfe6-109d-11ec-82a8-0242ac130003' }
2105
+ let(:dsa_object_guid) { '8609c6ea-8268-4c4f-a08a-001bca9bd1d7' }
2106
+ let(:args) { [ :drs_get_nc_changes, h_drs ] }
2107
+ let(:kwargs) { { nc_guid: nc_guid, dsa_object_guid: dsa_object_guid } }
2108
+ let(:request_struct) { described_class::DrsGetNcChangesRequest }
2109
+ let(:response_struct) { described_class::DrsGetNcChangesResponse }
2110
+ let(:values) do
2111
+ {
2112
+ h_drs: h_drs,
2113
+ dw_in_version: 8,
2114
+ pmsg_in: {
2115
+ msg_getchg: {
2116
+ uuid_dsa_obj_dest: dsa_object_guid,
2117
+ uuid_invoc_id_src: dsa_object_guid,
2118
+ p_nc: {
2119
+ guid: nc_guid,
2120
+ string_name: ["\0"]
2121
+ },
2122
+ ul_flags: described_class::DRS_INIT_SYNC | described_class::DRS_WRIT_REP,
2123
+ c_max_objects: 1,
2124
+ ul_extended_op: described_class::EXOP_REPL_OBJ
2125
+ }
2126
+ }
2127
+ }
2128
+ end
2129
+ let(:request) { request_struct.new(values) }
2130
+ let(:response) { response_struct.new(pmsg_out: {switch_type: 6}) }
2131
+ before :example do
2132
+ described_class::ATTRTYP_TO_ATTID.values.each do |oid|
2133
+ request.pmsg_in.msg_getchg.add_attrtyp_from_oid(oid)
2134
+ end
2135
+ allow(drsr).to receive(:dcerpc_request).and_return(response.to_binary_s)
2136
+ allow(response_struct).to receive(:read).and_return(response)
2137
+ end
2138
+
2139
+ it 'sends the correct request packet with authentication parameters' do
2140
+ drsr.send(*args, **kwargs)
2141
+ expect(drsr).to have_received(:dcerpc_request).with(
2142
+ request,
2143
+ auth_level: RubySMB::Dcerpc::RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
2144
+ auth_type: RubySMB::Dcerpc::RPC_C_AUTHN_WINNT
2145
+ )
2146
+ end
2147
+ it 'receives the expected response' do
2148
+ drsr.send(*args, **kwargs)
2149
+ expect(response_struct).to have_received(:read).with(response.to_binary_s)
2150
+ end
2151
+ context 'with an invalid response' do
2152
+ it 'raise an InvalidPacket exception' do
2153
+ allow(response_struct).to receive(:read).and_raise(IOError)
2154
+ expect { drsr.send(*args, **kwargs) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
2155
+ end
2156
+ end
2157
+ context 'when the response status is not STATUS_SUCCESS' do
2158
+ it 'raise an DrsrError exception' do
2159
+ response.error_status = WindowsError::NTStatus::STATUS_ACCESS_DENIED.value
2160
+ expect { drsr.send(*args, **kwargs) }.to raise_error(RubySMB::Dcerpc::Error::DrsrError)
2161
+ end
2162
+ end
2163
+ it 'returns the correct DrsGetNcChanges response' do
2164
+ expect(drsr.send(*args, **kwargs)).to eq(response)
2165
+ end
2166
+ end
2167
+
2168
+ end
2169
+