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,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