ruby_smb 1.0.3 → 2.0.1

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 (200) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +3 -2
  5. data/Gemfile +6 -2
  6. data/README.md +35 -47
  7. data/examples/enum_registry_key.rb +28 -0
  8. data/examples/enum_registry_values.rb +30 -0
  9. data/examples/negotiate.rb +51 -8
  10. data/examples/pipes.rb +2 -1
  11. data/examples/read_file_encryption.rb +56 -0
  12. data/examples/read_registry_key_value.rb +32 -0
  13. data/lib/ruby_smb.rb +4 -1
  14. data/lib/ruby_smb/client.rb +233 -22
  15. data/lib/ruby_smb/client/authentication.rb +70 -33
  16. data/lib/ruby_smb/client/echo.rb +20 -2
  17. data/lib/ruby_smb/client/encryption.rb +62 -0
  18. data/lib/ruby_smb/client/negotiation.rb +172 -24
  19. data/lib/ruby_smb/client/signing.rb +19 -0
  20. data/lib/ruby_smb/client/tree_connect.rb +24 -18
  21. data/lib/ruby_smb/client/utils.rb +8 -7
  22. data/lib/ruby_smb/client/winreg.rb +46 -0
  23. data/lib/ruby_smb/crypto.rb +30 -0
  24. data/lib/ruby_smb/dcerpc.rb +38 -0
  25. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  26. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  27. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  28. data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
  29. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  30. data/lib/ruby_smb/dcerpc/request.rb +28 -9
  31. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
  32. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  33. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  34. data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
  35. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  36. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  37. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  38. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  39. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  40. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  41. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  42. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  43. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  44. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  45. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  46. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  47. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
  48. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  49. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  50. data/lib/ruby_smb/dispatcher/socket.rb +4 -3
  51. data/lib/ruby_smb/error.rb +68 -2
  52. data/lib/ruby_smb/generic_packet.rb +33 -4
  53. data/lib/ruby_smb/smb1/commands.rb +1 -1
  54. data/lib/ruby_smb/smb1/file.rb +66 -15
  55. data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
  56. data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
  57. data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
  58. data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
  59. data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
  60. data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
  61. data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
  62. data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
  63. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
  64. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
  65. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
  66. data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
  67. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
  68. data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
  69. data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
  70. data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
  71. data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
  72. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
  73. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
  74. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +3 -2
  75. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
  76. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +3 -2
  77. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
  78. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
  79. data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
  80. data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
  81. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
  82. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
  83. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
  84. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
  85. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
  86. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
  87. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
  88. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
  89. data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
  90. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
  91. data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
  92. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
  93. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
  94. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
  95. data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
  96. data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
  97. data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
  98. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +3 -6
  99. data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
  100. data/lib/ruby_smb/smb1/pipe.rb +87 -6
  101. data/lib/ruby_smb/smb1/tree.rb +50 -3
  102. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  103. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  104. data/lib/ruby_smb/smb2/file.rb +103 -25
  105. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  106. data/lib/ruby_smb/smb2/packet.rb +2 -0
  107. data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
  108. data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
  109. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  110. data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
  111. data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
  112. data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
  113. data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
  114. data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
  115. data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
  116. data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
  117. data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
  118. data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
  119. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -17
  120. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +52 -5
  121. data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
  122. data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
  123. data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
  124. data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
  125. data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
  126. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
  127. data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
  128. data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
  129. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  130. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +93 -10
  131. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +10 -22
  132. data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
  133. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
  134. data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
  135. data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
  136. data/lib/ruby_smb/smb2/pipe.rb +86 -12
  137. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  138. data/lib/ruby_smb/smb2/tree.rb +65 -21
  139. data/lib/ruby_smb/version.rb +1 -1
  140. data/ruby_smb.gemspec +5 -3
  141. data/spec/lib/ruby_smb/client_spec.rb +1612 -108
  142. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  143. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  144. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  145. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
  146. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  147. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
  148. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  149. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  150. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  151. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  152. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
  153. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  154. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  155. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  156. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  157. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  158. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
  159. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  160. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
  161. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  162. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  163. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
  164. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  165. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
  166. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  167. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +2 -2
  168. data/spec/lib/ruby_smb/error_spec.rb +59 -0
  169. data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
  170. data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
  171. data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
  172. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  173. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  174. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  175. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  176. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
  177. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
  178. data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
  179. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
  180. data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
  181. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  182. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  183. data/spec/lib/ruby_smb/smb2/file_spec.rb +323 -6
  184. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  185. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  186. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +78 -0
  187. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  188. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  189. data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
  190. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  191. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  192. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -22
  193. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +286 -149
  194. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  195. data/spec/lib/ruby_smb/smb2/tree_spec.rb +261 -2
  196. metadata +191 -83
  197. metadata.gz.sig +0 -0
  198. data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
  199. data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
  200. data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RubySMB::SMB1::Packet::EmptyPacket do
4
+ subject(:packet) { described_class.new }
5
+
6
+ describe '#smb_header' do
7
+ subject(:header) { packet.smb_header }
8
+
9
+ it 'is a standard SMB Header' do
10
+ expect(header).to be_a RubySMB::SMB1::SMBHeader
11
+ end
12
+ end
13
+
14
+ describe '#parameter_block' do
15
+ subject(:parameter_block) { packet.parameter_block }
16
+
17
+ it 'is a standard ParameterBlock' do
18
+ expect(parameter_block).to be_a RubySMB::SMB1::ParameterBlock
19
+ end
20
+
21
+ it 'should be empty' do
22
+ expect(parameter_block.to_binary_s).to eq "\x00"
23
+ end
24
+ end
25
+
26
+ describe '#data_block' do
27
+ subject(:data_block) { packet.data_block }
28
+
29
+ it 'is a standard DataBlock' do
30
+ expect(data_block).to be_a RubySMB::SMB1::DataBlock
31
+ end
32
+
33
+ it 'should be empty' do
34
+ expect(data_block.to_binary_s).to eq "\x00\x00"
35
+ end
36
+ end
37
+
38
+ describe '#valid?' do
39
+ before :example do
40
+ packet.original_command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
41
+ packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
42
+ end
43
+
44
+ it 'returns true if the packet protocol ID and header command are valid' do
45
+ expect(packet).to be_valid
46
+ end
47
+
48
+ it 'returns false if the packet protocol ID is wrong' do
49
+ packet.smb_header.protocol = RubySMB::SMB2::SMB2_PROTOCOL_ID
50
+ expect(packet).to_not be_valid
51
+ end
52
+
53
+ it 'returns false if the packet header command is wrong' do
54
+ packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
55
+ expect(packet).to_not be_valid
56
+ end
57
+
58
+ it 'returns false if the packet parameter block size is not 0' do
59
+ packet.parameter_block.word_count = 10
60
+ expect(packet).to_not be_valid
61
+ end
62
+
63
+ it 'returns false if the packet data block size is not 0' do
64
+ packet.data_block.byte_count = 10
65
+ expect(packet).to_not be_valid
66
+ end
67
+ end
68
+ end
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyRequest do
10
10
  expect(header).to be_a RubySMB::SMB1::SMBHeader
11
11
  end
12
12
 
13
- it 'should have the command set to SMB_COM_NEGOTIATE' do
14
- expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
13
+ it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
14
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
15
15
  end
16
16
 
17
17
  it 'should not have the response flag set' do
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupLegacyResponse do
10
10
  expect(header).to be_a RubySMB::SMB1::SMBHeader
11
11
  end
12
12
 
13
- it 'should have the command set to SMB_COM_NEGOTIATE' do
14
- expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
13
+ it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
14
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
15
15
  end
16
16
 
17
17
  it 'should have the response flag set' do
@@ -10,8 +10,8 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupRequest do
10
10
  expect(header).to be_a RubySMB::SMB1::SMBHeader
11
11
  end
12
12
 
13
- it 'should have the command set to SMB_COM_NEGOTIATE' do
14
- expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
13
+ it 'should have the command set to SMB_COM_SESSION_SETUP_ANDX' do
14
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
15
15
  end
16
16
 
17
17
  it 'should not have the response flag set' do
@@ -11,7 +11,7 @@ RSpec.describe RubySMB::SMB1::Packet::SessionSetupResponse do
11
11
  end
12
12
 
13
13
  it 'should have the command set to SMB_COM_NEGOTIATE' do
14
- expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
14
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP_ANDX
15
15
  end
16
16
 
17
17
  it 'should have the response flag set' do
@@ -80,6 +80,8 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
80
80
 
81
81
  let(:names_blob) { names_array.collect(&:to_binary_s).join('') }
82
82
 
83
+ let(:find_info) { FindFileFullDirectoryInfo.new }
84
+
83
85
  it 'returns an array of parsed FindFileFullDirectoryInfo structs' do
84
86
  packet.data_block.trans2_data.buffer = names_blob
85
87
  expect(packet.results(FindFileFullDirectoryInfo, unicode: false)).to eq names_array
@@ -87,7 +89,6 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
87
89
 
88
90
  it 'sets the FindFileFullDirectoryInfo unicode attribute when unicode argument is true' do
89
91
  packet.data_block.trans2_data.buffer = names1.to_binary_s
90
- find_info = FindFileFullDirectoryInfo.new
91
92
  allow(FindFileFullDirectoryInfo).to receive(:new).and_return find_info
92
93
  expect(find_info).to receive(:unicode=).with(true).once
93
94
  packet.results(FindFileFullDirectoryInfo, unicode: true)
@@ -95,10 +96,18 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindFirst2Response do
95
96
 
96
97
  it 'does not set the FindFileFullDirectoryInfo unicode attribute when unicode argument is false' do
97
98
  packet.data_block.trans2_data.buffer = names1.to_binary_s
98
- find_info = FindFileFullDirectoryInfo.new
99
99
  allow(FindFileFullDirectoryInfo).to receive(:new).and_return find_info
100
100
  expect(find_info).to receive(:unicode=).with(false).once
101
101
  packet.results(FindFileFullDirectoryInfo, unicode: false)
102
102
  end
103
+
104
+ context 'when the File Information is not a valid' do
105
+ it 'raises an InvalidPacket exception' do
106
+ packet.data_block.trans2_data.buffer = names1.to_binary_s
107
+ allow(FindFileFullDirectoryInfo).to receive(:new).and_return(find_info)
108
+ allow(find_info).to receive(:read).and_raise(IOError)
109
+ expect { packet.results(FindFileFullDirectoryInfo, unicode: false) }.to raise_error(RubySMB::Error::InvalidPacket)
110
+ end
111
+ end
103
112
  end
104
113
  end
@@ -78,6 +78,8 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindNext2Response do
78
78
 
79
79
  let(:names_blob) { names_array.collect(&:to_binary_s).join('') }
80
80
 
81
+ let(:find_info) { FindFileFullDirectoryInfo.new }
82
+
81
83
  it 'returns an array of parsed FindFileFullDirectoryInfo structs' do
82
84
  packet.data_block.trans2_data.buffer = names_blob
83
85
  expect(packet.results(FindFileFullDirectoryInfo, unicode: false)).to eq names_array
@@ -85,7 +87,6 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindNext2Response do
85
87
 
86
88
  it 'sets the FindFileFullDirectoryInfo unicode attribute when unicode argument is true' do
87
89
  packet.data_block.trans2_data.buffer = names1.to_binary_s
88
- find_info = FindFileFullDirectoryInfo.new
89
90
  allow(FindFileFullDirectoryInfo).to receive(:new).and_return find_info
90
91
  expect(find_info).to receive(:unicode=).with(true).once
91
92
  packet.results(FindFileFullDirectoryInfo, unicode: true)
@@ -93,10 +94,18 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::FindNext2Response do
93
94
 
94
95
  it 'does not set the FindFileFullDirectoryInfo unicode attribute when unicode argument is false' do
95
96
  packet.data_block.trans2_data.buffer = names1.to_binary_s
96
- find_info = FindFileFullDirectoryInfo.new
97
97
  allow(FindFileFullDirectoryInfo).to receive(:new).and_return find_info
98
98
  expect(find_info).to receive(:unicode=).with(false).once
99
99
  packet.results(FindFileFullDirectoryInfo, unicode: false)
100
100
  end
101
+
102
+ context 'when the File Information is not a valid' do
103
+ it 'raises an InvalidPacket exception' do
104
+ packet.data_block.trans2_data.buffer = names1.to_binary_s
105
+ allow(FindFileFullDirectoryInfo).to receive(:new).and_return(find_info)
106
+ allow(find_info).to receive(:read).and_raise(IOError)
107
+ expect { packet.results(FindFileFullDirectoryInfo, unicode: false) }.to raise_error(RubySMB::Error::InvalidPacket)
108
+ end
109
+ end
101
110
  end
102
111
  end
@@ -104,4 +104,44 @@ RSpec.describe RubySMB::SMB1::Packet::TreeConnectResponse do
104
104
  expect(file_response.guest_access_rights).to be_a RubySMB::SMB1::BitField::FileAccessMask
105
105
  end
106
106
  end
107
+
108
+ describe '#access_rights' do
109
+ it 'is a DirectoryAccessMask if the Tree is a directory' do
110
+ allow(packet).to receive(:is_directory?).and_return(true)
111
+ expect(packet.access_rights).to be_a RubySMB::SMB1::BitField::DirectoryAccessMask
112
+ end
113
+
114
+ it 'is a FileAccessMask if the Tree is not a directory' do
115
+ allow(packet).to receive(:is_directory?).and_return(false)
116
+ expect(packet.access_rights).to be_a RubySMB::SMB1::BitField::FileAccessMask
117
+ end
118
+
119
+ context 'when it is not a valid FileAccessMask' do
120
+ it 'raises an InvalidBitField exception' do
121
+ allow(packet).to receive(:is_directory?).and_return(false)
122
+ allow(RubySMB::SMB1::BitField::FileAccessMask).to receive(:read).and_raise(IOError)
123
+ expect { packet.access_rights }.to raise_error(RubySMB::Error::InvalidBitField)
124
+ end
125
+ end
126
+ end
127
+
128
+ describe '#guest_access_rights' do
129
+ it 'is a DirectoryAccessMask if the Tree is a directory' do
130
+ allow(packet).to receive(:is_directory?).and_return(true)
131
+ expect(packet.guest_access_rights).to be_a RubySMB::SMB1::BitField::DirectoryAccessMask
132
+ end
133
+
134
+ it 'is a FileAccessMask if the Tree is not a directory' do
135
+ allow(packet).to receive(:is_directory?).and_return(false)
136
+ expect(packet.guest_access_rights).to be_a RubySMB::SMB1::BitField::FileAccessMask
137
+ end
138
+
139
+ context 'when it is not a valid FileAccessMask' do
140
+ it 'raises an InvalidBitField exception' do
141
+ allow(packet).to receive(:is_directory?).and_return(false)
142
+ allow(RubySMB::SMB1::BitField::FileAccessMask).to receive(:read).and_raise(IOError)
143
+ expect { packet.guest_access_rights }.to raise_error(RubySMB::Error::InvalidBitField)
144
+ end
145
+ end
146
+ end
107
147
  end
@@ -1,15 +1,12 @@
1
1
  RSpec.describe RubySMB::SMB1::Pipe do
2
2
 
3
+ it { expect(described_class).to be < RubySMB::SMB1::File }
4
+
3
5
  let(:peek_nmpipe_response) {
4
6
  packet = RubySMB::SMB1::Packet::Trans::PeekNmpipeResponse.new
5
7
  packet.data_block.trans_parameters.read("\x10\x20\x00\x00\x03\x00")
6
8
  packet
7
9
  }
8
-
9
- describe RubySMB::SMB1::Pipe do
10
- it { expect(described_class).to be < RubySMB::SMB1::File }
11
- end
12
-
13
10
  let(:dispatcher) { RubySMB::Dispatcher::Socket.new(double('socket')) }
14
11
  let(:client) { RubySMB::Client.new(dispatcher, username: 'msfadmin', password: 'msfadmin') }
15
12
  let(:connect_response) {
@@ -37,6 +34,68 @@ RSpec.describe RubySMB::SMB1::Pipe do
37
34
  described_class.new(tree: tree, response: nt_create_andx_response, name: filename)
38
35
  }
39
36
 
37
+ describe '#peek' do
38
+ let(:request) { RubySMB::SMB1::Packet::Trans::PeekNmpipeRequest.new }
39
+ let(:raw_response) { double('Raw response') }
40
+ let(:response) { double('Response') }
41
+
42
+ before :example do
43
+ allow(RubySMB::SMB1::Packet::Trans::PeekNmpipeRequest).to receive(:new).and_return(request)
44
+ allow(client).to receive(:send_recv).and_return(raw_response)
45
+ allow(RubySMB::SMB1::Packet::Trans::PeekNmpipeResponse).to receive(:read).and_return(response)
46
+ allow(response).to receive(:valid?).and_return(true)
47
+ allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_SUCCESS)
48
+ end
49
+
50
+ it 'creates a PeekNmpipeRequest'do
51
+ expect(RubySMB::SMB1::Packet::Trans::PeekNmpipeRequest).to receive(:new)
52
+ pipe.peek
53
+ end
54
+
55
+ it 'sets the request #fid field' do
56
+ expect(request).to receive(:fid=).with(pipe.fid)
57
+ pipe.peek
58
+ end
59
+
60
+ it 'sets the request #max_data_count fieldto the peek_size argument' do
61
+ peek_size = 5
62
+ pipe.peek(peek_size: peek_size)
63
+ expect(request.parameter_block.max_data_count).to eq(peek_size)
64
+ end
65
+
66
+ it 'calls Tree #set_header_fields' do
67
+ expect(tree).to receive(:set_header_fields).with(request)
68
+ pipe.peek
69
+ end
70
+
71
+ it 'calls Client #send_recv' do
72
+ expect(client).to receive(:send_recv).with(request)
73
+ pipe.peek
74
+ end
75
+
76
+ it 'parses the response as a SMB1 PeekNmpipeResponse packet' do
77
+ expect(RubySMB::SMB1::Packet::Trans::PeekNmpipeResponse).to receive(:read).with(raw_response)
78
+ pipe.peek
79
+ end
80
+
81
+ it 'raises an InvalidPacket exception if the response is not valid' do
82
+ allow(response).to receive(:valid?).and_return(false)
83
+ smb_header = double('SMB Header')
84
+ allow(response).to receive(:smb_header).and_return(smb_header)
85
+ allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
86
+ expect { pipe.peek }.to raise_error(RubySMB::Error::InvalidPacket)
87
+ end
88
+
89
+ it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW' do
90
+ allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
91
+ expect { pipe.peek }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
92
+ end
93
+
94
+ it 'returns the expected response' do
95
+ expect(pipe.peek).to eq(response)
96
+ end
97
+ end
98
+
40
99
  describe '#peek_available' do
41
100
  it 'reads the correct number of bytes available' do
42
101
  allow(pipe).to receive(:peek) { peek_nmpipe_response }
@@ -62,202 +121,266 @@ RSpec.describe RubySMB::SMB1::Pipe do
62
121
  end
63
122
  end
64
123
 
65
- context 'with DCERPC' do
66
- describe '#net_share_enum_all' do
67
- let(:host) { '1.2.3.4' }
68
- let(:dcerpc_response) { RubySMB::Dcerpc::Response.new }
69
-
70
- before :example do
71
- allow(pipe).to receive(:bind)
72
- allow(pipe).to receive(:request).and_return(dcerpc_response)
73
- allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return([])
124
+ describe '#initialize' do
125
+ context 'when name is not provided' do
126
+ it 'raises an ArgumentError' do
127
+ expect {
128
+ described_class.new(tree: tree, response: nt_create_andx_response, name: nil)
129
+ }.to raise_error(ArgumentError)
74
130
  end
131
+ end
75
132
 
76
- it 'calls #bind with the expected arguments' do
77
- expect(pipe).to receive(:bind).with(endpoint: RubySMB::Dcerpc::Srvsvc)
78
- pipe.net_share_enum_all(host)
79
- end
133
+ it 'calls the superclass with the expected arguments' do
134
+ expect(pipe.tree).to eq(tree)
135
+ expect(pipe.name).to eq(filename)
136
+ expect(pipe.attributes).to eq(nt_create_andx_response.parameter_block.ext_file_attributes)
137
+ expect(pipe.fid).to eq(nt_create_andx_response.parameter_block.fid)
138
+ expect(pipe.last_access).to eq(nt_create_andx_response.parameter_block.last_access_time.to_datetime)
139
+ expect(pipe.last_change).to eq(nt_create_andx_response.parameter_block.last_change_time.to_datetime)
140
+ expect(pipe.last_write).to eq(nt_create_andx_response.parameter_block.last_write_time.to_datetime)
141
+ expect(pipe.size).to eq(nt_create_andx_response.parameter_block.end_of_file)
142
+ expect(pipe.size_on_disk).to eq(nt_create_andx_response.parameter_block.allocation_size)
143
+ end
80
144
 
81
- it 'calls #request with the expected arguments' do
82
- expect(pipe).to receive(:request).with(RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL, host: host)
83
- pipe.net_share_enum_all(host)
145
+ context 'with \'srvsvc\' filename' do
146
+ it 'extends Srvsvc class' do
147
+ pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'srvsvc')
148
+ expect(pipe.respond_to?(:net_share_enum_all)).to be true
84
149
  end
150
+ end
85
151
 
86
- it 'parse the response with NetShareEnumAll #parse_response method' do
87
- stub = 'ABCD'
88
- dcerpc_response.alloc_hint = stub.size
89
- dcerpc_response.stub = stub
90
- expect(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).with(stub)
91
- pipe.net_share_enum_all(host)
152
+ context 'with \'winreg\' filename' do
153
+ it 'extends Winreg class' do
154
+ pipe = described_class.new(tree: tree, response: nt_create_andx_response, name: 'winreg')
155
+ expect(pipe.respond_to?(:has_registry_key?)).to be true
92
156
  end
157
+ end
158
+ end
93
159
 
94
- it 'returns the remote shares' do
95
- shares = [
96
- ["C$", "DISK", "Default share"],
97
- ["Shared", "DISK", ""],
98
- ["IPC$", "IPC", "Remote IPC"],
99
- ["ADMIN$", "DISK", "Remote Admin"]
100
- ]
101
- output = [
102
- {:name=>"C$", :type=>"DISK", :comment=>"Default share"},
103
- {:name=>"Shared", :type=>"DISK", :comment=>""},
104
- {:name=>"IPC$", :type=>"IPC", :comment=>"Remote IPC"},
105
- {:name=>"ADMIN$", :type=>"DISK", :comment=>"Remote Admin"},
106
- ]
107
- allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return(shares)
108
- expect(pipe.net_share_enum_all(host)).to eq(output)
109
- end
160
+ describe '#dcerpc_request' do
161
+ let(:options) { { host: '1.2.3.4' } }
162
+ let(:stub_packet ) { RubySMB::Dcerpc::Winreg::OpenKeyRequest.new }
163
+ let(:dcerpc_request) { double('DCERPC Request') }
164
+ let(:request_stub) { double('Request stub') }
165
+ let(:binary_dcerpc_request) { double('Binary DCERPC Request') }
166
+ let(:trans_nmpipe_request) { double('TransactNmpipeRequest') }
167
+ let(:trans_data) { double('Trans data') }
168
+ let(:trans_nmpipe_raw_response) { double('Trans nmpipe raw response') }
169
+ let(:trans_nmpipe_response) { double('TransactNmpipeResponse') }
170
+ let(:raw_data) { double('Raw data') }
171
+ let(:dcerpc_response) { double('DCERPC Response') }
172
+ let(:result) { 'Result' }
173
+
174
+ before :example do
175
+ allow(RubySMB::Dcerpc::Request).to receive(:new).and_return(dcerpc_request)
176
+ allow(dcerpc_request).to receive_messages(
177
+ :stub => request_stub,
178
+ :to_binary_s => binary_dcerpc_request
179
+ )
180
+ allow(request_stub).to receive(:read)
181
+ allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to receive(:new).and_return(trans_nmpipe_request)
182
+ allow(tree).to receive(:set_header_fields)
183
+ allow(trans_nmpipe_request).to receive_message_chain(:data_block, :trans_data => trans_data)
184
+ allow(trans_nmpipe_request).to receive(:set_fid)
185
+ allow(trans_data).to receive(:write_data=)
186
+ allow(client).to receive(:send_recv).and_return(trans_nmpipe_raw_response)
187
+ allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(trans_nmpipe_response)
188
+ allow(trans_nmpipe_response).to receive_messages(
189
+ :valid? => true,
190
+ :status_code => WindowsError::NTStatus::STATUS_SUCCESS
191
+ )
192
+ allow(trans_nmpipe_response).to receive_message_chain(:data_block, :trans_data, :read_data, :to_binary_s => raw_data)
193
+ allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(dcerpc_response)
194
+ allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::RESPONSE)
195
+ allow(dcerpc_response).to receive(:stub).and_return(result)
110
196
  end
111
197
 
112
- describe '#bind' do
113
- let(:options) { { endpoint: RubySMB::Dcerpc::Srvsvc } }
114
- let(:bind_packet) { RubySMB::Dcerpc::Bind.new(options) }
115
- let(:bind_ack_packet) { RubySMB::Dcerpc::BindAck.new }
198
+ it 'creates a Request packet with the expected arguments' do
199
+ pipe.dcerpc_request(stub_packet, options)
200
+ expect(options).to eq( { host: '1.2.3.4', endpoint: 'Winreg' })
201
+ expect(RubySMB::Dcerpc::Request).to have_received(:new).with({ opnum: stub_packet.opnum }, options)
202
+ end
116
203
 
117
- before :example do
118
- allow(RubySMB::Dcerpc::Bind).to receive(:new).and_return(bind_packet)
119
- allow(pipe).to receive(:write)
120
- allow(pipe).to receive(:read)
121
- bind_ack_packet.p_result_list.n_results = 1
122
- bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::ACCEPTANCE
123
- allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(bind_ack_packet)
124
- end
204
+ it 'sets DCERPC request stub to the stub packet passed as argument' do
205
+ pipe.dcerpc_request(stub_packet, options)
206
+ expect(request_stub).to have_received(:read).with(stub_packet.to_binary_s)
207
+ end
125
208
 
126
- it 'creates a Bind packet' do
127
- expect(RubySMB::Dcerpc::Bind).to receive(:new).with(options).and_return(bind_packet)
128
- pipe.bind(options)
129
- end
209
+ it 'creates a Trans TransactNmpipeRequest packet' do
210
+ pipe.dcerpc_request(stub_packet, options)
211
+ expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to have_received(:new).with(options)
212
+ end
130
213
 
131
- it 'writes to the named pipe' do
132
- expect(pipe).to receive(:write).with(data: bind_packet.to_binary_s)
133
- pipe.bind(options)
134
- end
214
+ it 'calls Tree #set_header_fields' do
215
+ pipe.dcerpc_request(stub_packet, options)
216
+ expect(tree).to have_received(:set_header_fields).with(trans_nmpipe_request)
217
+ end
135
218
 
136
- it 'reads the socket' do
137
- expect(pipe).to receive(:read)
138
- pipe.bind(options)
219
+ it 'calls TransactNmpipeRequest #set_fid' do
220
+ pipe.dcerpc_request(stub_packet, options)
221
+ expect(trans_nmpipe_request).to have_received(:set_fid).with(pipe.fid)
222
+ end
223
+
224
+ it 'sets the expected #write_data request property' do
225
+ pipe.dcerpc_request(stub_packet, options)
226
+ expect(trans_data).to have_received(:write_data=).with(binary_dcerpc_request)
227
+ end
228
+
229
+ it 'sends the expected request' do
230
+ pipe.dcerpc_request(stub_packet, options)
231
+ expect(client).to have_received(:send_recv).with(trans_nmpipe_request)
232
+ end
233
+
234
+ it 'creates a Trans TransactNmpipeResponse packet from the response' do
235
+ pipe.dcerpc_request(stub_packet, options)
236
+ expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to have_received(:read).with(trans_nmpipe_raw_response)
237
+ end
238
+
239
+ context 'when the response is not a Trans packet' do
240
+ it 'raises an InvalidPacket exception' do
241
+ allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :protocol)
242
+ allow(trans_nmpipe_response).to receive_message_chain(:smb_header, :command)
243
+ allow(trans_nmpipe_response).to receive(:valid?).and_return(false)
244
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Error::InvalidPacket)
139
245
  end
246
+ end
140
247
 
141
- it 'creates a BindAck packet from the response' do
142
- raw_response = RubySMB::Dcerpc::BindAck.new.to_binary_s
143
- allow(pipe).to receive(:read).and_return(raw_response)
144
- expect(RubySMB::Dcerpc::BindAck).to receive(:read).with(raw_response).and_return(bind_ack_packet)
145
- pipe.bind(options)
248
+ context 'when the response status code is not STATUS_SUCCESS or STATUS_BUFFER_OVERFLOW' do
249
+ it 'raises an UnexpectedStatusCode exception' do
250
+ allow(trans_nmpipe_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_INVALID_HANDLE)
251
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
146
252
  end
253
+ end
147
254
 
148
- it 'raises the expected exception when an invalid packet is received' do
149
- allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_raise(IOError)
150
- expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
255
+ context 'when the response status code is STATUS_SUCCESS' do
256
+ it 'does not raise any exception' do
257
+ expect { pipe.dcerpc_request(stub_packet, options) }.not_to raise_error
151
258
  end
152
259
 
153
- it 'raises the expected exception when it is not a BindAck packet' do
154
- response = RubySMB::Dcerpc::Bind.new
155
- allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(response)
156
- expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
260
+ it 'creates a DCERPC Response packet from the response' do
261
+ pipe.dcerpc_request(stub_packet, options)
262
+ expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data)
157
263
  end
158
264
 
159
- it 'raises an exception when no result is returned' do
160
- bind_ack_packet.p_result_list.n_results = 0
161
- expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
265
+ context 'when an IOError occurs while parsing the DCERPC response' do
266
+ it 'raises an InvalidPacket exception' do
267
+ allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
268
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
269
+ end
162
270
  end
163
271
 
164
- it 'raises an exception when result is not ACCEPTANCE' do
165
- bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::USER_REJECTION
166
- expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
272
+ context 'when the response is not a DCERPC Response packet' do
273
+ it 'raises an InvalidPacket exception' do
274
+ allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
275
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
276
+ end
167
277
  end
168
278
 
169
- it 'returns the expected BindAck packet' do
170
- expect(pipe.bind(options)).to eq(bind_ack_packet)
279
+ it 'returns the expected stub data' do
280
+ expect(pipe.dcerpc_request(stub_packet, options)).to eq(result)
171
281
  end
172
282
  end
173
283
 
174
- describe '#request' do
175
- let(:options) { { host: '1.2.3.4' } }
176
- let(:opnum) { RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL }
177
- let(:req_packet) { RubySMB::Dcerpc::Request.new({ :opnum => opnum }, options) }
178
- let(:nmpipe_packet) { RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest.new(options) }
179
- let(:nmpipe_response) { RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse.new }
180
- let(:res_packet) { RubySMB::Dcerpc::Response.new }
181
-
284
+ context 'when the response status code is STATUS_BUFFER_OVERFLOW' do
285
+ let(:data_count) { 100 }
286
+ let(:added_raw_data) { double('Added raw data') }
182
287
  before :example do
183
- allow(RubySMB::Dcerpc::Request).to receive(:new).and_return(req_packet)
184
- allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to receive(:new).and_return(nmpipe_packet)
185
- allow(client).to receive(:send_recv)
186
- allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(nmpipe_response)
187
- allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(res_packet)
288
+ allow(trans_nmpipe_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW)
289
+ allow(trans_nmpipe_response).to receive_message_chain(:parameter_block, :data_count => data_count)
290
+ allow(pipe).to receive(:read).and_return(added_raw_data)
291
+ allow(raw_data).to receive(:<<)
292
+ allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :first_frag => 1)
293
+ allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 1)
188
294
  end
189
295
 
190
- it 'creates a Request packet' do
191
- expect(RubySMB::Dcerpc::Request).to receive(:new).and_return(req_packet)
192
- pipe.request(opnum, options)
296
+ it 'does not raise any exception' do
297
+ expect { pipe.dcerpc_request(stub_packet, options) }.not_to raise_error
193
298
  end
194
299
 
195
- it 'creates a Trans TransactNmpipeRequest packet' do
196
- expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to receive(:new).and_return(nmpipe_packet)
197
- pipe.request(opnum, options)
300
+ it 'reads the expected number of bytes and concatenate it the first response raw data' do
301
+ pipe.dcerpc_request(stub_packet, options)
302
+ expect(pipe).to have_received(:read).with(bytes: tree.client.max_buffer_size - data_count)
303
+ expect(raw_data).to have_received(:<<).with(added_raw_data)
198
304
  end
199
305
 
200
- it 'calls Tree #set_header_fields' do
201
- expect(tree).to receive(:set_header_fields).with(nmpipe_packet)
202
- pipe.request(opnum, options)
306
+ it 'creates a DCERPC Response packet from the updated raw data' do
307
+ pipe.dcerpc_request(stub_packet, options)
308
+ expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data)
203
309
  end
204
310
 
205
- it 'calls TransactNmpipeRequest #set_fid' do
206
- expect(nmpipe_packet).to receive(:set_fid).with(pipe.fid)
207
- pipe.request(opnum, options)
311
+ context 'when an IOError occurs while parsing the DCERPC response' do
312
+ it 'raises an InvalidPacket exception' do
313
+ allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
314
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
315
+ end
208
316
  end
209
317
 
210
- it 'sets the expected data on the request' do
211
- expect(client).to receive(:send_recv) do
212
- expect(nmpipe_packet.data_block.trans_data.write_data).to eq(req_packet.to_binary_s)
318
+ context 'when the response is not a DCERPC Response packet' do
319
+ it 'raises an InvalidPacket exception' do
320
+ allow(dcerpc_response).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
321
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
213
322
  end
214
- pipe.request(opnum, options)
215
323
  end
216
324
 
217
- it 'sends the expected request' do
218
- expect(client).to receive(:send_recv).with(nmpipe_packet)
219
- pipe.request(opnum, options)
325
+ context 'when the response is not the first fragment' do
326
+ it 'raises an InvalidPacket exception' do
327
+ allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :first_frag => 0)
328
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
329
+ end
220
330
  end
221
331
 
222
- it 'creates a Trans TransactNmpipeResponse packet from the response' do
223
- raw_response = double('Raw response')
224
- allow(client).to receive(:send_recv).and_return(raw_response)
225
- expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).with(raw_response).and_return(nmpipe_response)
226
- pipe.request(opnum, options)
227
- end
332
+ context 'when the response is the last fragment' do
333
+ it 'only reads the pipe once' do
334
+ pipe.dcerpc_request(stub_packet, options)
335
+ expect(RubySMB::Dcerpc::Response).to have_received(:read).once
336
+ end
228
337
 
229
- it 'raises the expected exception when it is not a Trans packet' do
230
- response = RubySMB::SMB1::Packet::Trans2::Response.new
231
- allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(response)
232
- expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Error::InvalidPacket)
338
+ it 'returns the expected stub data' do
339
+ expect(pipe.dcerpc_request(stub_packet, options)).to eq(result)
340
+ end
233
341
  end
234
342
 
235
- it 'raises the expected exception when the status code is not STATUS_SUCCESS' do
236
- nmpipe_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
237
- expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
238
- end
343
+ context 'when the response is not the last fragment' do
344
+ let(:raw_data2) { double('Raw data #2') }
345
+ let(:dcerpc_response2) { double('DCERPC Response #2') }
346
+ let(:result2) { 'Result #2' }
347
+ before :example do
348
+ allow(dcerpc_response).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 0)
349
+ allow(pipe).to receive(:read).with(bytes: tree.client.max_buffer_size).and_return(raw_data2)
350
+ allow(RubySMB::Dcerpc::Response).to receive(:read).with(raw_data2).and_return(dcerpc_response2)
351
+ allow(dcerpc_response2).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::RESPONSE)
352
+ allow(dcerpc_response2).to receive_message_chain(:pdu_header, :pfc_flags, :last_frag => 1)
353
+ allow(dcerpc_response2).to receive(:stub).and_return(result2)
354
+ end
239
355
 
240
- it 'creates a DCERPC Response packet from the response' do
241
- nmpipe_response.data_block.trans_data.read_data = "test"
242
- expect(RubySMB::Dcerpc::Response).to receive(:read).with(nmpipe_response.data_block.trans_data.read_data)
243
- pipe.request(opnum, options)
244
- end
356
+ it 'reads the expected number of bytes' do
357
+ pipe.dcerpc_request(stub_packet, options)
358
+ expect(pipe).to have_received(:read).with(bytes: tree.client.max_buffer_size)
359
+ end
245
360
 
246
- it 'raises the expected exception when an invalid packet is received' do
247
- allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
248
- expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
249
- end
361
+ it 'creates a DCERPC Response packet from the new raw data' do
362
+ pipe.dcerpc_request(stub_packet, options)
363
+ expect(RubySMB::Dcerpc::Response).to have_received(:read).with(raw_data2)
364
+ end
250
365
 
251
- it 'raises the expected exception when it is not a Response packet' do
252
- response = RubySMB::Dcerpc::Request.new
253
- allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(response)
254
- expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
255
- end
366
+ context 'when an IOError occurs while parsing the new DCERPC response' do
367
+ it 'raises an InvalidPacket exception' do
368
+ allow(RubySMB::Dcerpc::Response).to receive(:read).with(raw_data2).and_raise(IOError)
369
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
370
+ end
371
+ end
256
372
 
257
- it 'returns the expected DCERPC Response' do
258
- expect(pipe.request(opnum, options)).to eq(res_packet)
373
+ context 'when the new response is not a DCERPC Response packet' do
374
+ it 'raises an InvalidPacket exception' do
375
+ allow(dcerpc_response2).to receive_message_chain(:pdu_header, :ptype => RubySMB::Dcerpc::PTypes::FAULT)
376
+ expect { pipe.dcerpc_request(stub_packet, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
377
+ end
378
+ end
379
+
380
+ it 'returns the expected stub data' do
381
+ expect(pipe.dcerpc_request(stub_packet, options)).to eq(result)
382
+ end
259
383
  end
260
384
  end
261
385
  end
262
-
263
386
  end