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,420 @@
1
+ RSpec.describe RubySMB::Dcerpc::Samr do
2
+ let(:samr) do
3
+ RubySMB::SMB1::Pipe.new(
4
+ tree: double('Tree'),
5
+ response: RubySMB::SMB1::Packet::NtCreateAndxResponse.new,
6
+ name: 'samr'
7
+ )
8
+ end
9
+
10
+ describe described_class::SamprHandle do
11
+ it 'is a Ndr::NdrContextHandle' do
12
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrContextHandle
13
+ end
14
+ end
15
+
16
+ describe '#samr_connect' do
17
+ let(:samr_connect_request) { double('SamrConnectRequest') }
18
+ let(:response) { double('Response') }
19
+ let(:samr_connect_response) { double('SamrConnectResponse') }
20
+ let(:server_handle) { double('server_handle') }
21
+ before :example do
22
+ allow(described_class::SamrConnectRequest).to receive(:new).and_return(samr_connect_request)
23
+ allow(samr).to receive(:dcerpc_request).and_return(response)
24
+ allow(described_class::SamrConnectResponse).to receive(:read).and_return(samr_connect_response)
25
+ allow(samr_connect_response).to receive_messages(
26
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
27
+ :server_handle => server_handle
28
+ )
29
+ end
30
+
31
+ it 'sets the request with the expected values' do
32
+ samr.samr_connect(server_name: 'TestServer')
33
+ expect(described_class::SamrConnectRequest).to have_received(:new).with(
34
+ server_name: 'TestServer',
35
+ desired_access: described_class::MAXIMUM_ALLOWED
36
+ )
37
+ end
38
+ it 'send the expected request structure' do
39
+ samr.samr_connect
40
+ expect(samr).to have_received(:dcerpc_request).with(samr_connect_request)
41
+ end
42
+ context 'when an IOError occurs while parsing the response' do
43
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
44
+ allow(described_class::SamrConnectResponse).to receive(:read).and_raise(IOError)
45
+ expect { samr.samr_connect }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
46
+ end
47
+ end
48
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
49
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
50
+ allow(samr_connect_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
51
+ expect { samr.samr_connect }.to raise_error(RubySMB::Dcerpc::Error::SamrError)
52
+ end
53
+ end
54
+ it 'returns the expected handler' do
55
+ expect(samr.samr_connect).to eq(server_handle)
56
+ end
57
+ context 'with a real binary stream' do
58
+ it 'returns the expected value' do
59
+ raw_response = "\x00\x00\x00\x00\xFCF\xAC\x19F\xF5\x9EF\x8E\x9A\x8C\xAC\x0FG\x18\xD8\x00\x00\x00\x00"
60
+ allow(samr).to receive(:dcerpc_request).and_return(raw_response)
61
+ allow(described_class::SamrConnectResponse).to receive(:read).and_call_original
62
+ expect(samr.samr_connect).to eq({:context_handle_attributes=>0, :context_handle_uuid=>"19ac46fc-f546-469e-8e9a-8cac0f4718d8"})
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#samr_lookup_domain' do
68
+ let(:server_handle) { double('server_handle') }
69
+ let(:samr_lookup_domain_request) { double('SamrLookupDomainInSamServerRequest') }
70
+ let(:response) { double('Response') }
71
+ let(:samr_lookup_domain_response) { double('SamrLookupDomainInSamServerResponse') }
72
+ let(:domain_id) { double('domain_id') }
73
+ before :example do
74
+ allow(described_class::SamrLookupDomainInSamServerRequest).to receive(:new).and_return(samr_lookup_domain_request)
75
+ allow(samr).to receive(:dcerpc_request).and_return(response)
76
+ allow(described_class::SamrLookupDomainInSamServerResponse).to receive(:read).and_return(samr_lookup_domain_response)
77
+ allow(samr_lookup_domain_response).to receive_messages(
78
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
79
+ :domain_id => domain_id
80
+ )
81
+ end
82
+
83
+ it 'sets the request with the expected values' do
84
+ samr.samr_lookup_domain(server_handle: server_handle, name: 'My Name')
85
+ expect(described_class::SamrLookupDomainInSamServerRequest).to have_received(:new).with(
86
+ server_handle: server_handle,
87
+ name: 'My Name'
88
+ )
89
+ end
90
+ it 'send the expected request structure' do
91
+ samr.samr_lookup_domain(server_handle: server_handle, name: '')
92
+ expect(samr).to have_received(:dcerpc_request).with(samr_lookup_domain_request)
93
+ end
94
+ context 'when an IOError occurs while parsing the response' do
95
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
96
+ allow(described_class::SamrLookupDomainInSamServerResponse).to receive(:read).and_raise(IOError)
97
+ expect { samr.samr_lookup_domain(server_handle: server_handle, name: '') }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
98
+ end
99
+ end
100
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
101
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
102
+ allow(samr_lookup_domain_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
103
+ expect { samr.samr_lookup_domain(server_handle: server_handle, name: '') }.to raise_error(RubySMB::Dcerpc::Error::SamrError)
104
+ end
105
+ end
106
+ it 'returns the expected handler' do
107
+ expect(samr.samr_lookup_domain(server_handle: server_handle, name: '')).to eq(domain_id)
108
+ end
109
+ context 'with a real binary stream' do
110
+ it 'returns the expected value' do
111
+ raw_response =
112
+ "\x00\x00\x02\x00\x04\x00\x00\x00"\
113
+ "\x01\x04\x00\x00\x00\x00\x00\x05"\
114
+ "\x15\x00\x00\x00~\xC7\x01\x19TU"\
115
+ "\x90\x00\xA0\xD8\xF8\xF3\x00\x00\x00\x00"
116
+ allow(samr).to receive(:dcerpc_request).and_return(raw_response)
117
+ allow(described_class::SamrLookupDomainInSamServerResponse).to receive(:read).and_call_original
118
+ expect(samr.samr_lookup_domain(server_handle: server_handle, name: '')).to eq(
119
+ "S-1-5-21-419547006-9459028-4093171872"
120
+ )
121
+ end
122
+ end
123
+ end
124
+
125
+ describe '#samr_open_domain' do
126
+ let(:server_handle) { double('server_handle') }
127
+ let(:domain_id) { double('domain_id') }
128
+ let(:samr_open_domain_request) { double('SamrOpenDomainRequest') }
129
+ let(:response) { double('Response') }
130
+ let(:samr_open_domain_response) { double('SamrOpenDomainResponse') }
131
+ let(:domain_handle) { double('domain_handle') }
132
+ before :example do
133
+ allow(described_class::SamrOpenDomainRequest).to receive(:new).and_return(samr_open_domain_request)
134
+ allow(samr).to receive(:dcerpc_request).and_return(response)
135
+ allow(described_class::SamrOpenDomainResponse).to receive(:read).and_return(samr_open_domain_response)
136
+ allow(samr_open_domain_response).to receive_messages(
137
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
138
+ :domain_handle => domain_handle
139
+ )
140
+ end
141
+
142
+ it 'sets the request with the expected values' do
143
+ samr.samr_open_domain(server_handle: server_handle, domain_id: domain_id)
144
+ expect(described_class::SamrOpenDomainRequest).to have_received(:new).with(
145
+ server_handle: server_handle,
146
+ desired_access: described_class::MAXIMUM_ALLOWED,
147
+ domain_id: domain_id
148
+ )
149
+ end
150
+ it 'send the expected request structure' do
151
+ samr.samr_open_domain(server_handle: server_handle, domain_id: domain_id)
152
+ expect(samr).to have_received(:dcerpc_request).with(samr_open_domain_request)
153
+ end
154
+ context 'when an IOError occurs while parsing the response' do
155
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
156
+ allow(described_class::SamrOpenDomainResponse).to receive(:read).and_raise(IOError)
157
+ expect { samr.samr_open_domain(server_handle: server_handle, domain_id: domain_id) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
158
+ end
159
+ end
160
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
161
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
162
+ allow(samr_open_domain_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
163
+ expect { samr.samr_open_domain(server_handle: server_handle, domain_id: domain_id) }.to raise_error(RubySMB::Dcerpc::Error::SamrError)
164
+ end
165
+ end
166
+ it 'returns the expected handler' do
167
+ expect(samr.samr_open_domain(server_handle: server_handle, domain_id: domain_id)).to eq(domain_handle)
168
+ end
169
+ context 'with a real binary stream' do
170
+ it 'returns the expected value' do
171
+ raw_response = "\x00\x00\x00\x00\xC3\x9C\xFEe\xB5\xBA{K\x96<v\x82\x156S\xAA\x00\x00\x00\x00"
172
+ allow(samr).to receive(:dcerpc_request).and_return(raw_response)
173
+ allow(described_class::SamrOpenDomainResponse).to receive(:read).and_call_original
174
+ expect(samr.samr_open_domain(server_handle: server_handle, domain_id: domain_id)).to eq(
175
+ {:context_handle_attributes=>0, :context_handle_uuid=>"65fe9cc3-bab5-4b7b-963c-7682153653aa"}
176
+ )
177
+ end
178
+ end
179
+ end
180
+
181
+ describe '#samr_enumerate_users_in_domain' do
182
+ let(:domain_handle) { double('domain_handle') }
183
+ let(:enumeration_context) { double('enumeration_context') }
184
+ let(:user_account_control) { double('user_account_control') }
185
+ let(:samr_enumerate_users_in_domain_request) { double('SamrEnumerateUsersInDomainRequest') }
186
+ let(:response) { double('Response') }
187
+ let(:samr_enumerate_users_in_domain_response) { double('SamrEnumerateUsersInDomainResponse') }
188
+ let(:entry1) { double('entry1') }
189
+ let(:entry2) { double('entry2') }
190
+ let(:entries) { [entry1, entry2] }
191
+ before :example do
192
+ allow(described_class::SamrEnumerateUsersInDomainRequest).to receive(:new).and_return(samr_enumerate_users_in_domain_request)
193
+ allow(samr_enumerate_users_in_domain_request).to receive(:enumeration_context=)
194
+ allow(samr_enumerate_users_in_domain_request).to receive(:enumeration_context).and_return(enumeration_context)
195
+ allow(samr).to receive(:dcerpc_request).and_return(response)
196
+ allow(described_class::SamrEnumerateUsersInDomainResponse).to receive(:read).and_return(samr_enumerate_users_in_domain_response)
197
+ allow(samr_enumerate_users_in_domain_response).to receive(:error_status).and_return(WindowsError::NTStatus::STATUS_SUCCESS)
198
+ allow(samr_enumerate_users_in_domain_response).to receive_message_chain(:buffer, :buffer => entries)
199
+ allow(entry1).to receive(:relative_id).and_return(501)
200
+ allow(entry2).to receive(:relative_id).and_return(502)
201
+ allow(entry1).to receive_message_chain(:name, :buffer => 'Entry 1')
202
+ allow(entry2).to receive_message_chain(:name, :buffer => 'Entry 2')
203
+ end
204
+
205
+ it 'sets the request with the expected values' do
206
+ samr.samr_enumerate_users_in_domain(
207
+ domain_handle: domain_handle,
208
+ enumeration_context: enumeration_context,
209
+ user_account_control: user_account_control
210
+ )
211
+ expect(described_class::SamrEnumerateUsersInDomainRequest).to have_received(:new).with(
212
+ domain_handle: domain_handle,
213
+ user_account_control: user_account_control,
214
+ prefered_maximum_length: 0xFFFFFFFF
215
+ )
216
+ expect(samr_enumerate_users_in_domain_request).to have_received(:enumeration_context=).with(enumeration_context)
217
+ end
218
+ it 'send the expected request structure' do
219
+ samr.samr_enumerate_users_in_domain(domain_handle: domain_handle)
220
+ expect(samr).to have_received(:dcerpc_request).with(samr_enumerate_users_in_domain_request)
221
+ end
222
+ context 'when an IOError occurs while parsing the response' do
223
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
224
+ allow(described_class::SamrEnumerateUsersInDomainResponse).to receive(:read).and_raise(IOError)
225
+ expect { samr.samr_enumerate_users_in_domain(domain_handle: domain_handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
226
+ end
227
+ end
228
+ context 'when the response error status is not ERROR_SUCCESS or STATUS_MORE_ENTRIES' do
229
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
230
+ allow(samr_enumerate_users_in_domain_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
231
+ expect { samr.samr_enumerate_users_in_domain(domain_handle: domain_handle) }.to raise_error(RubySMB::Dcerpc::Error::SamrError)
232
+ end
233
+ end
234
+ it 'returns the expected handler' do
235
+ expect(samr.samr_enumerate_users_in_domain(domain_handle: domain_handle)).to eq({
236
+ 501 => 'Entry 1',
237
+ 502 => 'Entry 2'
238
+ })
239
+ end
240
+ context 'with a real binary stream' do
241
+ it 'returns the expected value' do
242
+ raw_response =
243
+ "\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00\x00\x00\x04\x00\x02\x00"\
244
+ "\x06\x00\x00\x00\xF4\x01\x00\x00\x1A\x00\x1A\x00\b\x00\x02\x00\xF5"\
245
+ "\x01\x00\x00\n\x00\n\x00\f\x00\x02\x00\xF6\x01\x00\x00\f\x00\f\x00"\
246
+ "\x10\x00\x02\x00Q\x04\x00\x00\x10\x00\x10\x00\x14\x00\x02\x00\xE9\x03"\
247
+ "\x00\x00\x1E\x00\x1E\x00\x18\x00\x02\x00P\x04\x00\x00 \x00 \x00\x1C"\
248
+ "\x00\x02\x00\r\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00A\x00d\x00m"\
249
+ "\x00i\x00n\x00i\x00s\x00t\x00r\x00a\x00t\x00o\x00r\x00\x00\x00\x05"\
250
+ "\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00G\x00u\x00e\x00s\x00t\x00"\
251
+ "\x00\x00\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00k\x00r\x00b"\
252
+ "\x00t\x00g\x00t\x00\b\x00\x00\x00\x00\x00\x00\x00\b\x00\x00\x00s\x00m"\
253
+ "\x00b\x00t\x00e\x00s\x00t\x002\x00\x0F\x00\x00\x00\x00\x00\x00\x00\x0F"\
254
+ "\x00\x00\x00W\x00I\x00N\x00-\x00D\x00P\x000\x00M\x001\x00B\x00C\x007"\
255
+ "\x006\x008\x00$\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00\x00\x10\x00"\
256
+ "\x00\x00D\x00E\x00S\x00K\x00T\x00O\x00P\x00-\x005\x00A\x00R\x004\x00M"\
257
+ "\x002\x00S\x00$\x00\x06\x00\x00\x00\x00\x00\x00\x00"
258
+ allow(samr).to receive(:dcerpc_request).and_return(raw_response)
259
+ allow(described_class::SamrEnumerateUsersInDomainResponse).to receive(:read).and_call_original
260
+ expect(samr.samr_enumerate_users_in_domain(domain_handle: domain_handle)).to eq({
261
+ 500 => "Administrator".encode('utf-16le'),
262
+ 501 => "Guest".encode('utf-16le'),
263
+ 502 => "krbtgt".encode('utf-16le'),
264
+ 1105 => "smbtest2".encode('utf-16le'),
265
+ 1001 => "WIN-DP0M1BC768$".encode('utf-16le'),
266
+ 1104 => "DESKTOP-5AR4M2S$".encode('utf-16le')
267
+ })
268
+ end
269
+ end
270
+ context 'with a STATUS_MORE_ENTRIES response' do
271
+ let(:enumeration_context2) { double('enumeration_context2') }
272
+ let(:entry3) { double('entry3') }
273
+ let(:entry4) { double('entry4') }
274
+ let(:entries2) { [entry3, entry4] }
275
+ before :example do
276
+ first_pass = true
277
+ allow(described_class::SamrEnumerateUsersInDomainResponse).to receive(:read) do
278
+ if first_pass
279
+ allow(samr_enumerate_users_in_domain_response).to receive(:error_status).and_return(WindowsError::NTStatus::STATUS_MORE_ENTRIES)
280
+ allow(samr_enumerate_users_in_domain_response).to receive(:enumeration_context).and_return(enumeration_context2)
281
+ first_pass = false
282
+ else
283
+ allow(samr_enumerate_users_in_domain_response).to receive(:error_status).and_return(WindowsError::NTStatus::STATUS_SUCCESS)
284
+ allow(samr_enumerate_users_in_domain_response).to receive_message_chain(:buffer, :buffer => entries2)
285
+ end
286
+ samr_enumerate_users_in_domain_response
287
+ end
288
+ allow(entry3).to receive(:relative_id).and_return(503)
289
+ allow(entry4).to receive(:relative_id).and_return(504)
290
+ allow(entry3).to receive_message_chain(:name, :buffer => 'Entry 3')
291
+ allow(entry4).to receive_message_chain(:name, :buffer => 'Entry 4')
292
+ end
293
+ it 'sends multiple requests with the expected enumeration_context value' do
294
+ samr.samr_enumerate_users_in_domain(
295
+ domain_handle: domain_handle,
296
+ enumeration_context: enumeration_context
297
+ )
298
+ expect(samr).to have_received(:dcerpc_request).with(samr_enumerate_users_in_domain_request).twice
299
+ expect(samr_enumerate_users_in_domain_request).to have_received(:enumeration_context=).with(enumeration_context)
300
+ expect(samr_enumerate_users_in_domain_request).to have_received(:enumeration_context=).with(enumeration_context2)
301
+ end
302
+ it 'returns the expected hash' do
303
+ expect(samr.samr_enumerate_users_in_domain(domain_handle: domain_handle)).to eq({
304
+ 501 => 'Entry 1',
305
+ 502 => 'Entry 2',
306
+ 503 => 'Entry 3',
307
+ 504 => 'Entry 4'
308
+ })
309
+ end
310
+ end
311
+ end
312
+
313
+ describe '#samr_rid_to_sid' do
314
+ let(:object_handle) { double('object_handle') }
315
+ let(:samr_rid_to_sid_request) { double('SamrRidToSidRequest') }
316
+ let(:response) { double('Response') }
317
+ let(:samr_rid_to_sid_response) { double('SamrRidToSidResponse') }
318
+ let(:sid) { double('sid') }
319
+ before :example do
320
+ allow(described_class::SamrRidToSidRequest).to receive(:new).and_return(samr_rid_to_sid_request)
321
+ allow(samr).to receive(:dcerpc_request).and_return(response)
322
+ allow(described_class::SamrRidToSidResponse).to receive(:read).and_return(samr_rid_to_sid_response)
323
+ allow(samr_rid_to_sid_response).to receive_messages(
324
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
325
+ :sid => sid
326
+ )
327
+ end
328
+
329
+ it 'sets the request with the expected values' do
330
+ samr.samr_rid_to_sid(object_handle: object_handle, rid: 501)
331
+ expect(described_class::SamrRidToSidRequest).to have_received(:new).with(
332
+ object_handle: object_handle,
333
+ rid: 501
334
+ )
335
+ end
336
+ it 'send the expected request structure' do
337
+ samr.samr_rid_to_sid(object_handle: object_handle, rid: 501)
338
+ expect(samr).to have_received(:dcerpc_request).with(samr_rid_to_sid_request)
339
+ end
340
+ context 'when an IOError occurs while parsing the response' do
341
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
342
+ allow(described_class::SamrRidToSidResponse).to receive(:read).and_raise(IOError)
343
+ expect { samr.samr_rid_to_sid(object_handle: object_handle, rid: 501) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
344
+ end
345
+ end
346
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
347
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
348
+ allow(samr_rid_to_sid_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
349
+ expect { samr.samr_rid_to_sid(object_handle: object_handle, rid: 501) }.to raise_error(RubySMB::Dcerpc::Error::SamrError)
350
+ end
351
+ end
352
+ it 'returns the expected handler' do
353
+ expect(samr.samr_rid_to_sid(object_handle: object_handle, rid: 501)).to eq(sid)
354
+ end
355
+ context 'with a real binary stream' do
356
+ it 'returns the expected value' do
357
+ raw_response =
358
+ "\x00\x00\x02\x00\x05\x00\x00\x00\x01\x05\x00\x00\x00\x00\x00"\
359
+ "\x05\x15\x00\x00\x00~\xC7\x01\x19TU\x90\x00\xA0\xD8\xF8\xF3"\
360
+ "\xF4\x01\x00\x00\x00\x00\x00\x00"
361
+ allow(samr).to receive(:dcerpc_request).and_return(raw_response)
362
+ allow(described_class::SamrRidToSidResponse).to receive(:read).and_call_original
363
+ expect(samr.samr_rid_to_sid(object_handle: object_handle, rid: '')).to eq(
364
+ "S-1-5-21-419547006-9459028-4093171872-500"
365
+ )
366
+ end
367
+ end
368
+ end
369
+
370
+ describe '#close_handle' do
371
+ let(:samr_close_handle_request) { double('SamrCloseHandleRequest') }
372
+ let(:response) { double('Response') }
373
+ let(:samr_close_handle_response) { double('SamrCloseHandleResponse') }
374
+ let(:sam_handle) { double('sam_handle') }
375
+ before :example do
376
+ allow(described_class::SamrCloseHandleRequest).to receive(:new).and_return(samr_close_handle_request)
377
+ allow(samr).to receive(:dcerpc_request).and_return(response)
378
+ allow(described_class::SamrCloseHandleResponse).to receive(:read).and_return(samr_close_handle_response)
379
+ allow(samr_close_handle_response).to receive_messages(
380
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
381
+ :sam_handle => sam_handle
382
+ )
383
+ end
384
+
385
+ it 'sets the request with the expected values' do
386
+ samr.close_handle(sam_handle)
387
+ expect(described_class::SamrCloseHandleRequest).to have_received(:new).with(sam_handle: sam_handle)
388
+ end
389
+ it 'send the expected request structure' do
390
+ samr.close_handle(sam_handle)
391
+ expect(samr).to have_received(:dcerpc_request).with(samr_close_handle_request)
392
+ end
393
+ context 'when an IOError occurs while parsing the response' do
394
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
395
+ allow(described_class::SamrCloseHandleResponse).to receive(:read).and_raise(IOError)
396
+ expect { samr.close_handle(sam_handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
397
+ end
398
+ end
399
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
400
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
401
+ allow(samr_close_handle_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
402
+ expect { samr.close_handle(sam_handle) }.to raise_error(RubySMB::Dcerpc::Error::SamrError)
403
+ end
404
+ end
405
+ it 'returns the expected handler' do
406
+ expect(samr.close_handle(sam_handle)).to eq(sam_handle)
407
+ end
408
+ context 'with a real binary stream' do
409
+ it 'returns the expected value' do
410
+ raw_response = "\x00\x00\x00\x00\e\x05ucy\xE3\b@\xAC\xFDjc\xEB\xD1?\xBF\x00\x00\x00\x00"
411
+ allow(samr).to receive(:dcerpc_request).and_return(raw_response)
412
+ allow(described_class::SamrCloseHandleResponse).to receive(:read).and_call_original
413
+ expect(samr.close_handle(sam_handle)).to eq({
414
+ :context_handle_attributes=>0,
415
+ :context_handle_uuid=>"6375051b-e379-4008-acfd-6a63ebd13fbf"
416
+ })
417
+ end
418
+ end
419
+ end
420
+ end
@@ -0,0 +1,92 @@
1
+ RSpec.describe RubySMB::Dcerpc::SecTrailer do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :auth_type }
5
+ it { is_expected.to respond_to :auth_level }
6
+ it { is_expected.to respond_to :auth_pad_length }
7
+ it { is_expected.to respond_to :auth_reserved }
8
+ it { is_expected.to respond_to :auth_context_id }
9
+
10
+ it 'is little endian' do
11
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
12
+ end
13
+
14
+ it 'has :byte_align parameter set to the expected value' do
15
+ expect(described_class.default_parameters[:byte_align]).to eq(1)
16
+ end
17
+
18
+ describe '#auth_type' do
19
+ it 'is a NdrUint8' do
20
+ expect(packet.auth_type).to be_a RubySMB::Dcerpc::Ndr::NdrUint8
21
+ end
22
+ end
23
+
24
+ describe '#auth_level' do
25
+ it 'is a NdrUint8' do
26
+ expect(packet.auth_level).to be_a RubySMB::Dcerpc::Ndr::NdrUint8
27
+ end
28
+ end
29
+
30
+ describe '#auth_pad_length' do
31
+ it 'is a NdrUint8' do
32
+ expect(packet.auth_pad_length).to be_a RubySMB::Dcerpc::Ndr::NdrUint8
33
+ end
34
+
35
+ it 'defaults to 0' do
36
+ expect(packet.auth_pad_length).to eq(0)
37
+ end
38
+
39
+ context 'when the parent structure has an #auth_pad field' do
40
+ let(:pad) { 'A' * rand(0xFF) }
41
+ let(:packet_with_parent) do
42
+ Class.new(BinData::Record) do
43
+ string :auth_pad
44
+ sec_trailer :sec_trailer
45
+ end.new(auth_pad: pad)
46
+ end
47
+
48
+ it 'has a value equal to the size of the #auth_pad field' do
49
+ expect(packet_with_parent.sec_trailer.auth_pad_length).to eq(pad.size)
50
+ end
51
+ end
52
+
53
+ context 'when the parent structure does not have an #auth_pad field' do
54
+ let(:pad) { 'A' * rand(0xFF) }
55
+ let(:packet_with_parent) do
56
+ Class.new(BinData::Record) do
57
+ string :other
58
+ sec_trailer :sec_trailer
59
+ end.new(other: pad)
60
+ end
61
+
62
+ it 'defaults to 0' do
63
+ expect(packet_with_parent.sec_trailer.auth_pad_length).to eq(0)
64
+ end
65
+ end
66
+ end
67
+
68
+ describe '#auth_reserved' do
69
+ it 'is a NdrUint8' do
70
+ expect(packet.auth_reserved).to be_a RubySMB::Dcerpc::Ndr::NdrUint8
71
+ end
72
+ end
73
+
74
+ describe '#auth_context_id' do
75
+ it 'is a NdrUint32' do
76
+ expect(packet.auth_context_id).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
77
+ end
78
+ end
79
+
80
+ it 'reads its own binary representation and output the same packet' do
81
+ packet = described_class.new(
82
+ auth_type: rand(0xFF),
83
+ auth_level: rand(0xFF),
84
+ auth_pad_length: rand(0xFF),
85
+ auth_reserved: rand(0xFF),
86
+ auth_context_id: rand(0xFF)
87
+ )
88
+ binary = packet.to_binary_s
89
+ expect(described_class.read(binary)).to eq(packet)
90
+ end
91
+
92
+ end