ruby_smb 1.0.0 → 1.1.0

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 (171) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.travis.yml +4 -1
  4. data/README.md +35 -47
  5. data/examples/enum_registry_key.rb +28 -0
  6. data/examples/enum_registry_values.rb +30 -0
  7. data/examples/pipes.rb +2 -1
  8. data/examples/read_registry_key_value.rb +32 -0
  9. data/lib/ruby_smb/client/authentication.rb +43 -25
  10. data/lib/ruby_smb/client/echo.rb +20 -2
  11. data/lib/ruby_smb/client/negotiation.rb +27 -12
  12. data/lib/ruby_smb/client/tree_connect.rb +20 -14
  13. data/lib/ruby_smb/client/utils.rb +2 -2
  14. data/lib/ruby_smb/client/winreg.rb +46 -0
  15. data/lib/ruby_smb/client.rb +28 -4
  16. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  17. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  18. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  19. data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
  20. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  21. data/lib/ruby_smb/dcerpc/request.rb +28 -9
  22. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
  23. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  24. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  25. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  26. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  27. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  28. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  29. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  30. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  31. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  32. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  33. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  34. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  35. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  36. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  37. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
  38. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  39. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  40. data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
  41. data/lib/ruby_smb/dcerpc.rb +38 -0
  42. data/lib/ruby_smb/dispatcher/socket.rb +3 -1
  43. data/lib/ruby_smb/error.rb +40 -1
  44. data/lib/ruby_smb/generic_packet.rb +33 -4
  45. data/lib/ruby_smb/smb1/file.rb +67 -11
  46. data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
  47. data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
  48. data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
  49. data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
  50. data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
  51. data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
  52. data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
  53. data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
  54. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
  55. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
  56. data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
  57. data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
  58. data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
  59. data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
  60. data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
  61. data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
  62. data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
  63. data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
  64. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
  65. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -1
  66. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
  67. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
  68. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
  69. data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
  70. data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
  71. data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
  72. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
  73. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
  74. data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
  75. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
  76. data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
  77. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
  78. data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
  79. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
  80. data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
  81. data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
  82. data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
  83. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
  84. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
  85. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
  86. data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
  87. data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
  88. data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
  89. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +2 -5
  90. data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
  91. data/lib/ruby_smb/smb1/pipe.rb +86 -5
  92. data/lib/ruby_smb/smb1/tree.rb +40 -2
  93. data/lib/ruby_smb/smb2/file.rb +97 -1
  94. data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
  95. data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
  96. data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
  97. data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
  98. data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
  99. data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
  100. data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
  101. data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
  102. data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
  103. data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
  104. data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
  105. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +2 -5
  106. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
  107. data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
  108. data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
  109. data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
  110. data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
  111. data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
  112. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
  113. data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
  114. data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
  115. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +2 -5
  116. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
  117. data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
  118. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
  119. data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
  120. data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
  121. data/lib/ruby_smb/smb2/pipe.rb +98 -11
  122. data/lib/ruby_smb/smb2/tree.rb +44 -6
  123. data/lib/ruby_smb/version.rb +1 -1
  124. data/lib/ruby_smb.rb +0 -1
  125. data/ruby_smb.gemspec +3 -3
  126. data/spec/lib/ruby_smb/client_spec.rb +271 -11
  127. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  128. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  129. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
  130. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  131. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
  132. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  133. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  134. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  135. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  136. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
  137. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  138. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  139. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  140. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  141. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  142. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
  143. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  144. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
  145. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  146. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  147. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
  148. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  149. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
  150. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  151. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +3 -1
  152. data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
  153. data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
  154. data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
  155. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
  156. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
  157. data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
  158. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
  159. data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
  160. data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
  161. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +78 -0
  162. data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
  163. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
  164. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +322 -145
  165. data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
  166. data.tar.gz.sig +0 -0
  167. metadata +70 -11
  168. metadata.gz.sig +0 -0
  169. data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
  170. data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
  171. data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
@@ -3,18 +3,29 @@ module RubySMB
3
3
  # Represents a pipe on the Remote server that we can perform
4
4
  # various I/O operations on.
5
5
  class Pipe < File
6
- require 'ruby_smb/smb2/dcerpc'
6
+ require 'ruby_smb/dcerpc'
7
7
 
8
- include RubySMB::SMB2::Dcerpc
8
+ include RubySMB::Dcerpc
9
9
 
10
10
  STATUS_CONNECTED = 0x00000003
11
11
  STATUS_CLOSING = 0x00000004
12
12
 
13
+ def initialize(tree:, response:, name:)
14
+ raise ArgumentError, 'No Name Provided' if name.nil?
15
+ case name
16
+ when 'srvsvc'
17
+ extend RubySMB::Dcerpc::Srvsvc
18
+ when 'winreg'
19
+ extend RubySMB::Dcerpc::Winreg
20
+ end
21
+ super(tree: tree, response: response, name: name)
22
+ end
23
+
13
24
  # Performs a peek operation on the named pipe
14
25
  #
15
26
  # @param peek_size [Integer] Amount of data to peek
16
27
  # @return [RubySMB::SMB2::Packet::IoctlResponse]
17
- # @raise [RubySMB::Error::InvalidPacket] if not a valid FSCTL_PIPE_PEEK response
28
+ # @raise [RubySMB::Error::InvalidPacket] if not a valid FIoctlResponse response
18
29
  # @raise [RubySMB::Error::UnexpectedStatusCode] If status is not STATUS_BUFFER_OVERFLOW or STATUS_SUCCESS
19
30
  def peek(peek_size: 0)
20
31
  packet = RubySMB::SMB2::Packet::IoctlRequest.new
@@ -24,19 +35,19 @@ module RubySMB
24
35
  packet.max_output_response = 16 + peek_size
25
36
  packet = set_header_fields(packet)
26
37
  raw_response = @tree.client.send_recv(packet)
27
- begin
28
- response = RubySMB::SMB2::Packet::IoctlResponse.read(raw_response)
29
- rescue IOError
30
- response = RubySMB::SMB2::Packet::ErrorPacket.read(raw_response)
38
+ response = RubySMB::SMB2::Packet::IoctlResponse.read(raw_response)
39
+ unless response.valid?
40
+ raise RubySMB::Error::InvalidPacket.new(
41
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
42
+ expected_cmd: RubySMB::SMB2::Packet::IoctlResponse::COMMAND,
43
+ received_proto: response.smb2_header.protocol,
44
+ received_cmd: response.smb2_header.command
45
+ )
31
46
  end
32
47
 
33
48
  unless response.status_code == WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW or response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
34
49
  raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
35
50
  end
36
-
37
- unless response.smb2_header.command == RubySMB::SMB2::Commands::IOCTL
38
- raise RubySMB::Error::InvalidPacket, 'Not an IoctlResponse packet'
39
- end
40
51
  response
41
52
  end
42
53
 
@@ -67,6 +78,82 @@ module RubySMB
67
78
  state == STATUS_CONNECTED
68
79
  end
69
80
 
81
+ def dcerpc_request(stub_packet, options={})
82
+ options.merge!(endpoint: stub_packet.class.name.split('::').at(-2))
83
+ dcerpc_request = RubySMB::Dcerpc::Request.new({ opnum: stub_packet.opnum }, options)
84
+ dcerpc_request.stub.read(stub_packet.to_binary_s)
85
+ ioctl_send_recv(dcerpc_request, options)
86
+ end
87
+
88
+ def ioctl_send_recv(action, options={})
89
+ request = set_header_fields(RubySMB::SMB2::Packet::IoctlRequest.new(options))
90
+ request.ctl_code = 0x0011C017
91
+ request.flags.is_fsctl = 0x00000001
92
+ request.buffer = action.to_binary_s
93
+
94
+ ioctl_raw_response = @tree.client.send_recv(request)
95
+ ioctl_response = RubySMB::SMB2::Packet::IoctlResponse.read(ioctl_raw_response)
96
+ unless ioctl_response.valid?
97
+ raise RubySMB::Error::InvalidPacket.new(
98
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
99
+ expected_cmd: RubySMB::SMB2::Packet::IoctlRequest::COMMAND,
100
+ received_proto: ioctl_response.smb2_header.protocol,
101
+ received_cmd: ioctl_response.smb2_header.command
102
+ )
103
+ end
104
+ # TODO: improve the handling of STATUS_PENDING responses
105
+ if ioctl_response.status_code == WindowsError::NTStatus::STATUS_PENDING
106
+ sleep 1
107
+ ioctl_raw_response = @tree.client.dispatcher.recv_packet
108
+ ioctl_response = RubySMB::SMB2::Packet::IoctlResponse.read(ioctl_raw_response)
109
+ unless ioctl_response.valid?
110
+ raise RubySMB::Error::InvalidPacket.new(
111
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
112
+ expected_cmd: RubySMB::SMB2::Packet::IoctlRequest::COMMAND,
113
+ received_proto: ioctl_response.smb2_header.protocol,
114
+ received_cmd: ioctl_response.smb2_header.command
115
+ )
116
+ end
117
+ elsif ![WindowsError::NTStatus::STATUS_SUCCESS,
118
+ WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW].include?(ioctl_response.status_code)
119
+ raise RubySMB::Error::UnexpectedStatusCode, ioctl_response.status_code.name
120
+ end
121
+
122
+ raw_data = ioctl_response.output_data
123
+ if ioctl_response.status_code == WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW
124
+ raw_data << read(bytes: @tree.client.max_buffer_size - ioctl_response.output_count)
125
+ dcerpc_response = dcerpc_response_from_raw_response(raw_data)
126
+ unless dcerpc_response.pdu_header.pfc_flags.first_frag == 1
127
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Not the first fragment"
128
+ end
129
+ stub_data = dcerpc_response.stub.to_s
130
+
131
+ loop do
132
+ break if dcerpc_response.pdu_header.pfc_flags.last_frag == 1
133
+ raw_data = read(bytes: @tree.client.max_buffer_size)
134
+ dcerpc_response = dcerpc_response_from_raw_response(raw_data)
135
+ stub_data << dcerpc_response.stub.to_s
136
+ end
137
+ stub_data
138
+ else
139
+ dcerpc_response = dcerpc_response_from_raw_response(raw_data)
140
+ dcerpc_response.stub.to_s
141
+ end
142
+ end
143
+
144
+
145
+ private
146
+
147
+ def dcerpc_response_from_raw_response(raw_data)
148
+ dcerpc_response = RubySMB::Dcerpc::Response.read(raw_data)
149
+ unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::RESPONSE
150
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Not a Response packet"
151
+ end
152
+ dcerpc_response
153
+ rescue IOError
154
+ raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
155
+ end
156
+
70
157
  end
71
158
  end
72
159
  end
@@ -34,11 +34,20 @@ module RubySMB
34
34
  # Disconnects this Tree from the current session
35
35
  #
36
36
  # @return [WindowsError::ErrorCode] the NTStatus sent back by the server.
37
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a TreeDisconnectResponse packet
37
38
  def disconnect!
38
39
  request = RubySMB::SMB2::Packet::TreeDisconnectRequest.new
39
40
  request = set_header_fields(request)
40
41
  raw_response = client.send_recv(request)
41
42
  response = RubySMB::SMB2::Packet::TreeDisconnectResponse.read(raw_response)
43
+ unless response.valid?
44
+ raise RubySMB::Error::InvalidPacket.new(
45
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
46
+ expected_cmd: RubySMB::SMB2::Packet::TreeDisconnectResponse::COMMAND,
47
+ received_proto: response.smb2_header.protocol,
48
+ received_cmd: response.smb2_header.command
49
+ )
50
+ end
42
51
  response.status_code
43
52
  end
44
53
 
@@ -89,9 +98,16 @@ module RubySMB
89
98
 
90
99
  raw_response = client.send_recv(create_request)
91
100
  response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
92
-
93
- if response.is_a?(RubySMB::SMB2::Packet::ErrorPacket)
94
- raise RubySMB::Error::RubySMBError
101
+ unless response.valid?
102
+ raise RubySMB::Error::InvalidPacket.new(
103
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
104
+ expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
105
+ received_proto: response.smb2_header.protocol,
106
+ received_cmd: response.smb2_header.command
107
+ )
108
+ end
109
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
110
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
95
111
  end
96
112
 
97
113
  case @share_type
@@ -102,7 +118,7 @@ module RubySMB
102
118
  # when 0x03
103
119
  # it's a printer!
104
120
  else
105
- raise RubySMB::Error::RubySMBError
121
+ raise RubySMB::Error::RubySMBError, 'Unsupported share type'
106
122
  end
107
123
  end
108
124
 
@@ -116,6 +132,7 @@ module RubySMB
116
132
  # @param pattern [String] search pattern
117
133
  # @param type [Class] file information class
118
134
  # @return [Array] array of directory structures
135
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a QueryDirectoryResponse packet
119
136
  def list(directory: nil, pattern: '*', type: RubySMB::Fscc::FileInformation::FileIdFullDirectoryInformation)
120
137
  create_response = open_directory(directory: directory)
121
138
  file_id = create_response.file_id
@@ -133,13 +150,20 @@ module RubySMB
133
150
  loop do
134
151
  response = client.send_recv(directory_request)
135
152
  directory_response = RubySMB::SMB2::Packet::QueryDirectoryResponse.read(response)
153
+ unless directory_response.valid?
154
+ raise RubySMB::Error::InvalidPacket.new(
155
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
156
+ expected_cmd: RubySMB::SMB2::Packet::QueryDirectoryResponse::COMMAND,
157
+ received_proto: directory_response.smb2_header.protocol,
158
+ received_cmd: directory_response.smb2_header.command
159
+ )
160
+ end
136
161
 
137
162
  status_code = directory_response.smb2_header.nt_status.to_nt_status
138
163
 
139
164
  break if status_code == WindowsError::NTStatus::STATUS_NO_MORE_FILES
140
165
 
141
166
  unless status_code == WindowsError::NTStatus::STATUS_SUCCESS
142
-
143
167
  raise RubySMB::Error::UnexpectedStatusCode, status_code.to_s
144
168
  end
145
169
 
@@ -162,6 +186,7 @@ module RubySMB
162
186
  # @param write [Boolean] whether to request write access
163
187
  # @param delete [Boolean] whether to request delete access
164
188
  # @return [RubySMB::SMB2::Packet::CreateResponse] the response packet returned from the server
189
+ # @raise [RubySMB::Error::InvalidPacket] if the response is not a CreateResponse packet
165
190
  def open_directory(directory: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
166
191
  impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE,
167
192
  read: true, write: false, delete: false)
@@ -169,7 +194,20 @@ module RubySMB
169
194
  create_request = open_directory_packet(directory: directory, disposition: disposition,
170
195
  impersonation: impersonation, read: read, write: write, delete: delete)
171
196
  raw_response = client.send_recv(create_request)
172
- RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
197
+ response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
198
+ unless response.valid?
199
+ raise RubySMB::Error::InvalidPacket.new(
200
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
201
+ expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
202
+ received_proto: response.smb2_header.protocol,
203
+ received_cmd: response.smb2_header.command
204
+ )
205
+ end
206
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
207
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
208
+ end
209
+
210
+ response
173
211
  end
174
212
 
175
213
  # Creates the Packet for the #open_directory method.
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '1.0.0'.freeze
2
+ VERSION = '1.1.0'.freeze
3
3
  end
data/lib/ruby_smb.rb CHANGED
@@ -15,7 +15,6 @@ module RubySMB
15
15
  require 'ruby_smb/field'
16
16
  require 'ruby_smb/nbss'
17
17
  require 'ruby_smb/fscc'
18
- require 'ruby_smb/dcerpc'
19
18
  require 'ruby_smb/generic_packet'
20
19
  require 'ruby_smb/dispatcher'
21
20
  require 'ruby_smb/version'
data/ruby_smb.gemspec CHANGED
@@ -6,8 +6,8 @@ require 'ruby_smb/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'ruby_smb'
8
8
  spec.version = RubySMB::VERSION
9
- spec.authors = ['David Maloney', 'James Lee', 'Dev Mohanty', 'Christophe De La Fuente']
10
- spec.email = ['DMaloney@rapid7.com', 'egypt@metasploit.com', 'dev_mohanty@rapid7.com', 'paristvinternet-github@yahoo.com']
9
+ spec.authors = ['Metasploit Hackers', 'David Maloney', 'James Lee', 'Dev Mohanty', 'Christophe De La Fuente']
10
+ spec.email = ['msfdev@metasploit.com']
11
11
  spec.summary = 'A pure Ruby implementation of the SMB Protocol Family'
12
12
  spec.description = ''
13
13
  spec.homepage = 'https://github.com/rapid7/ruby_smb'
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
26
26
  spec.platform = Gem::Platform::RUBY
27
27
  end
28
28
 
29
- spec.required_ruby_version = '>= 2.2.0'
29
+ spec.required_ruby_version = '>= 2.3.0'
30
30
 
31
31
  spec.add_development_dependency 'bundler'
32
32
  spec.add_development_dependency 'fivemat'
@@ -9,6 +9,7 @@ RSpec.describe RubySMB::Client do
9
9
  let(:smb1_client) { described_class.new(dispatcher, smb2: false, username: username, password: password) }
10
10
  let(:smb2_client) { described_class.new(dispatcher, smb1: false, username: username, password: password) }
11
11
  let(:empty_packet) { RubySMB::SMB1::Packet::EmptyPacket.new }
12
+ let(:error_packet) { RubySMB::SMB2::Packet::ErrorPacket.new }
12
13
 
13
14
  describe '#initialize' do
14
15
  it 'should raise an ArgumentError without a valid dispatcher' do
@@ -153,6 +154,94 @@ RSpec.describe RubySMB::Client do
153
154
  end
154
155
  end
155
156
 
157
+ describe '#logoff!' do
158
+ context 'with SMB1' do
159
+ let(:raw_response) { double('Raw response') }
160
+ let(:logoff_response) {
161
+ RubySMB::SMB1::Packet::LogoffResponse.new(smb_header: {:command => RubySMB::SMB1::Commands::SMB_COM_LOGOFF} )
162
+ }
163
+ before :example do
164
+ allow(smb1_client).to receive(:send_recv).and_return(raw_response)
165
+ allow(RubySMB::SMB1::Packet::LogoffResponse).to receive(:read).and_return(logoff_response)
166
+ allow(smb1_client).to receive(:wipe_state!)
167
+ end
168
+
169
+ it 'creates a LogoffRequest packet' do
170
+ expect(RubySMB::SMB1::Packet::LogoffRequest).to receive(:new).and_call_original
171
+ smb1_client.logoff!
172
+ end
173
+
174
+ it 'calls #send_recv' do
175
+ expect(smb1_client).to receive(:send_recv)
176
+ smb1_client.logoff!
177
+ end
178
+
179
+ it 'reads the raw response as a LogoffResponse packet' do
180
+ expect(RubySMB::SMB1::Packet::LogoffResponse).to receive(:read).with(raw_response)
181
+ smb1_client.logoff!
182
+ end
183
+
184
+ it 'raise an InvalidPacket exception when the response is an empty packet' do
185
+ allow(RubySMB::SMB1::Packet::LogoffResponse).to receive(:read).and_return(RubySMB::SMB1::Packet::EmptyPacket.new)
186
+ expect {smb1_client.logoff!}.to raise_error(RubySMB::Error::InvalidPacket)
187
+ end
188
+
189
+ it 'raise an InvalidPacket exception when the response is not valid' do
190
+ allow(logoff_response).to receive(:valid?).and_return(false)
191
+ expect {smb1_client.logoff!}.to raise_error(RubySMB::Error::InvalidPacket)
192
+ end
193
+
194
+ it 'calls #wipe_state!' do
195
+ expect(smb1_client).to receive(:wipe_state!)
196
+ smb1_client.logoff!
197
+ end
198
+
199
+ it 'returns the expected status code' do
200
+ logoff_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_PENDING.value
201
+ allow(RubySMB::SMB1::Packet::LogoffResponse).to receive(:read).and_return(logoff_response)
202
+ expect(smb1_client.logoff!).to eq(WindowsError::NTStatus::STATUS_PENDING)
203
+ end
204
+ end
205
+
206
+ context 'with SMB2' do
207
+ let(:raw_response) { double('Raw response') }
208
+ let(:logoff_response) {
209
+ RubySMB::SMB2::Packet::LogoffResponse.new(smb_header: {:command => RubySMB::SMB2::Commands::LOGOFF} )
210
+ }
211
+ before :example do
212
+ allow(smb2_client).to receive(:send_recv).and_return(raw_response)
213
+ allow(RubySMB::SMB2::Packet::LogoffResponse).to receive(:read).and_return(logoff_response)
214
+ allow(smb2_client).to receive(:wipe_state!)
215
+ end
216
+
217
+ it 'creates a LogoffRequest packet' do
218
+ expect(RubySMB::SMB2::Packet::LogoffRequest).to receive(:new).and_call_original
219
+ smb2_client.logoff!
220
+ end
221
+
222
+ it 'calls #send_recv' do
223
+ expect(smb2_client).to receive(:send_recv)
224
+ smb2_client.logoff!
225
+ end
226
+
227
+ it 'reads the raw response as a LogoffResponse packet' do
228
+ expect(RubySMB::SMB2::Packet::LogoffResponse).to receive(:read).with(raw_response)
229
+ smb2_client.logoff!
230
+ end
231
+
232
+ it 'raise an InvalidPacket exception when the response is an error packet' do
233
+ allow(RubySMB::SMB2::Packet::LogoffResponse).to receive(:read).and_return(RubySMB::SMB2::Packet::ErrorPacket.new)
234
+ expect {smb2_client.logoff!}.to raise_error(RubySMB::Error::InvalidPacket)
235
+ end
236
+
237
+ it 'raise an InvalidPacket exception when the response is not a LOGOFF command' do
238
+ logoff_response.smb2_header.command = RubySMB::SMB2::Commands::ECHO
239
+ allow(RubySMB::SMB2::Packet::LogoffResponse).to receive(:read).and_return(logoff_response)
240
+ expect {smb2_client.logoff!}.to raise_error(RubySMB::Error::InvalidPacket)
241
+ end
242
+ end
243
+ end
244
+
156
245
  context 'NetBIOS Session Service' do
157
246
  describe '#session_request' do
158
247
  let(:session_header) { RubySMB::Nbss::SessionHeader.new }
@@ -197,6 +286,11 @@ RSpec.describe RubySMB::Client do
197
286
  allow(dispatcher).to receive(:recv_packet).and_return(negative_session_response.to_binary_s)
198
287
  expect { client.session_request }.to raise_error(RubySMB::Error::NetBiosSessionService)
199
288
  end
289
+
290
+ it 'raises an InvalidPacket exception when an error occurs while reading' do
291
+ allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_raise(IOError)
292
+ expect { client.session_request }.to raise_error(RubySMB::Error::InvalidPacket)
293
+ end
200
294
  end
201
295
 
202
296
  describe '#session_request_packet' do
@@ -332,10 +426,15 @@ RSpec.describe RubySMB::Client do
332
426
  expect(smb1_client.negotiate_response(smb1_extended_response_raw)).to eq smb1_extended_response
333
427
  end
334
428
 
335
- it 'raises an exception if the Response is invalid' do
429
+ it 'raises an exception if the response is not a SMB packet' do
336
430
  expect { smb1_client.negotiate_response(random_junk) }.to raise_error(RubySMB::Error::InvalidPacket)
337
431
  end
338
432
 
433
+ it 'raises an InvalidPacket error if the response is not a valid response' do
434
+ empty_packet.smb_header.command = RubySMB::SMB2::Commands::NEGOTIATE
435
+ expect { smb1_client.negotiate_response(empty_packet.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
436
+ end
437
+
339
438
  it 'considers the response invalid if it is not an actual Negotiate Response' do
340
439
  bogus_response = smb1_extended_response
341
440
  bogus_response.smb_header.command = 0xff
@@ -357,6 +456,12 @@ RSpec.describe RubySMB::Client do
357
456
  it 'raises an exception if the Response is invalid' do
358
457
  expect { smb2_client.negotiate_response(random_junk) }.to raise_error(RubySMB::Error::InvalidPacket)
359
458
  end
459
+
460
+ it 'considers the response invalid if it is not an actual Negotiate Response' do
461
+ bogus_response = smb2_response
462
+ bogus_response.smb2_header.command = RubySMB::SMB2::Commands::ECHO
463
+ expect { smb2_client.negotiate_response(bogus_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
464
+ end
360
465
  end
361
466
 
362
467
  context 'with SMB1 and SMB2 enabled' do
@@ -624,7 +729,7 @@ RSpec.describe RubySMB::Client do
624
729
  expect { smb1_client.smb1_ntlmssp_challenge_packet(response.to_binary_s) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
625
730
  end
626
731
 
627
- it 'raises an InvalidPacket if the Command field is wrong' do
732
+ it 'raise an InvalidPacket exception when the response is not valid' do
628
733
  expect { smb1_client.smb1_ntlmssp_challenge_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
629
734
  end
630
735
  end
@@ -645,7 +750,7 @@ RSpec.describe RubySMB::Client do
645
750
  expect(smb1_client.smb1_ntlmssp_final_packet(response.to_binary_s)).to eq response
646
751
  end
647
752
 
648
- it 'raises an InvalidPacket if the Command field is wrong' do
753
+ it 'raise an InvalidPacket exception when the response is not valid' do
649
754
  expect { smb1_client.smb1_ntlmssp_final_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
650
755
  end
651
756
  end
@@ -717,12 +822,7 @@ RSpec.describe RubySMB::Client do
717
822
  expect(smb1_client.smb1_anonymous_auth_response(anonymous_response.to_binary_s)).to eq anonymous_response
718
823
  end
719
824
 
720
- it 'returns an empty packet if the raw data is not a valid response' do
721
- empty_packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
722
- expect(smb1_client.smb1_anonymous_auth_response(empty_packet.to_binary_s)).to eq empty_packet
723
- end
724
-
725
- it 'raises an InvalidPacket error if the command is wrong' do
825
+ it 'raise an InvalidPacket exception when the response is not valid' do
726
826
  anonymous_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
727
827
  expect { smb1_client.smb1_anonymous_auth_response(anonymous_response.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
728
828
  end
@@ -829,7 +929,7 @@ RSpec.describe RubySMB::Client do
829
929
  expect { smb2_client.smb2_ntlmssp_challenge_packet(response.to_binary_s) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
830
930
  end
831
931
 
832
- it 'raises an InvalidPacket if the Command field is wrong' do
932
+ it 'raise an InvalidPacket exception when the response is not valid' do
833
933
  expect { smb2_client.smb2_ntlmssp_challenge_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
834
934
  end
835
935
  end
@@ -888,7 +988,7 @@ RSpec.describe RubySMB::Client do
888
988
  expect(smb2_client.smb2_ntlmssp_final_packet(response.to_binary_s)).to eq response
889
989
  end
890
990
 
891
- it 'raises an InvalidPacket if the Command field is wrong' do
991
+ it 'raise an InvalidPacket exception when the response is not valid' do
892
992
  expect { smb2_client.smb2_ntlmssp_final_packet(wrong_command.to_binary_s) }.to raise_error(RubySMB::Error::InvalidPacket)
893
993
  end
894
994
  end
@@ -1199,6 +1299,12 @@ RSpec.describe RubySMB::Client do
1199
1299
  expect(smb1_client).to receive(:send_recv).and_return(echo_response.to_binary_s)
1200
1300
  expect(smb1_client.echo).to eq WindowsError::NTStatus::STATUS_ABANDONED
1201
1301
  end
1302
+
1303
+ it 'raise an InvalidPacket exception when the response is not valid' do
1304
+ echo_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_SESSION_SETUP
1305
+ allow(smb1_client).to receive(:send_recv).and_return(echo_response.to_binary_s)
1306
+ expect { smb1_client.echo }.to raise_error(RubySMB::Error::InvalidPacket)
1307
+ end
1202
1308
  end
1203
1309
 
1204
1310
  context 'with SMB2' do
@@ -1210,8 +1316,162 @@ RSpec.describe RubySMB::Client do
1210
1316
  expect(smb2_client).to receive(:send_recv).with(echo_request).and_return(echo_response.to_binary_s)
1211
1317
  expect(smb2_client.smb2_echo).to eq echo_response
1212
1318
  end
1319
+
1320
+ it 'raise an InvalidPacket exception when the response is not valid' do
1321
+ echo_response.smb2_header.command = RubySMB::SMB2::Commands::SESSION_SETUP
1322
+ allow(smb2_client).to receive(:send_recv).and_return(echo_response.to_binary_s)
1323
+ expect { smb2_client.smb2_echo }.to raise_error(RubySMB::Error::InvalidPacket)
1324
+ end
1213
1325
  end
1214
1326
  end
1215
1327
 
1328
+ context 'Winreg' do
1329
+ describe '#connect_to_winreg' do
1330
+ let(:host) { '1.2.3.4' }
1331
+ let(:share) { "\\\\#{host}\\IPC$" }
1332
+ let(:ipc_tree) { double('IPC$ tree') }
1333
+ let(:named_pipe) { double('Named pipe') }
1334
+ before :example do
1335
+ allow(ipc_tree).to receive_messages(
1336
+ :share => share,
1337
+ :open_file => named_pipe
1338
+ )
1339
+ allow(client).to receive(:tree_connect).and_return(ipc_tree)
1340
+ end
1341
+
1342
+ context 'when the client is already connected to the IPC$ share' do
1343
+ before :example do
1344
+ client.tree_connects << ipc_tree
1345
+ allow(ipc_tree).to receive(:share).and_return(share)
1346
+ end
1347
+
1348
+ it 'does not connect to the already connected tree' do
1349
+ client.connect_to_winreg(host)
1350
+ expect(client).to_not have_received(:tree_connect)
1351
+ end
1352
+ end
1353
+
1354
+ it 'calls #tree_connect' do
1355
+ client.connect_to_winreg(host)
1356
+ expect(client).to have_received(:tree_connect).with(share)
1357
+ end
1358
+
1359
+ it 'open \'winreg\' file on the IPC$ Tree' do
1360
+ client.connect_to_winreg(host)
1361
+ expect(ipc_tree).to have_received(:open_file).with(filename: "winreg", write: true, read: true)
1362
+ end
1363
+
1364
+ it 'returns the expected opened named pipe' do
1365
+ expect(client.connect_to_winreg(host)).to eq(named_pipe)
1366
+ end
1367
+
1368
+ context 'when a block is given' do
1369
+ before :example do
1370
+ allow(named_pipe).to receive(:close)
1371
+ end
1372
+
1373
+ it 'yields the expected named_pipe' do
1374
+ client.connect_to_winreg(host) do |np|
1375
+ expect(np).to eq(named_pipe)
1376
+ end
1377
+ end
1378
+
1379
+ it 'closes the named pipe' do
1380
+ client.connect_to_winreg(host) { |np| }
1381
+ expect(named_pipe).to have_received(:close)
1382
+ end
1383
+
1384
+ it 'returns the block return value' do
1385
+ result = double('Result')
1386
+ expect(client.connect_to_winreg(host) { |np| result }).to eq(result)
1387
+ end
1388
+ end
1389
+ end
1390
+
1391
+ describe '#has_registry_key?' do
1392
+ let(:host) { '1.2.3.4' }
1393
+ let(:key) { 'HKLM\\Registry\\Key' }
1394
+ let(:named_pipe) { double('Named pipe') }
1395
+ let(:result) { double('Result') }
1396
+ before :example do
1397
+ allow(client).to receive(:connect_to_winreg).and_yield(named_pipe)
1398
+ allow(named_pipe).to receive(:has_registry_key?).and_return(result)
1399
+ end
1400
+
1401
+ it 'calls #connect_to_winreg to wrap the main logic around' do
1402
+ client.has_registry_key?(host, key)
1403
+ expect(client).to have_received(:connect_to_winreg).with(host)
1404
+ end
1405
+
1406
+ it 'calls Pipe #has_registry_key?' do
1407
+ client.has_registry_key?(host, key)
1408
+ expect(named_pipe).to have_received(:has_registry_key?).with(key)
1409
+ end
1410
+ end
1411
+
1412
+ describe '#read_registry_key_value' do
1413
+ let(:host) { '1.2.3.4' }
1414
+ let(:key) { 'HKLM\\Registry\\Key' }
1415
+ let(:value_name) { 'Value' }
1416
+ let(:named_pipe) { double('Named pipe') }
1417
+ let(:result) { double('Result') }
1418
+ before :example do
1419
+ allow(client).to receive(:connect_to_winreg).and_yield(named_pipe)
1420
+ allow(named_pipe).to receive(:read_registry_key_value).and_return(result)
1421
+ end
1422
+
1423
+ it 'calls #connect_to_winreg to wrap the main logic around' do
1424
+ client.read_registry_key_value(host, key, value_name)
1425
+ expect(client).to have_received(:connect_to_winreg).with(host)
1426
+ end
1427
+
1428
+ it 'calls Pipe #read_registry_key_value' do
1429
+ client.read_registry_key_value(host, key, value_name)
1430
+ expect(named_pipe).to have_received(:read_registry_key_value).with(key, value_name)
1431
+ end
1432
+ end
1433
+
1434
+ describe '#enum_registry_key' do
1435
+ let(:host) { '1.2.3.4' }
1436
+ let(:key) { 'HKLM\\Registry\\Key' }
1437
+ let(:named_pipe) { double('Named pipe') }
1438
+ let(:result) { double('Result') }
1439
+ before :example do
1440
+ allow(client).to receive(:connect_to_winreg).and_yield(named_pipe)
1441
+ allow(named_pipe).to receive(:enum_registry_key).and_return(result)
1442
+ end
1443
+
1444
+ it 'calls #connect_to_winreg to wrap the main logic around' do
1445
+ client.enum_registry_key(host, key)
1446
+ expect(client).to have_received(:connect_to_winreg).with(host)
1447
+ end
1448
+
1449
+ it 'calls Pipe #enum_registry_key' do
1450
+ client.enum_registry_key(host, key)
1451
+ expect(named_pipe).to have_received(:enum_registry_key).with(key)
1452
+ end
1453
+ end
1454
+
1455
+ describe '#enum_registry_values' do
1456
+ let(:host) { '1.2.3.4' }
1457
+ let(:key) { 'HKLM\\Registry\\Key' }
1458
+ let(:named_pipe) { double('Named pipe') }
1459
+ let(:result) { double('Result') }
1460
+ before :example do
1461
+ allow(client).to receive(:connect_to_winreg).and_yield(named_pipe)
1462
+ allow(named_pipe).to receive(:enum_registry_values).and_return(result)
1463
+ end
1464
+
1465
+ it 'calls #connect_to_winreg to wrap the main logic around' do
1466
+ client.enum_registry_values(host, key)
1467
+ expect(client).to have_received(:connect_to_winreg).with(host)
1468
+ end
1469
+
1470
+ it 'calls Pipe #enum_registry_values' do
1471
+ client.enum_registry_values(host, key)
1472
+ expect(named_pipe).to have_received(:enum_registry_values).with(key)
1473
+ end
1474
+ end
1475
+ end
1216
1476
  end
1217
1477
 
@@ -31,7 +31,7 @@ RSpec.describe RubySMB::Dcerpc::BindAck do
31
31
  end
32
32
 
33
33
  it 'should have a default value of 0xFFFF' do
34
- expect(packet.max_xmit_frag).to eq 0xFFFF
34
+ expect(packet.max_xmit_frag).to eq RubySMB::Dcerpc::MAX_XMIT_FRAG
35
35
  end
36
36
  end
37
37
 
@@ -41,7 +41,7 @@ RSpec.describe RubySMB::Dcerpc::BindAck do
41
41
  end
42
42
 
43
43
  it 'should have a default value of 0xFFFF' do
44
- expect(packet.max_recv_frag).to eq 0xFFFF
44
+ expect(packet.max_recv_frag).to eq RubySMB::Dcerpc::MAX_RECV_FRAG
45
45
  end
46
46
  end
47
47