ruby_smb 0.0.8 → 0.0.9

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 (60) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/examples/tree_connect.rb +27 -0
  5. data/lib/ruby_smb/client.rb +25 -2
  6. data/lib/ruby_smb/client/authentication.rb +5 -6
  7. data/lib/ruby_smb/client/negotiation.rb +2 -3
  8. data/lib/ruby_smb/client/signing.rb +6 -2
  9. data/lib/ruby_smb/client/tree_connect.rb +86 -0
  10. data/lib/ruby_smb/generic_packet.rb +1 -1
  11. data/lib/ruby_smb/smb1.rb +1 -1
  12. data/lib/ruby_smb/smb1/bit_field.rb +4 -0
  13. data/lib/ruby_smb/smb1/bit_field/directory_access_mask.rb +38 -0
  14. data/lib/ruby_smb/smb1/bit_field/file_access_mask.rb +38 -0
  15. data/lib/ruby_smb/smb1/bit_field/optional_support.rb +19 -0
  16. data/lib/ruby_smb/smb1/bit_field/tree_connect_flags.rb +18 -0
  17. data/lib/ruby_smb/smb1/commands.rb +2 -0
  18. data/lib/ruby_smb/smb1/packet.rb +4 -0
  19. data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +34 -0
  20. data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +74 -0
  21. data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +29 -0
  22. data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +30 -0
  23. data/lib/ruby_smb/smb1/tree.rb +55 -0
  24. data/lib/ruby_smb/smb2.rb +1 -0
  25. data/lib/ruby_smb/smb2/bit_field.rb +4 -0
  26. data/lib/ruby_smb/smb2/bit_field/directory_access_mask.rb +38 -0
  27. data/lib/ruby_smb/smb2/bit_field/file_access_mask.rb +38 -0
  28. data/lib/ruby_smb/smb2/bit_field/share_capabailities.rb +21 -0
  29. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +75 -0
  30. data/lib/ruby_smb/smb2/packet.rb +5 -0
  31. data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -0
  32. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +27 -0
  33. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +50 -0
  34. data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +21 -0
  35. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +22 -0
  36. data/lib/ruby_smb/smb2/smb2_header.rb +3 -3
  37. data/lib/ruby_smb/smb2/tree.rb +51 -0
  38. data/lib/ruby_smb/version.rb +1 -1
  39. data/ruby_smb.gemspec +1 -1
  40. data/spec/lib/ruby_smb/client_spec.rb +114 -4
  41. data/spec/lib/ruby_smb/smb1/bit_field/directory_access_mask_spec.rb +190 -0
  42. data/spec/lib/ruby_smb/smb1/bit_field/file_access_mask_spec.rb +190 -0
  43. data/spec/lib/ruby_smb/smb1/bit_field/optional_support_spec.rb +52 -0
  44. data/spec/lib/ruby_smb/smb1/bit_field/tree_connect_flags_spec.rb +37 -0
  45. data/spec/lib/ruby_smb/smb1/packet/tree_connect_request_spec.rb +53 -0
  46. data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +86 -0
  47. data/spec/lib/ruby_smb/smb1/packet/tree_disconnect_request_spec.rb +40 -0
  48. data/spec/lib/ruby_smb/smb1/packet/tree_disconnect_response_spec.rb +40 -0
  49. data/spec/lib/ruby_smb/smb1/tree_spec.rb +55 -0
  50. data/spec/lib/ruby_smb/smb2/bit_field/directory_access_mask_spec.rb +190 -0
  51. data/spec/lib/ruby_smb/smb2/bit_field/file_access_mask_spec.rb +190 -0
  52. data/spec/lib/ruby_smb/smb2/bit_field/share_capabilities_spec.rb +54 -0
  53. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +184 -0
  54. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +49 -0
  55. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +57 -0
  56. data/spec/lib/ruby_smb/smb2/packet/tree_disconnect_request_spec.rb +30 -0
  57. data/spec/lib/ruby_smb/smb2/packet/tree_disconnect_response_spec.rb +30 -0
  58. data/spec/lib/ruby_smb/smb2/tree_spec.rb +54 -0
  59. metadata +63 -6
  60. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 203527ee7c807b85b3af96aea81bdc9f543b5f16
4
- data.tar.gz: f80aa766405b6b813a5ac9a65aca3778d24f20a0
3
+ metadata.gz: 4447c748fa5ae3b4bade1f7da2f90b05e98f90e3
4
+ data.tar.gz: 0a077bd853a42f08210f527475965459347570a0
5
5
  SHA512:
6
- metadata.gz: 79add85ae366057d7c77cafa684c6c3d6e842777bbf161d768dd8e206a344f712fc3cf5684a0d625c77162e1a07f8dcb7e43bf92292b9fedd0bfd8169a873375
7
- data.tar.gz: 5866aa5f7aed28b0dfa8b3c147434ebefe6a6e4964618ba7d4762349f5090e826c1461950ec79a53fc52074f75eb99abc8b6a488d9901f2701b537c28aec5601
6
+ metadata.gz: 0284a70fde3ac94578b232fb30cfd0a2a579947104a700371cd04f78b9b29ff295ac4f90423fbb280848fc35f1095b42c9f3caa0c229dbee02a1f8480466b28e
7
+ data.tar.gz: 94ba89646185e15f2c2a945849948287fb01734523c092fbe410f0e8d42d31b518c53eb2689192d64358fda5493fbf791d12e3cd0e3ce2102828f0345910ad13
checksums.yaml.gz.sig CHANGED
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # This example script is used for testing TreeConnect functionality
4
+ # It will attempt to connect to a specific share and then disconnect.
5
+ # Example usage: ruby tree_connect.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE
6
+ # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
7
+
8
+ require 'bundler/setup'
9
+ require 'ruby_smb'
10
+
11
+ address = ARGV[0]
12
+ username = ARGV[1]
13
+ password = ARGV[2]
14
+ share = ARGV[3]
15
+ path = "\\\\#{address}\\#{share}"
16
+
17
+ sock = TCPSocket.new address, 445
18
+ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
19
+
20
+ client = RubySMB::Client.new(dispatcher, smb1: true, smb2: true, username: username, password: password)
21
+ protocol = client.negotiate
22
+ status = client.authenticate
23
+
24
+ puts "#{protocol} : #{status}"
25
+
26
+ tree = client.smb2_tree_connect(path)
27
+ tree.disconnect!
@@ -6,10 +6,12 @@ module RubySMB
6
6
  require 'ruby_smb/client/negotiation'
7
7
  require 'ruby_smb/client/authentication'
8
8
  require 'ruby_smb/client/signing'
9
+ require 'ruby_smb/client/tree_connect'
9
10
 
10
11
  include RubySMB::Client::Negotiation
11
12
  include RubySMB::Client::Authentication
12
13
  include RubySMB::Client::Signing
14
+ include RubySMB::Client::TreeConnect
13
15
 
14
16
  # The Default SMB1 Dialect string used in an SMB1 Negotiate Request
15
17
  SMB1_DIALECT_SMB1_DEFAULT = "NT LM 0.12"
@@ -116,6 +118,20 @@ module RubySMB
116
118
  @smb2_message_id = 0
117
119
  end
118
120
 
121
+ # Sets the message id field in an SMB2 packet's
122
+ # header to the one tracked by the client. It then increments
123
+ # the counter on the client.
124
+ #
125
+ # @param packet [RubySMB::GenericPacket] the packet to set the message id for
126
+ # @return [RubySMB::GenericPacket] the modified packet
127
+ def increment_smb_message_id(packet)
128
+ if packet.smb2_header.message_id == 0 && self.smb2_message_id != 0
129
+ packet.smb2_header.message_id = self.smb2_message_id
130
+ self.smb2_message_id += 1
131
+ end
132
+ packet
133
+ end
134
+
119
135
  def login(username: self.username, password: self.password, domain: self.domain, local_workstation: self.local_workstation )
120
136
  @domain = domain
121
137
  @local_workstation = local_workstation
@@ -141,15 +157,22 @@ module RubySMB
141
157
  def send_recv(packet)
142
158
  case packet.packet_smb_version
143
159
  when 'SMB1'
160
+ if self.user_id
161
+ packet.smb_header.uid = self.user_id
162
+ end
144
163
  packet = smb1_sign(packet)
145
164
  when 'SMB2'
146
- packet = smb2_sign(packet)
165
+ packet = increment_smb_message_id(packet)
166
+ packet.smb2_header.session_id = self.session_id
167
+ unless packet.is_a?(RubySMB::SMB2::Packet::SessionSetupRequest)
168
+ packet = smb2_sign(packet)
169
+ end
147
170
  else
148
171
  packet = packet
149
172
  end
150
173
  dispatcher.send_packet(packet)
151
174
  raw_response = dispatcher.recv_packet
152
- if self.sequence_counter > 0
175
+ if self.signing_required && !self.session_key.empty?
153
176
  self.sequence_counter += 1
154
177
  end
155
178
  raw_response
@@ -136,12 +136,11 @@ module RubySMB
136
136
  response = smb2_ntlmssp_negotiate
137
137
  challenge_packet = smb2_ntlmssp_challenge_packet(response)
138
138
  session_id = challenge_packet.smb2_header.session_id
139
+ self.session_id = session_id
139
140
  challenge_message = smb2_type2_message(challenge_packet)
140
141
  raw = smb2_ntlmssp_authenticate(challenge_message, session_id)
141
142
  response = smb2_ntlmssp_final_packet(raw)
142
- response_code = response.status_code
143
- self.session_id = response.smb2_header.session_id if response_code.name == "STATUS_SUCCESS"
144
- response_code
143
+ response.status_code
145
144
  end
146
145
 
147
146
  # Takes the raw binary string and returns a {RubySMB::SMB2::Packet::SessionSetupResponse}
@@ -185,7 +184,9 @@ module RubySMB
185
184
  type1_message = ntlm_client.init_context
186
185
  packet = RubySMB::SMB2::Packet::SessionSetupRequest.new
187
186
  packet.set_type1_blob(type1_message.serialize)
188
- packet.smb2_header.message_id = 1 #self.smb2_message_id
187
+ # This Message ID should always be 1, but thanks to Multi-Protocol Negotiation
188
+ # the Message ID can be out of sync at this point so we re-synch it here.
189
+ packet.smb2_header.message_id = 1
189
190
  self.smb2_message_id = 2
190
191
  packet
191
192
  end
@@ -225,8 +226,6 @@ module RubySMB
225
226
  packet = RubySMB::SMB2::Packet::SessionSetupRequest.new
226
227
  packet.smb2_header.session_id = session_id
227
228
  packet.set_type3_blob(type3_message.serialize)
228
- packet.smb2_header.message_id = self.smb2_message_id
229
- self.smb2_message_id += 1
230
229
  packet
231
230
  end
232
231
 
@@ -1,3 +1,4 @@
1
+ require 'securerandom'
1
2
  module RubySMB
2
3
  class Client
3
4
  # This module holds all of the methods backing the {RubySMB::Client#negotiate} method
@@ -114,11 +115,9 @@ module RubySMB
114
115
  # @ return [RubySMB::SMB2::Packet::NegotiateRequest] a completed SMB2 Negotiate Request packet
115
116
  def smb2_negotiate_request
116
117
  packet = RubySMB::SMB2::Packet::NegotiateRequest.new
117
- packet.smb2_header.message_id = self.smb2_message_id
118
- # Increment the message id when doing SMB2
119
- self.smb2_message_id += 1
120
118
  packet.security_mode.signing_enabled = 1
121
119
  packet.add_dialect(SMB2_DIALECT_DEFAULT)
120
+ packet.client_guid = SecureRandom.random_bytes(16)
122
121
  packet
123
122
  end
124
123
  end
@@ -17,7 +17,9 @@ module RubySMB
17
17
  # @return [RubySMB::GenericPacket] the packet, signed if needed
18
18
  def smb1_sign(packet)
19
19
  if self.signing_required && !self.session_key.empty?
20
- packet.smb_header.security_features = self.sequence_counter
20
+ # Pack the Sequence counter into a int64le
21
+ packed_sequence_counter = [self.sequence_counter].pack('Q<')
22
+ packet.smb_header.security_features = packed_sequence_counter
21
23
  signature = OpenSSL::Digest::MD5.digest(self.session_key + packet.to_binary_s)[0,8]
22
24
  packet.smb_header.security_features = signature
23
25
  self.sequence_counter += 1
@@ -35,8 +37,10 @@ module RubySMB
35
37
  # @return [RubySMB::GenericPacket] the packet, signed if needed
36
38
  def smb2_sign(packet)
37
39
  if self.signing_required && !self.session_key.empty?
40
+ packet.smb2_header.flags.signed = 1
41
+ packet.smb2_header.signature = "\x00" * 16
38
42
  hmac = OpenSSL::HMAC.digest(OpenSSL::Digest::SHA256.new, self.session_key, packet.to_binary_s)
39
- packet.smb2_header.signature = hmac
43
+ packet.smb2_header.signature = hmac[0,16]
40
44
  packet
41
45
  else
42
46
  packet
@@ -0,0 +1,86 @@
1
+ module RubySMB
2
+ class Client
3
+
4
+ # This module contains all of the methods for a client to connect to a
5
+ # remote share or named pipe.
6
+ module TreeConnect
7
+
8
+ #
9
+ # SMB 1 Methods
10
+ #
11
+
12
+ # Sends a request to connect to a remote Tree and returns the
13
+ # {RubySMB::SMB1::Tree}
14
+ #
15
+ # @param share [String] the share path to connect to
16
+ # @return [RubySMB::SMB1::Tree] the connected Tree
17
+ def smb1_tree_connect(share)
18
+ request = RubySMB::SMB1::Packet::TreeConnectRequest.new
19
+ request.smb_header.tid = 65535
20
+ request.data_block.path = share
21
+ raw_response = send_recv(request)
22
+ begin
23
+ response = RubySMB::SMB1::Packet::TreeConnectResponse.read(raw_response)
24
+ rescue EOFError
25
+ response = RubySMB::SMB1::Packet::ErrorPacket.read(raw_response)
26
+ end
27
+ smb1_tree_from_response(share, response)
28
+ end
29
+
30
+ # Parses a Tree structure from a Tree Connect Response
31
+ #
32
+ # @param share [String] the share path to connect to
33
+ # @param response [RubySMB::SMB1::Packet::TreeConnectResponse] the response packet to parse into our Tree
34
+ # @return [RubySMB::SMB1::Tree]
35
+ def smb1_tree_from_response(share,response)
36
+ unless response.smb_header.command == RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
37
+ raise RubySMB::Error::InvalidPacket, "Not a TreeConnectResponse"
38
+ end
39
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
40
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
41
+ end
42
+ RubySMB::SMB1::Tree.new(client: self, share: share, response: response)
43
+ end
44
+
45
+ #
46
+ # SMB2 Methods
47
+ #
48
+
49
+ # Sends a request to connect to a remote Tree and returns the
50
+ # {RubySMB::SMB2::Tree}
51
+ #
52
+ # @param share [String] the share path to connect to
53
+ # @return [RubySMB::SMB2::Tree] the connected Tree
54
+ def smb2_tree_connect(share)
55
+ request = RubySMB::SMB2::Packet::TreeConnectRequest.new
56
+ request.smb2_header.tree_id = 65535
57
+ request.encode_path(share)
58
+ raw_response = send_recv(request)
59
+ begin
60
+ response = RubySMB::SMB2::Packet::TreeConnectResponse.read(raw_response)
61
+ rescue EOFError
62
+ response = RubySMB::SMB2::Packet::ErrorPacket.read(raw_response)
63
+ end
64
+ smb2_tree_from_response(share, response)
65
+ end
66
+
67
+ # Parses a Tree structure from a Tree Connect Response
68
+ #
69
+ # @param share [String] the share path to connect to
70
+ # @param response [RubySMB::SMB2::Packet::TreeConnectResponse] the response packet to parse into our Tree
71
+ # @return [RubySMB::SMB2::Tree]
72
+ def smb2_tree_from_response(share,response)
73
+ unless response.smb2_header.command == RubySMB::SMB2::Commands::TREE_CONNECT
74
+ raise RubySMB::Error::InvalidPacket, "Not a TreeConnectResponse"
75
+ end
76
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
77
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
78
+ end
79
+ RubySMB::SMB2::Tree.new(client: self, share: share, response: response)
80
+ end
81
+
82
+ end
83
+
84
+
85
+ end
86
+ end
@@ -161,7 +161,7 @@ module RubySMB
161
161
  def process_array_field(array_field, depth)
162
162
  array_field_str = ''
163
163
  array_field.each do |sub_field|
164
- fields = sub_field.class.fields.fields
164
+ fields = sub_field.class.fields.raw_fields
165
165
  sub_field_hashes = self.class.walk_fields(fields)
166
166
  sub_field_hashes.each do |sub_field_hash|
167
167
  name = sub_field_hash[:name]
data/lib/ruby_smb/smb1.rb CHANGED
@@ -12,5 +12,5 @@ module RubySMB::SMB1
12
12
  require 'ruby_smb/smb1/data_block'
13
13
  require 'ruby_smb/smb1/dialect'
14
14
  require 'ruby_smb/smb1/packet'
15
-
15
+ require 'ruby_smb/smb1/tree'
16
16
  end
@@ -5,6 +5,10 @@ module RubySMB
5
5
  require 'ruby_smb/smb1/bit_field/header_flags2'
6
6
  require 'ruby_smb/smb1/bit_field/security_mode'
7
7
  require 'ruby_smb/smb1/bit_field/capabilities'
8
+ require 'ruby_smb/smb1/bit_field/tree_connect_flags'
9
+ require 'ruby_smb/smb1/bit_field/optional_support'
10
+ require 'ruby_smb/smb1/bit_field/directory_access_mask'
11
+ require 'ruby_smb/smb1/bit_field/file_access_mask'
8
12
  end
9
13
  end
10
14
  end
@@ -0,0 +1,38 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # An Access Mask bit field used to describe the permissions on a Directory, as defined in
5
+ # [2.2.1.4.2 Directory_Access_Mask](https://msdn.microsoft.com/en-us/library/ff470234.aspx)
6
+ class DirectoryAccessMask < BinData::Record
7
+ endian :little
8
+ bit1 :read_attr, label: 'Read Attributes'
9
+ bit1 :delete_child, label: 'Delete Child'
10
+ bit1 :traverse, label: 'Traverse'
11
+ bit1 :write_ea, label: 'Write Extended Attributes'
12
+ bit1 :read_ea, label: 'Read Extended Attributes'
13
+ bit1 :add_subdir, label: 'Add Subdirectory'
14
+ bit1 :add_file, label: 'Add File'
15
+ bit1 :list, label: 'List Directory'
16
+ # byte boundary
17
+ bit7 :reserved, label: 'Reserved Space'
18
+ bit1 :write_attr, label: 'Write Attributes'
19
+
20
+ # byte boundary
21
+ bit3 :reserved2, label: 'Reserved Space'
22
+ bit1 :synchronize, label: 'Synchronize'
23
+ bit1 :write_owner, label: 'Write Owner'
24
+ bit1 :write_dac, label: 'Write DAC'
25
+ bit1 :read_control, label: 'Read Control'
26
+ bit1 :delete_access, label: 'Delete'
27
+ # byte boundary
28
+ bit1 :generic_read, label: 'Generic Read'
29
+ bit1 :generic_write, label: 'Generic Write'
30
+ bit1 :generic_execute, label: 'Generic Execute'
31
+ bit1 :generic_all, label: 'Generic All'
32
+ bit2 :reserved3
33
+ bit1 :maximum, label: 'Maximum Allowed'
34
+ bit1 :system_security, label: 'System Security'
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,38 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # An Access Mask bit field used to describe the permissions on a File, Printer, or named Pipe. As defined in
5
+ # [2.2.1.4.1 File_Pipe_Printer_Access_Mask](https://msdn.microsoft.com/en-us/library/ff469915.aspx)
6
+ class FileAccessMask < BinData::Record
7
+ endian :little
8
+ bit1 :read_attr, label: 'Read Attributes'
9
+ bit1 :delete_child, label: 'Delete Child'
10
+ bit1 :execute, label: 'Traverse'
11
+ bit1 :write_ea, label: 'Write Extended Attributes'
12
+ bit1 :read_ea, label: 'Read Extended Attributes'
13
+ bit1 :append_data, label: 'Append Data'
14
+ bit1 :write_data, label: 'Write Data'
15
+ bit1 :read_data, label: 'Read Data'
16
+ # byte boundary
17
+ bit7 :reserved, label: 'Reserved Space'
18
+ bit1 :write_attr, label: 'Write Attributes'
19
+
20
+ # byte boundary
21
+ bit3 :reserved2, label: 'Reserved Space'
22
+ bit1 :synchronize, label: 'Synchronize'
23
+ bit1 :write_owner, label: 'Write Owner'
24
+ bit1 :write_dac, label: 'Write DAC'
25
+ bit1 :read_control, label: 'Read Control'
26
+ bit1 :delete_access, label: 'Delete'
27
+ # byte boundary
28
+ bit1 :generic_read, label: 'Generic Read'
29
+ bit1 :generic_write, label: 'Generic Write'
30
+ bit1 :generic_execute, label: 'Generic Execute'
31
+ bit1 :generic_all, label: 'Generic All'
32
+ bit2 :reserved3
33
+ bit1 :maximum, label: 'Maximum Allowed'
34
+ bit1 :system_security, label: 'System Security'
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,19 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # The OptionalSupport bit-field for an SMB1 TreeConnect Response Packet
5
+ # [2.2.4.7.2 Server Response Extensions](https://msdn.microsoft.com/en-us/library/cc246331.aspx)
6
+ class OptionalSupport < BinData::Record
7
+ endian :little
8
+ bit2 :reserved, label: 'Reserved Space', initial_value: 0
9
+ bit1 :extended_signature, label: 'Extended Signature', initial_value: 0
10
+ bit1 :unique_filename, label: 'Unique Filename', initial_value: 0
11
+ bit2 :csc_mask, label: 'CSC Mask', initial_value: 0
12
+ bit1 :dfs, label: 'DFS Share', initial_value: 0
13
+ bit1 :search, label: 'Exclusive Search Bits', initial_value: 1
14
+ bit8 :reserved2, label: 'Reserved Space', initial_value: 0
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,18 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # The Flags bit-field for an SMB1 TreeConnect Request Packet
5
+ # [2.2.4.7.1 Client Request Extensions](https://msdn.microsoft.com/en-us/library/cc246330.aspx)
6
+ class TreeConnectFlags < BinData::Record
7
+ endian :little
8
+ bit4 :reserved, label: 'Reserved Space', initial_value: 0
9
+ bit1 :extended_response, label: 'Extended Response', initial_value: 1
10
+ bit1 :extended_signature, label: 'Extended Signature', initial_value: 0
11
+ bit1 :reserved2, label: 'Reserved Space', initial_value: 0
12
+ bit1 :disconnect, label: 'Disconnect Tree', initial_value: 0
13
+ bit4 :reserved3, label: 'Reserved Space', initial_value: 0
14
+ bit4 :reserved4, label: 'Reserved Space', initial_value: 0
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,8 +1,10 @@
1
1
  module RubySMB
2
2
  module SMB1
3
3
  module Commands
4
+ SMB_COM_TREE_DISCONNECT = 0x71
4
5
  SMB_COM_NEGOTIATE = 0x72
5
6
  SMB_COM_SESSION_SETUP = 0x73
7
+ SMB_COM_TREE_CONNECT = 0x75
6
8
  SMB_COM_NO_ANDX_COMMAND = 0xFF
7
9
  end
8
10
  end
@@ -7,6 +7,10 @@ module RubySMB
7
7
  require 'ruby_smb/smb1/packet/negotiate_response_extended'
8
8
  require 'ruby_smb/smb1/packet/session_setup_request'
9
9
  require 'ruby_smb/smb1/packet/session_setup_response'
10
+ require 'ruby_smb/smb1/packet/tree_connect_request'
11
+ require 'ruby_smb/smb1/packet/tree_connect_response'
12
+ require 'ruby_smb/smb1/packet/tree_disconnect_request'
13
+ require 'ruby_smb/smb1/packet/tree_disconnect_response'
10
14
  end
11
15
  end
12
16
  end
@@ -0,0 +1,34 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+
5
+ # This class represents an SMB1 TreeConnect Request Packet as defined in
6
+ # [2.2.4.7.1 Client Request Extensions](https://msdn.microsoft.com/en-us/library/cc246330.aspx)
7
+ class TreeConnectRequest < RubySMB::GenericPacket
8
+
9
+ # A SMB1 Parameter Block as defined by the {TreeConnectRequest}
10
+ class ParameterBlock < RubySMB::SMB1::ParameterBlock
11
+ and_x_block :andx_block
12
+ tree_connect_flags :flags
13
+ uint16 :password_length, label: 'Password Length', initial_value: 0x01
14
+ end
15
+
16
+ class DataBlock < RubySMB::SMB1::DataBlock
17
+ stringz :password, label: 'Password Field', initial_value: '', length: lambda { self.parent.parameter_block.password_length }
18
+ stringz :path, label: 'Resource Path'
19
+ stringz :service, label: 'Resource Type', initial_value: '?????'
20
+ end
21
+
22
+ smb_header :smb_header
23
+ parameter_block :parameter_block
24
+ data_block :data_block
25
+
26
+ def initialize_instance
27
+ super
28
+ smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
29
+ end
30
+
31
+ end
32
+ end
33
+ end
34
+ end