ruby_smb 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/examples/anonymous_auth.rb +3 -3
  5. data/examples/append_file.rb +10 -8
  6. data/examples/authenticate.rb +9 -5
  7. data/examples/delete_file.rb +8 -6
  8. data/examples/enum_registry_key.rb +5 -4
  9. data/examples/enum_registry_values.rb +5 -4
  10. data/examples/list_directory.rb +8 -6
  11. data/examples/negotiate_with_netbios_service.rb +9 -5
  12. data/examples/net_share_enum_all.rb +6 -4
  13. data/examples/pipes.rb +11 -12
  14. data/examples/query_service_status.rb +64 -0
  15. data/examples/read_file.rb +8 -6
  16. data/examples/read_registry_key_value.rb +6 -5
  17. data/examples/rename_file.rb +9 -7
  18. data/examples/tree_connect.rb +7 -5
  19. data/examples/write_file.rb +9 -7
  20. data/lib/ruby_smb/client.rb +72 -43
  21. data/lib/ruby_smb/client/negotiation.rb +1 -0
  22. data/lib/ruby_smb/dcerpc.rb +2 -0
  23. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  24. data/lib/ruby_smb/dcerpc/ndr.rb +209 -44
  25. data/lib/ruby_smb/dcerpc/request.rb +13 -0
  26. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  27. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  28. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  29. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  30. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  31. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  32. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  33. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  34. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  35. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  36. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  37. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  38. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  39. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  40. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  41. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  46. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  47. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  48. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  49. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  50. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  51. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  52. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  53. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  54. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  55. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  56. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  57. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  58. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  59. data/lib/ruby_smb/dispatcher/socket.rb +1 -1
  60. data/lib/ruby_smb/field/stringz16.rb +17 -1
  61. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  62. data/lib/ruby_smb/smb1/file.rb +2 -10
  63. data/lib/ruby_smb/smb1/pipe.rb +2 -0
  64. data/lib/ruby_smb/smb2/file.rb +25 -17
  65. data/lib/ruby_smb/smb2/pipe.rb +3 -0
  66. data/lib/ruby_smb/smb2/tree.rb +9 -3
  67. data/lib/ruby_smb/version.rb +1 -1
  68. data/spec/lib/ruby_smb/client_spec.rb +161 -60
  69. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  70. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  71. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  72. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  73. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  74. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  75. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  76. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  77. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  78. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  79. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  80. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  81. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  82. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  83. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  84. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  85. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  86. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  87. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  88. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  89. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  90. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  91. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  92. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  93. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  94. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  95. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  96. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  97. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  98. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  99. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  100. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  101. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +215 -41
  102. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
  103. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  104. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  105. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +7 -0
  106. data/spec/lib/ruby_smb/smb2/file_spec.rb +60 -6
  107. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +7 -0
  108. data/spec/lib/ruby_smb/smb2/tree_spec.rb +35 -1
  109. metadata +72 -2
  110. metadata.gz.sig +0 -0
@@ -0,0 +1,22 @@
1
+ RSpec.describe RubySMB::Dcerpc::Winreg::SaveKeyResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :error_status }
5
+
6
+ it 'is little endian' do
7
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
8
+ end
9
+
10
+ describe '#error_status' do
11
+ it 'is a 32-bit unsigned integer' do
12
+ expect(packet.error_status).to be_a BinData::Uint32le
13
+ end
14
+ end
15
+
16
+ describe '#initialize_instance' do
17
+ it 'sets #opnum to REG_CREATE_KEY constant' do
18
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_CREATE_KEY)
19
+ end
20
+ end
21
+ end
22
+
@@ -132,8 +132,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
132
132
  describe '#query_value' do
133
133
  let(:handle) { double('Handle') }
134
134
  let(:value_name) { double('Value Name') }
135
- let(:query_value_request_packet1) { double('Query Value Request Packet #1') }
136
- let(:query_value_request_packet2) { double('Query Value Request Packet #2') }
135
+ let(:query_value_request_packet) { double('Query Value Request Packet #1') }
137
136
  let(:lp_data1) { double('LpData #1') }
138
137
  let(:lp_data2) { double('LpData #2') }
139
138
  let(:response1) { double('Response #1') }
@@ -142,26 +141,28 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
142
141
  let(:query_value_response2) { double('Query Value Response #2') }
143
142
  let(:data) { double('Data') }
144
143
  let(:lpcb_data) { double('LpcbData') }
145
- let(:lpcb_data_referent) { double('Lpcb Data Referent') }
144
+ let(:lpcb_data_referent) { double('LpcbData Referent') }
145
+ let(:lp_data2_referent) { double('LpData Referent') }
146
146
  before :example do
147
+ allow(described_class::QueryValueRequest).to receive(:new).and_return(query_value_request_packet)
148
+ allow(query_value_request_packet).to receive_messages(
149
+ :lp_type= => nil,
150
+ :lpcb_data= => nil,
151
+ :lpcb_len= => nil,
152
+ :lp_data= => nil,
153
+ :lp_data => lp_data2,
154
+ )
155
+ allow(lp_data2).to receive(:referent).and_return(lp_data2_referent)
156
+ allow(lp_data2_referent).to receive(:max_count=)
147
157
  first_request = true
148
- allow(described_class::QueryValueRequest).to receive(:new) do
158
+ allow(winreg).to receive(:dcerpc_request) do |arg|
149
159
  if first_request
150
160
  first_request = false
151
- query_value_request_packet1
161
+ response1
152
162
  else
153
- query_value_request_packet2
163
+ response2
154
164
  end
155
165
  end
156
- allow(query_value_request_packet1).to receive(:lp_data).and_return(lp_data1)
157
- allow(query_value_request_packet2).to receive_messages(
158
- :lp_data => lp_data2,
159
- :lpcb_data= => nil
160
- )
161
- allow(lp_data1).to receive(:referent_identifier=)
162
- allow(lp_data2).to receive(:max_count=)
163
- allow(winreg).to receive(:dcerpc_request).with(query_value_request_packet1).and_return(response1)
164
- allow(winreg).to receive(:dcerpc_request).with(query_value_request_packet2).and_return(response2)
165
166
  allow(described_class::QueryValueResponse).to receive(:read).with(response1).and_return(query_value_response1)
166
167
  allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_return(query_value_response2)
167
168
  allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
@@ -175,24 +176,22 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
175
176
 
176
177
  it 'create the expected QueryValueRequest packets' do
177
178
  winreg.query_value(handle, value_name)
178
- expect(described_class::QueryValueRequest).to have_received(:new).with(hkey: handle, lp_value_name: value_name).twice
179
- end
180
-
181
- it 'sets the expected user rights on the first request packet' do
182
- winreg.query_value(handle, value_name)
183
- expect(lp_data1).to have_received(:referent_identifier=).with(0)
179
+ expect(described_class::QueryValueRequest).to have_received(:new).with(hkey: handle, lp_value_name: value_name)
184
180
  end
185
181
 
186
- it 'sets the expected user rights on the second request packet' do
182
+ it 'sets the expected fields on the request packet' do
187
183
  winreg.query_value(handle, value_name)
188
- expect(lp_data2).to have_received(:max_count=).with(lpcb_data_referent)
189
- expect(query_value_request_packet2).to have_received(:lpcb_data=).with(lpcb_data)
184
+ expect(query_value_request_packet).to have_received(:lp_type=).with(0)
185
+ expect(query_value_request_packet).to have_received(:lpcb_data=).with(0)
186
+ expect(query_value_request_packet).to have_received(:lpcb_len=).with(0)
187
+ expect(query_value_request_packet).to have_received(:lpcb_data=).with(lpcb_data)
188
+ expect(query_value_request_packet).to have_received(:lp_data=).with([])
189
+ expect(lp_data2_referent).to have_received(:max_count=).with(lpcb_data_referent)
190
190
  end
191
191
 
192
192
  it 'sends the expected dcerpc requests' do
193
193
  winreg.query_value(handle, value_name)
194
- expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet1).once.ordered
195
- expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet2).once.ordered
194
+ expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet).twice
196
195
  end
197
196
 
198
197
  context 'when receiving the first response' do
@@ -293,8 +292,20 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
293
292
  let(:query_info_key_request_packet) { double('CloseKey Request Packet') }
294
293
  let(:response) { double('Response') }
295
294
  let(:query_info_key_response) { double('CloseKey Response') }
295
+ let(:lp_class) { double('LpClass') }
296
+ let(:lp_class_referent) { double('LpClass referent') }
297
+ let(:lp_class_buf_ref) { double('LpClass buffer referent') }
296
298
  before :example do
297
299
  allow(described_class::QueryInfoKeyRequest).to receive(:new).and_return(query_info_key_request_packet)
300
+ allow(query_info_key_request_packet).to receive_messages(
301
+ :lp_class= => nil,
302
+ :lp_class => lp_class,
303
+ )
304
+ allow(lp_class).to receive(:referent).and_return(lp_class_referent)
305
+ allow(lp_class_referent).to receive(:actual_count=)
306
+ allow(lp_class).to receive(:maximum_length=)
307
+ allow(lp_class).to receive_message_chain(:buffer, :referent => lp_class_buf_ref)
308
+ allow(lp_class_buf_ref).to receive(:max_count=)
298
309
  allow(winreg).to receive(:dcerpc_request).and_return(response)
299
310
  allow(described_class::QueryInfoKeyResponse).to receive(:read).and_return(query_info_key_response)
300
311
  allow(query_info_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
@@ -310,6 +321,14 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
310
321
  expect(winreg).to have_received(:dcerpc_request).with(query_info_key_request_packet)
311
322
  end
312
323
 
324
+ it 'sets the expected fields on the request packet' do
325
+ winreg.query_info_key(handle)
326
+ expect(query_info_key_request_packet).to have_received(:lp_class=).with('')
327
+ expect(lp_class_referent).to have_received(:actual_count=).with(0)
328
+ expect(lp_class).to have_received(:maximum_length=).with(1024)
329
+ expect(lp_class_buf_ref).to have_received(:max_count=).with(1024 / 2)
330
+ end
331
+
313
332
  it 'creates a QueryInfoKeyResponse structure from the expected dcerpc response' do
314
333
  winreg.query_info_key(handle)
315
334
  expect(described_class::QueryInfoKeyResponse).to have_received(:read).with(response)
@@ -338,25 +357,27 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
338
357
  let(:handle) { double('Handle') }
339
358
  let(:index) { double('Index') }
340
359
  let(:enum_key_request_packet) { double('enum_key Request Packet') }
341
- let(:lp_class) { double('Lp Class') }
342
360
  let(:lp_name) { double('Lp Name') }
343
361
  let(:buffer) { double('Buffer') }
344
- let(:lp_class_buffer_referent) { double('Lp Class buffer referent') }
345
362
  let(:lp_name_buffer_referent) { double('Lp Name buffer referent') }
346
363
  let(:response) { double('Response') }
347
364
  let(:enum_key_response) { double('enum_key Response') }
348
365
  let(:result_str) { double('Result String') }
366
+ let(:lp_class) { double('Lp Class') }
367
+ let(:lp_class_buffer_referent) { double('Lp Class buffer referent') }
349
368
  before :example do
350
369
  allow(described_class::EnumKeyRequest).to receive(:new).and_return(enum_key_request_packet)
351
370
  allow(enum_key_request_packet).to receive_messages(
352
371
  :lpft_last_write_time= => nil,
353
- :lp_class => lp_class,
354
- :lp_name => lp_name
372
+ :lp_class= => nil,
373
+ :lp_name => lp_name,
374
+ :lp_class => lp_class
355
375
  )
356
376
  allow(lp_class).to receive(:referent).and_return(lp_class_buffer_referent)
377
+ allow(lp_class_buffer_referent).to receive(:buffer=)
357
378
  allow(lp_name).to receive(:buffer).and_return(buffer)
379
+ allow(lp_name).to receive(:buffer=)
358
380
  allow(buffer).to receive(:referent).and_return(lp_name_buffer_referent)
359
- allow(lp_class_buffer_referent).to receive(:buffer=)
360
381
  allow(lp_name_buffer_referent).to receive(:max_count=)
361
382
  allow(winreg).to receive(:dcerpc_request).and_return(response)
362
383
  allow(described_class::EnumKeyResponse).to receive(:read).and_return(enum_key_response)
@@ -369,10 +390,12 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
369
390
  expect(described_class::EnumKeyRequest).to have_received(:new).with(hkey: handle, dw_index: index)
370
391
  end
371
392
 
372
- it 'sets the expected user rights on the request packet' do
393
+ it 'sets the expected parameters on the request packet' do
373
394
  winreg.enum_key(handle, index)
374
395
  expect(enum_key_request_packet).to have_received(:lpft_last_write_time=).with(0)
375
- expect(lp_class_buffer_referent).to have_received(:buffer=).with(0)
396
+ expect(enum_key_request_packet).to have_received(:lp_class=).with('')
397
+ expect(lp_class_buffer_referent).to have_received(:buffer=).with(:null)
398
+ expect(lp_name).to have_received(:buffer=).with('')
376
399
  expect(lp_name_buffer_referent).to have_received(:max_count=).with(256)
377
400
  end
378
401
 
@@ -410,7 +433,6 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
410
433
  let(:index) { double('Index') }
411
434
  let(:enum_value_request_packet) { double('EnumValue Request Packet') }
412
435
  let(:lp_value_name) { double('Lp Value Name') }
413
- let(:lp_data) { double('Lp Data') }
414
436
  let(:buffer) { double('Buffer') }
415
437
  let(:referent) { double('Referent') }
416
438
  let(:response) { double('Response') }
@@ -418,14 +440,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
418
440
  let(:result_str) { double('Result String') }
419
441
  before :example do
420
442
  allow(described_class::EnumValueRequest).to receive(:new).and_return(enum_value_request_packet)
421
- allow(enum_value_request_packet).to receive_messages(
422
- :lp_value_name => lp_value_name,
423
- :lp_data => lp_data
424
- )
443
+ allow(enum_value_request_packet).to receive(:lp_value_name).and_return(lp_value_name)
425
444
  allow(lp_value_name).to receive(:buffer).and_return(buffer)
445
+ allow(lp_value_name).to receive(:buffer=)
426
446
  allow(buffer).to receive(:referent).and_return(referent)
427
447
  allow(referent).to receive(:max_count=)
428
- allow(lp_data).to receive(:referent_identifier=)
429
448
  allow(winreg).to receive(:dcerpc_request).and_return(response)
430
449
  allow(described_class::EnumValueResponse).to receive(:read).and_return(enum_value_response)
431
450
  allow(enum_value_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
@@ -437,10 +456,10 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
437
456
  expect(described_class::EnumValueRequest).to have_received(:new).with(hkey: handle, dw_index: index)
438
457
  end
439
458
 
440
- it 'sets the expected user rights on the request packet' do
459
+ it 'sets the expected buffer on the request packet' do
441
460
  winreg.enum_value(handle, index)
442
461
  expect(referent).to have_received(:max_count=).with(256)
443
- expect(lp_data).to have_received(:referent_identifier=).with(0)
462
+ expect(lp_value_name).to have_received(:buffer=).with('')
444
463
  end
445
464
 
446
465
  it 'sends the expected dcerpc request' do
@@ -492,6 +511,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
492
511
  expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
493
512
  end
494
513
 
514
+ it 'does not bind a DCERPC connection if #bind argument is false' do
515
+ winreg.has_registry_key?(key, bind: false)
516
+ expect(winreg).to_not have_received(:bind)
517
+ end
518
+
495
519
  it 'opens the expected root key' do
496
520
  winreg.has_registry_key?(key)
497
521
  expect(winreg).to have_received(:open_root_key).with(root_key)
@@ -519,6 +543,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
519
543
  it 'closes the key' do
520
544
  winreg.has_registry_key?(key)
521
545
  expect(winreg).to have_received(:close_key).with(subkey_handle)
546
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
522
547
  end
523
548
 
524
549
  it 'returns true when no error occurs' do
@@ -549,6 +574,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
549
574
  expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
550
575
  end
551
576
 
577
+ it 'does not bind a DCERPC connection if #bind argument is false' do
578
+ winreg.read_registry_key_value(key, value_name, bind: false)
579
+ expect(winreg).to_not have_received(:bind)
580
+ end
581
+
552
582
  it 'opens the expected root key' do
553
583
  winreg.read_registry_key_value(key, value_name)
554
584
  expect(winreg).to have_received(:open_root_key).with(root_key)
@@ -567,6 +597,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
567
597
  it 'closes the key' do
568
598
  winreg.read_registry_key_value(key, value_name)
569
599
  expect(winreg).to have_received(:close_key).with(subkey_handle)
600
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
570
601
  end
571
602
 
572
603
  it 'returns expect registry key value' do
@@ -600,6 +631,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
600
631
  expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
601
632
  end
602
633
 
634
+ it 'does not bind a DCERPC connection if #bind argument is false' do
635
+ winreg.enum_registry_key(key, bind: false)
636
+ expect(winreg).to_not have_received(:bind)
637
+ end
638
+
603
639
  it 'opens the expected root key' do
604
640
  winreg.enum_registry_key(key)
605
641
  expect(winreg).to have_received(:open_root_key).with(root_key)
@@ -630,6 +666,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
630
666
  it 'closes the key' do
631
667
  winreg.enum_registry_key(key)
632
668
  expect(winreg).to have_received(:close_key).with(subkey_handle)
669
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
633
670
  end
634
671
 
635
672
  it 'returns the expected array of enumerated keys' do
@@ -667,6 +704,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
667
704
  expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
668
705
  end
669
706
 
707
+ it 'does not bind a DCERPC connection if #bind argument is false' do
708
+ winreg.enum_registry_values(key, bind: false)
709
+ expect(winreg).to_not have_received(:bind)
710
+ end
711
+
670
712
  it 'opens the expected root key' do
671
713
  winreg.enum_registry_values(key)
672
714
  expect(winreg).to have_received(:open_root_key).with(root_key)
@@ -697,6 +739,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
697
739
  it 'closes the key' do
698
740
  winreg.enum_registry_values(key)
699
741
  expect(winreg).to have_received(:close_key).with(subkey_handle)
742
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
700
743
  end
701
744
 
702
745
  it 'returns the expected array of enumerated keys' do
@@ -707,4 +750,135 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
707
750
  expect(winreg.enum_registry_values(key)).to eq([value1, value2])
708
751
  end
709
752
  end
753
+
754
+ describe '#create_key' do
755
+ let(:handle) { double('Handle') }
756
+ let(:sub_key) { double('Sub key') }
757
+ let(:create_key_request) { double('CreateKey Request') }
758
+ let(:response) { double('Response') }
759
+ let(:create_key_response) { double('CreateKey Response') }
760
+ let(:hkey) { double('hkey') }
761
+ before :example do
762
+ allow(described_class::CreateKeyRequest).to receive(:new).and_return(create_key_request)
763
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
764
+ allow(described_class::CreateKeyResponse).to receive(:read).and_return(create_key_response)
765
+ allow(create_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
766
+ allow(create_key_response).to receive(:hkey).and_return(hkey)
767
+ end
768
+
769
+ it 'create the expected CreateKeyRequest packet with the default options' do
770
+ opts = {
771
+ hkey: handle,
772
+ lp_sub_key: sub_key,
773
+ lp_class: :null,
774
+ dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
775
+ sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(maximum: 1),
776
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
777
+ lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY
778
+ }
779
+ winreg.create_key(handle, sub_key)
780
+ expect(described_class::CreateKeyRequest).to have_received(:new).with(opts)
781
+ end
782
+
783
+ it 'create the expected CreateKeyRequest packet with custom options' do
784
+ opts = {
785
+ hkey: handle,
786
+ lp_sub_key: sub_key,
787
+ lp_class: 'MyClass',
788
+ dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_SYMLINK,
789
+ sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(key_set_value: 1),
790
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new(n_length: 3),
791
+ lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_OPENED_EXISTING_KEY
792
+ }
793
+ winreg.create_key(handle, sub_key, opts)
794
+ expect(described_class::CreateKeyRequest).to have_received(:new).with(opts)
795
+ end
796
+
797
+ it 'sends the expected dcerpc request' do
798
+ winreg.create_key(handle, sub_key)
799
+ expect(winreg).to have_received(:dcerpc_request).with(create_key_request)
800
+ end
801
+
802
+ it 'creates a CreateKeyResponse structure from the expected dcerpc response' do
803
+ winreg.create_key(handle, sub_key)
804
+ expect(described_class::CreateKeyResponse).to have_received(:read).with(response)
805
+ end
806
+
807
+ context 'when an IOError occurs while parsing the response' do
808
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
809
+ allow(described_class::CreateKeyResponse).to receive(:read).and_raise(IOError)
810
+ expect { winreg.create_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
811
+ end
812
+ end
813
+
814
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
815
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
816
+ allow(create_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
817
+ expect { winreg.create_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
818
+ end
819
+ end
820
+
821
+ it 'returns the expected key name' do
822
+ expect(winreg.create_key(handle, sub_key)).to eq(hkey)
823
+ end
824
+ end
825
+
826
+ describe '#save_key' do
827
+ let(:handle) { double('Handle') }
828
+ let(:filename) { double('Filename') }
829
+ let(:save_key_request) { double('CreateKey Request') }
830
+ let(:response) { double('Response') }
831
+ let(:save_key_response) { double('CreateKey Response') }
832
+ let(:hkey) { double('hkey') }
833
+ before :example do
834
+ allow(described_class::SaveKeyRequest).to receive(:new).and_return(save_key_request)
835
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
836
+ allow(described_class::SaveKeyResponse).to receive(:read).and_return(save_key_response)
837
+ allow(save_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
838
+ end
839
+
840
+ it 'create the expected SaveKeyRequest packet with the default options' do
841
+ opts = {
842
+ hkey: handle,
843
+ lp_file: filename,
844
+ lp_security_attributes: :null,
845
+ }
846
+ winreg.save_key(handle, filename)
847
+ expect(described_class::SaveKeyRequest).to have_received(:new).with(opts)
848
+ end
849
+
850
+ it 'create the expected SaveKeyRequest packet with custom options' do
851
+ opts = {
852
+ hkey: handle,
853
+ lp_file: filename,
854
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
855
+ }
856
+ winreg.save_key(handle, filename, opts)
857
+ expect(described_class::SaveKeyRequest).to have_received(:new).with(opts)
858
+ end
859
+
860
+ it 'sends the expected dcerpc request' do
861
+ winreg.save_key(handle, filename)
862
+ expect(winreg).to have_received(:dcerpc_request).with(save_key_request)
863
+ end
864
+
865
+ it 'creates a SaveKeyResponse structure from the expected dcerpc response' do
866
+ winreg.save_key(handle, filename)
867
+ expect(described_class::SaveKeyResponse).to have_received(:read).with(response)
868
+ end
869
+
870
+ context 'when an IOError occurs while parsing the response' do
871
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
872
+ allow(described_class::SaveKeyResponse).to receive(:read).and_raise(IOError)
873
+ expect { winreg.save_key(handle, filename) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
874
+ end
875
+ end
876
+
877
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
878
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
879
+ allow(save_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
880
+ expect { winreg.save_key(handle, filename) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
881
+ end
882
+ end
883
+ end
710
884
  end
@@ -102,26 +102,26 @@ RSpec.describe RubySMB::Dispatcher::Socket do
102
102
  end
103
103
 
104
104
  it 'reads the number of bytes specified in the nbss header' do
105
- packet_length = 10
106
- session_header.packet_length = packet_length
105
+ stream_protocol_length = 10
106
+ session_header.stream_protocol_length = stream_protocol_length
107
107
  allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
108
108
  expect(response_socket).to receive(:read).with(4).and_return(session_header)
109
- expect(response_socket).to receive(:read).with(packet_length).and_return('A' * packet_length)
109
+ expect(response_socket).to receive(:read).with(stream_protocol_length).and_return('A' * stream_protocol_length)
110
110
  smb_socket.recv_packet
111
111
  end
112
112
 
113
113
  context 'when the socket does not return everything the first time' do
114
114
  it 'calls #read several times until everything is returned' do
115
- packet_length = 67
115
+ stream_protocol_length = 67
116
116
  returned_length = 10
117
- session_header.packet_length = packet_length
117
+ session_header.stream_protocol_length = stream_protocol_length
118
118
  allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
119
119
 
120
120
  expect(response_socket).to receive(:read).with(4).and_return(session_header)
121
121
  loop do
122
- expect(response_socket).to receive(:read).with(packet_length).and_return('A' * returned_length).once
123
- packet_length -= returned_length
124
- break if packet_length <= 0
122
+ expect(response_socket).to receive(:read).with(stream_protocol_length).and_return('A' * returned_length).once
123
+ stream_protocol_length -= returned_length
124
+ break if stream_protocol_length <= 0
125
125
  end
126
126
  smb_socket.recv_packet
127
127
  end
@@ -134,7 +134,7 @@ RSpec.describe RubySMB::Dispatcher::Socket do
134
134
 
135
135
  context 'when the SMB packet is empty' do
136
136
  it 'returns the nbss header only' do
137
- session_header.packet_length = 0
137
+ session_header.stream_protocol_length = 0
138
138
  allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
139
139
  expect(smb_socket.recv_packet(full_response: true)).to eq(session_header.to_binary_s)
140
140
  end
@@ -148,7 +148,7 @@ RSpec.describe RubySMB::Dispatcher::Socket do
148
148
 
149
149
  context 'when the SMB packet is empty' do
150
150
  it 'returns an empty string' do
151
- session_header.packet_length = 0
151
+ session_header.stream_protocol_length = 0
152
152
  allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
153
153
  expect(smb_socket.recv_packet(full_response: false)).to eq('')
154
154
  end