ruby_smb 0.0.8

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 (102) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.gitignore +21 -0
  4. data/.rspec +3 -0
  5. data/.simplecov +42 -0
  6. data/.travis.yml +5 -0
  7. data/.yardopts +1 -0
  8. data/CONTRIBUTING.md +119 -0
  9. data/Gemfile +13 -0
  10. data/LICENSE.txt +18 -0
  11. data/README.md +64 -0
  12. data/Rakefile +22 -0
  13. data/examples/authenticate.rb +30 -0
  14. data/examples/negotiate.rb +25 -0
  15. data/lib/ruby_smb/client/authentication.rb +236 -0
  16. data/lib/ruby_smb/client/negotiation.rb +126 -0
  17. data/lib/ruby_smb/client/signing.rb +48 -0
  18. data/lib/ruby_smb/client.rb +164 -0
  19. data/lib/ruby_smb/dispatcher/base.rb +18 -0
  20. data/lib/ruby_smb/dispatcher/socket.rb +53 -0
  21. data/lib/ruby_smb/dispatcher.rb +4 -0
  22. data/lib/ruby_smb/error.rb +17 -0
  23. data/lib/ruby_smb/field/file_time.rb +62 -0
  24. data/lib/ruby_smb/field/nt_status.rb +16 -0
  25. data/lib/ruby_smb/field/stringz16.rb +55 -0
  26. data/lib/ruby_smb/field.rb +7 -0
  27. data/lib/ruby_smb/generic_packet.rb +179 -0
  28. data/lib/ruby_smb/gss.rb +109 -0
  29. data/lib/ruby_smb/smb1/andx_block.rb +13 -0
  30. data/lib/ruby_smb/smb1/bit_field/capabilities.rb +39 -0
  31. data/lib/ruby_smb/smb1/bit_field/header_flags.rb +19 -0
  32. data/lib/ruby_smb/smb1/bit_field/header_flags2.rb +27 -0
  33. data/lib/ruby_smb/smb1/bit_field/security_mode.rb +16 -0
  34. data/lib/ruby_smb/smb1/bit_field.rb +10 -0
  35. data/lib/ruby_smb/smb1/commands.rb +9 -0
  36. data/lib/ruby_smb/smb1/data_block.rb +42 -0
  37. data/lib/ruby_smb/smb1/dialect.rb +11 -0
  38. data/lib/ruby_smb/smb1/packet/error_packet.rb +14 -0
  39. data/lib/ruby_smb/smb1/packet/negotiate_request.rb +52 -0
  40. data/lib/ruby_smb/smb1/packet/negotiate_response.rb +46 -0
  41. data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +47 -0
  42. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +71 -0
  43. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +48 -0
  44. data/lib/ruby_smb/smb1/packet.rb +12 -0
  45. data/lib/ruby_smb/smb1/parameter_block.rb +42 -0
  46. data/lib/ruby_smb/smb1/smb_header.rb +21 -0
  47. data/lib/ruby_smb/smb1.rb +16 -0
  48. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +17 -0
  49. data/lib/ruby_smb/smb2/bit_field/smb2_capabailities.rb +23 -0
  50. data/lib/ruby_smb/smb2/bit_field/smb2_header_flags.rb +23 -0
  51. data/lib/ruby_smb/smb2/bit_field/smb2_security_mode.rb +15 -0
  52. data/lib/ruby_smb/smb2/bit_field/smb2_security_mode_single.rb +14 -0
  53. data/lib/ruby_smb/smb2/bit_field.rb +11 -0
  54. data/lib/ruby_smb/smb2/commands.rb +25 -0
  55. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +50 -0
  56. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +33 -0
  57. data/lib/ruby_smb/smb2/packet/session_setup_request.rb +53 -0
  58. data/lib/ruby_smb/smb2/packet/session_setup_response.rb +38 -0
  59. data/lib/ruby_smb/smb2/packet.rb +10 -0
  60. data/lib/ruby_smb/smb2/smb2_header.rb +22 -0
  61. data/lib/ruby_smb/smb2.rb +12 -0
  62. data/lib/ruby_smb/version.rb +3 -0
  63. data/lib/ruby_smb.rb +22 -0
  64. data/ruby_smb.gemspec +38 -0
  65. data/spec/lib/ruby_smb/client_spec.rb +638 -0
  66. data/spec/lib/ruby_smb/dispatcher/dispatcher_base_spec.rb +22 -0
  67. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +60 -0
  68. data/spec/lib/ruby_smb/field/file_time_spec.rb +59 -0
  69. data/spec/lib/ruby_smb/field/nt_status_spec.rb +19 -0
  70. data/spec/lib/ruby_smb/field/stringz16_spec.rb +50 -0
  71. data/spec/lib/ruby_smb/generic_packet_spec.rb +58 -0
  72. data/spec/lib/ruby_smb/smb1/andx_block_spec.rb +41 -0
  73. data/spec/lib/ruby_smb/smb1/bit_field/capabilities_spec.rb +245 -0
  74. data/spec/lib/ruby_smb/smb1/bit_field/header_flags2_spec.rb +146 -0
  75. data/spec/lib/ruby_smb/smb1/bit_field/header_flags_spec.rb +102 -0
  76. data/spec/lib/ruby_smb/smb1/bit_field/security_mode_spec.rb +44 -0
  77. data/spec/lib/ruby_smb/smb1/data_block_spec.rb +26 -0
  78. data/spec/lib/ruby_smb/smb1/dialect_spec.rb +26 -0
  79. data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +39 -0
  80. data/spec/lib/ruby_smb/smb1/packet/negotiate_request_spec.rb +77 -0
  81. data/spec/lib/ruby_smb/smb1/packet/negotiate_response_extended_spec.rb +149 -0
  82. data/spec/lib/ruby_smb/smb1/packet/negotiate_response_spec.rb +150 -0
  83. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +100 -0
  84. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +72 -0
  85. data/spec/lib/ruby_smb/smb1/parameter_block_spec.rb +26 -0
  86. data/spec/lib/ruby_smb/smb1/smb_header_spec.rb +96 -0
  87. data/spec/lib/ruby_smb/smb2/bit_field/header_flags_spec.rb +81 -0
  88. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +28 -0
  89. data/spec/lib/ruby_smb/smb2/bit_field/smb2_capabilities_spec.rb +72 -0
  90. data/spec/lib/ruby_smb/smb2/bit_field/smb_secruity_mode_spec.rb +22 -0
  91. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +122 -0
  92. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +147 -0
  93. data/spec/lib/ruby_smb/smb2/packet/session_setup_request_spec.rb +79 -0
  94. data/spec/lib/ruby_smb/smb2/packet/session_setup_response_spec.rb +54 -0
  95. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +127 -0
  96. data/spec/lib/ruby_smb_spec.rb +2 -0
  97. data/spec/spec_helper.rb +100 -0
  98. data/spec/support/mock_socket_dispatcher.rb +8 -0
  99. data/spec/support/shared/examples/bit_field_single_flag.rb +14 -0
  100. data.tar.gz.sig +0 -0
  101. metadata +384 -0
  102. metadata.gz.sig +0 -0
@@ -0,0 +1,179 @@
1
+ module RubySMB
2
+ # Parent class for all SMB Packets.
3
+ class GenericPacket < BinData::Record
4
+ # Outputs a nicely formatted string representation
5
+ # of the Packet's structure.
6
+ #
7
+ # @return [String] formatted string representation of the packet structure
8
+ def self.describe
9
+ description = ''
10
+ fields_hashed.each do |field|
11
+ description << format_field(field)
12
+ end
13
+ description
14
+ end
15
+
16
+ def display
17
+ display_str = ''
18
+ self.class.fields_hashed.each do |field|
19
+ display_str << display_field(field)
20
+ end
21
+ display_str
22
+ end
23
+
24
+
25
+ def packet_smb_version
26
+ class_name = self.class.to_s
27
+ case class_name
28
+ when /SMB1/
29
+ 'SMB1'
30
+ when /SMB2/
31
+ 'SMB2'
32
+ else
33
+ ''
34
+ end
35
+ end
36
+
37
+ def status_code
38
+ smb_version = packet_smb_version
39
+ case smb_version
40
+ when 'SMB1'
41
+ status_code = WindowsError::NTStatus.find_by_retval(self.smb_header.nt_status.value).first
42
+ when 'SMB2'
43
+ status_code = WindowsError::NTStatus.find_by_retval(self.smb2_header.nt_status.value).first
44
+ else
45
+ nil
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ # Returns an array of hashes representing the
52
+ # fields for this record.
53
+ #
54
+ # @return [Array<Hash>] the array of hash representations of the record's fields
55
+ def self.fields_hashed
56
+ walk_fields(fields)
57
+ end
58
+
59
+ # Takes a hash representation of a field and spits out a formatted
60
+ # string representation.
61
+ #
62
+ # @param field [Hash] the hash representing the field
63
+ # @param depth [Fixnum] the recursive depth level to track indentation
64
+ # @return [String] the formatted string representation of the field
65
+ def self.format_field(field, depth = 0)
66
+ name = field[:name].to_s
67
+ if field[:class].ancestors.include? BinData::Record
68
+ class_str = ''
69
+ name.upcase!
70
+ else
71
+ class_str = field[:class].to_s.split('::').last
72
+ class_str = "(#{class_str})"
73
+ name.capitalize!
74
+ end
75
+ formatted_name = "\n" + ("\t" * depth) + name
76
+ formatted_string = sprintf '%-30s %-10s %s', formatted_name, class_str, field[:label]
77
+ field[:fields].each do |sub_field|
78
+ formatted_string << format_field(sub_field, (depth + 1))
79
+ end
80
+ formatted_string
81
+ end
82
+
83
+ # Recursively walks through a field, building a hash representation
84
+ # of that field and all of it's sub-fields.
85
+ #
86
+ # @param fields [Array<BinData::SanitizedField>] an array of fields to walk
87
+ # @return [Array<Hash>] an array of hashes representing the fields
88
+ def self.walk_fields(fields)
89
+ field_hashes = []
90
+ fields.each do |field|
91
+ field_hash = {}
92
+ field_hash[:name] = field.name
93
+ prototype = field.prototype
94
+ field_hash[:class] = prototype.instance_variable_get(:@obj_class)
95
+ params = prototype.instance_variable_get(:@obj_params)
96
+ field_hash[:label] = params[:label]
97
+ field_hash[:value] = params[:value]
98
+ sub_fields = params[:fields]
99
+ field_hash[:fields] = if sub_fields.nil?
100
+ []
101
+ else
102
+ walk_fields(sub_fields)
103
+ end
104
+ field_hashes << field_hash
105
+ end
106
+ field_hashes
107
+ end
108
+
109
+ # Takes a hash representation of a field in the packet structure and formats it
110
+ # into a string representing the contents of that field.
111
+ #
112
+ # @param field [Hash] hash representation of the field to display
113
+ # @param depth [Fixnum] the recursion depth for setting indent levels
114
+ # @param parents [Array<Symbol>] the name of the parent field, if any, of this field
115
+ # @return [String] a formatted string representing the field and it's current contents
116
+ def display_field(field, depth = 0, parents = [])
117
+ my_parents = parents.dup
118
+ field_str = ''
119
+ name = field[:name]
120
+ if field[:class] == BinData::Array
121
+ field_str = "\n" + ("\t" * depth) + name.to_s.upcase
122
+ parent = self
123
+ my_parents.each do |pfield|
124
+ parent = parent.send(pfield)
125
+ end
126
+ array_field = parent.send(name)
127
+ field_str << process_array_field(array_field, (depth + 1))
128
+ else
129
+ if my_parents.empty?
130
+ label = "\n" + ("\t" * depth) + name.to_s.upcase
131
+ if field[:class].ancestors.include? BinData::Record
132
+ field_str = label
133
+ else
134
+ value = self.send(name)
135
+ field_str = sprintf '%-30s %s', label, value
136
+ end
137
+ else
138
+ parent = self
139
+ my_parents.each do |pfield|
140
+ parent = parent.send(pfield)
141
+ end
142
+ value = parent.send(name)
143
+ label = field[:label] || name.to_s.capitalize
144
+ label = "\n" + ("\t" * depth) + label
145
+ field_str = sprintf '%-30s %s', label, value
146
+ end
147
+ end
148
+ my_parents << name
149
+ field[:fields].each do |sub_field|
150
+ field_str << display_field(sub_field, (depth + 1), my_parents)
151
+ end
152
+ field_str
153
+ end
154
+
155
+ # Takes a {BinData::Array} field and processes it to get
156
+ # the structure elements and values out since they cannot be
157
+ # evaluated at the class level.
158
+ #
159
+ # @param array_field [BinData::Array] the Array field to be processed
160
+ # @return [String] the formatted string representing the contents of the array
161
+ def process_array_field(array_field, depth)
162
+ array_field_str = ''
163
+ array_field.each do |sub_field|
164
+ fields = sub_field.class.fields.fields
165
+ sub_field_hashes = self.class.walk_fields(fields)
166
+ sub_field_hashes.each do |sub_field_hash|
167
+ name = sub_field_hash[:name]
168
+ label = sub_field_hash[:label]
169
+ value = sub_field.send(name)
170
+ label ||= name
171
+ label = "\n" + "\t" * depth + label
172
+ sub_field_str = sprintf '%-30s %s', label, value
173
+ array_field_str << sub_field_str
174
+ end
175
+ end
176
+ array_field_str
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,109 @@
1
+ module RubySMB
2
+
3
+ # module containing methods required for using the [GSS-API](http://www.rfc-editor.org/rfc/rfc2743.txt)
4
+ # for Secure Protected Negotiation(SPNEGO) in SMB Authentication.
5
+ module Gss
6
+
7
+ # Cargo culted from Rex. Hacked Together ASN1 encoding that works for our GSS purposes
8
+ # @todo Document these magic numbers
9
+ def self.asn1encode(str = '')
10
+ # If the high bit of the first byte is 1, it contains the number of
11
+ # length bytes that follow
12
+ case str.length
13
+ when 0..0x7F
14
+ encoded_string = [str.length].pack('C') + str
15
+ when 0x80..0xFF
16
+ encoded_string = [0x81, str.length].pack('CC') + str
17
+ when 0x100..0xFFFF
18
+ encoded_string = [0x82, str.length].pack('Cn') + str
19
+ when 0x10000..0xffffff
20
+ encoded_string = [0x83, str.length >> 16, str.length & 0xFFFF].pack('CCn') + str
21
+ when 0x1000000..0xffffffff
22
+ encoded_string = [0x84, str.length].pack('CN') + str
23
+ else
24
+ raise RubySMB::Error::ASN1Encoding, "Source string is too long. Size is #{str.length}"
25
+ end
26
+ encoded_string
27
+ end
28
+
29
+ # Create a GSS Security Blob of an NTLM Type 1 Message.
30
+ # This code has been cargo culted and needs to be researched
31
+ # and refactored into something better later.
32
+ #@todo Refactor this into non-magical code
33
+ def self.gss_type1(type1)
34
+ "\x60".force_encoding("binary") + self.asn1encode(
35
+ "\x06".force_encoding("binary") + self.asn1encode(
36
+ "\x2b\x06\x01\x05\x05\x02".force_encoding("binary")
37
+ ) +
38
+ "\xa0".force_encoding("binary") + self.asn1encode(
39
+ "\x30".force_encoding("binary") + self.asn1encode(
40
+ "\xa0".force_encoding("binary") + self.asn1encode(
41
+ "\x30".force_encoding("binary") + self.asn1encode(
42
+ "\x06".force_encoding("binary") + self.asn1encode(
43
+ "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a".force_encoding("binary")
44
+ )
45
+ )
46
+ ) +
47
+ "\xa2".force_encoding("binary") + self.asn1encode(
48
+ "\x04".force_encoding("binary") + self.asn1encode(
49
+ type1
50
+ )
51
+ )
52
+ )
53
+ )
54
+ )
55
+ end
56
+
57
+
58
+ # Create a GSS Security Blob of an NTLM Type 2 Message.
59
+ # This code has been cargo culted and needs to be researched
60
+ # and refactored into something better later.
61
+ def self.gss_type2(type2)
62
+
63
+ blob =
64
+ "\xa1" + self.asn1encode(
65
+ "\x30" + self.asn1encode(
66
+ "\xa0" + self.asn1encode(
67
+ "\x0a" + self.asn1encode(
68
+ "\x01"
69
+ )
70
+ ) +
71
+ "\xa1" + self.asn1encode(
72
+ "\x06" + self.asn1encode(
73
+ "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
74
+ )
75
+ ) +
76
+ "\xa2" + self.asn1encode(
77
+ "\x04" + self.asn1encode(
78
+ type2
79
+ )
80
+ )
81
+ )
82
+ )
83
+
84
+ return blob
85
+ end
86
+
87
+ # Create a GSS Security Blob of an NTLM Type 3 Message.
88
+ # This code has been cargo culted and needs to be researched
89
+ # and refactored into something better later.
90
+ #@todo Refactor this into non-magical code
91
+ def self.gss_type3(type3)
92
+ gss =
93
+ "\xa1".force_encoding("binary") + self.asn1encode(
94
+ "\x30".force_encoding("binary") + self.asn1encode(
95
+ "\xa2".force_encoding("binary") + self.asn1encode(
96
+ "\x04".force_encoding("binary") + self.asn1encode(
97
+ type3
98
+ )
99
+ )
100
+ )
101
+ )
102
+
103
+ gss
104
+ end
105
+
106
+
107
+
108
+ end
109
+ end
@@ -0,0 +1,13 @@
1
+ module RubySMB
2
+ module SMB1
3
+ # Represents the ANDX Block in SMB1 ANDX Command Packets
4
+ # [2.2.3.4 Batched Messages ("AndX" Messages)](https://msdn.microsoft.com/en-us/library/ee442210.aspx)
5
+ class AndXBlock < BinData::Record
6
+ endian :little
7
+
8
+ bit8 :andx_command, label: 'Next Command Code', initial_value: RubySMB::SMB1::Commands::SMB_COM_NO_ANDX_COMMAND
9
+ bit8 :andx_reserved, label: 'AndX Reserved', initial_value: 0x00
10
+ bit16 :andx_offset, label: 'Andx Offset', initial_value: 0x00
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # The Capabilities bit-field for a NegotiateResponse as defined in
5
+ # [2.2.4.52.2 Response](https://msdn.microsoft.com/en-us/library/ee441946.aspx)
6
+ class Capabilities < BinData::Record
7
+ endian :little
8
+ bit1 :level_2_oplocks, label: 'Level II OpLocks', initial_value: 1
9
+ bit1 :nt_status, label: 'NTStatus Codes', initial_value: 1
10
+ bit1 :rpc_remote_apis, label: 'MS-RPC Supported'
11
+ bit1 :nt_smbs, label: 'NT Lan Manager', initial_value: 1
12
+ bit1 :large_files, label: '64-bit File offsets'
13
+ bit1 :unicode, label: 'Unicode Strings', initial_value: 1
14
+ bit1 :mpx_mode, label: 'Multiplex Mode'
15
+ bit1 :raw_mode, label: 'Raw Mode'
16
+ # Byte Border
17
+ bit1 :large_writex, label: 'Large Write Andx'
18
+ bit1 :large_readx, label: 'Large Read Andx'
19
+ bit1 :info_level_passthru, label: 'Infolevel Passthrough'
20
+ bit1 :dfs, label: 'DFS'
21
+ bit1 :reserved1, label: 'Reserved', initial_value: 0
22
+ bit1 :bulk_transfer, label: 'Bulk Transfer', initial_value: 0
23
+ bit1 :nt_find, label: 'Trans2 Find'
24
+ bit1 :lock_and_read, label: 'Lock And Read'
25
+ # Byte Border
26
+ bit1 :unix, label: 'UNIX Extensions'
27
+ bit6 :reserved2, label: 'Reserved', initial_value: 0
28
+ bit1 :lwio, label: 'LWIO IOCTL/FSCTL'
29
+ # Byte Border
30
+ bit1 :extended_security, label: 'Extended Security', initial_value: 1
31
+ bit1 :reserved3, label: 'Reserved', initial_value: 0
32
+ bit1 :dynamic_reauth, label: 'Dynamic Reauth'
33
+ bit3 :reserved4, label: 'Reserved', initial_value: 0
34
+ bit1 :compressed_data, label: 'Compressed Data'
35
+ bit1 :reserved5, label: 'Reserved', initial_value: 0
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # The Flags bit-field for an SMB1 Header as defined in
5
+ # [2.2.3.1 SMB Header Extensions](https://msdn.microsoft.com/en-us/library/cc246254.aspx)
6
+ class HeaderFlags < BinData::Record
7
+ endian :little
8
+ bit1 :reply, label: 'Response Packet?'
9
+ bit1 :opbatch, label: 'Batch OpLock', initial_value: 0
10
+ bit1 :oplock, label: 'Exclusive Oplock', initial_value: 0
11
+ bit1 :canonicalized_paths, label: 'Canonicalized Pathnames', initial_value: 1
12
+ bit1 :case_insensitive, label: 'Pathnames Case Insensitive', initial_value: 1
13
+ bit1 :reserved, label: 'Flags Reserved', initial_value: 0
14
+ bit1 :buf_avail, label: 'Receive Buffer Available', initial_value: 0
15
+ bit1 :lock_and_read_ok, label: 'Lock&Read Supported'
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # The Flags2 bit-field for an SMB1 Header as defined in
5
+ # [2.2.3.1 SMB Header Extensions](https://msdn.microsoft.com/en-us/library/cc246254.aspx)
6
+ class HeaderFlags2 < BinData::Record
7
+ endian :little
8
+ bit1 :reserved1, label: 'Reserved', initial_value: 0
9
+ bit1 :is_long_name, label: 'Long Names Used'
10
+ bit1 :reserved2, label: 'Reserved', initial_value: 0
11
+ bit1 :signature_required, label: 'Security Signature Required'
12
+ bit1 :compressed, label: 'Compressed'
13
+ bit1 :security_signature, label: 'Security Signing'
14
+ bit1 :eas, label: 'Extended Attributes'
15
+ bit1 :long_names, label: 'Long Names Allowed', initial_value: 1
16
+ # Byte Border
17
+ bit1 :unicode, label: 'Unicode Strings', initial_value: 0
18
+ bit1 :nt_status, label: 'NTStatus Errors', initial_value: 1
19
+ bit1 :paging_io, label: 'Read if Execute', initial_value: 1
20
+ bit1 :dfs, label: 'Use DFS'
21
+ bit1 :extended_security, label: 'Extended Security', inital_value: 1
22
+ bit1 :reparse_path, label: '@GMT Token Required'
23
+ resume_byte_alignment
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,16 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ # The SecurityMode bit-field for a NegotiateResponse as defined in
5
+ # [2.2.4.52.2 Response](https://msdn.microsoft.com/en-us/library/ee441946.aspx)
6
+ class SecurityMode < BinData::Record
7
+ endian :little
8
+ bit4 :reserved, label: 'Reserved'
9
+ bit1 :security_signatures_required, label: 'Signatures Required'
10
+ bit1 :security_signatures_enabled, label: 'Signatures Enabled'
11
+ bit1 :encrypt_passwords, label: 'Encrypted Password', initial_value: 1
12
+ bit1 :user_security, label: 'User Level Access', initial_value: 1
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module BitField
4
+ require 'ruby_smb/smb1/bit_field/header_flags'
5
+ require 'ruby_smb/smb1/bit_field/header_flags2'
6
+ require 'ruby_smb/smb1/bit_field/security_mode'
7
+ require 'ruby_smb/smb1/bit_field/capabilities'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Commands
4
+ SMB_COM_NEGOTIATE = 0x72
5
+ SMB_COM_SESSION_SETUP = 0x73
6
+ SMB_COM_NO_ANDX_COMMAND = 0xFF
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,42 @@
1
+ module RubySMB
2
+ module SMB1
3
+ # Represents the DataBlock portion of an SMB1 Packet. The DataBlock will
4
+ # always contain a byte_count field that gives the size of the rest of
5
+ # the data block in bytes.
6
+ class DataBlock < BinData::Record
7
+ endian :little
8
+
9
+ uint16 :byte_count, label: 'Byte Count', value: -> { calculate_byte_count }
10
+
11
+ # Class method to stub byte count calculation during
12
+ # lazy evaluation.
13
+ #
14
+ # @return [Fixnum] will always return 0
15
+ def self.calculate_byte_count
16
+ 0
17
+ end
18
+
19
+ # Returns the name of all fields, other than byte_count, in
20
+ # the DataBlock as symbols.
21
+ #
22
+ # @return [Array<Symbol>] the names of all other DataBlock fields
23
+ def self.data_fields
24
+ fields = self.fields.collect(&:name)
25
+ fields.reject { |field| field == :byte_count }
26
+ end
27
+
28
+ # Calculates the size of the other fields in the DataBlock
29
+ # in Bytes.
30
+ #
31
+ # @return [Fixnum] The size of the DataBlock in Words
32
+ def calculate_byte_count
33
+ total_count = 0
34
+ self.class.data_fields.each do |field_name|
35
+ field_value = send(field_name)
36
+ total_count += field_value.do_num_bytes
37
+ end
38
+ total_count
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,11 @@
1
+ module RubySMB
2
+ module SMB1
3
+ # This class represents the Dialect for a NegotiateRequest.
4
+ # [2.2.4.52.1](https://msdn.microsoft.com/en-us/library/ee441572.aspx)
5
+ class Dialect < BinData::Record
6
+ endian :little
7
+ bit8 :buffer_format, label: 'Buffer Format ID', initial_value: 0x2
8
+ stringz :dialect_string, label: 'Dialect Name'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+
5
+ # This packet rpresent an SMB1 Response Packet when an Error has occured.
6
+ # The Parameter and Data Blocks will be empty, for reasons.
7
+ class ErrorPacket < RubySMB::GenericPacket
8
+ smb_header :smb_header
9
+ parameter_block :parameter_block
10
+ data_block :data_block
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,52 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+ # A SMB1 SMB_COM_NEGOTIATE Request Packet as defined in
5
+ # [2.2.4.52.1](https://msdn.microsoft.com/en-us/library/ee441572.aspx)
6
+ class NegotiateRequest < RubySMB::GenericPacket
7
+ # Represents the specific layout of the DataBlock for a NegotiateRequest Packet.
8
+ class DataBlock < RubySMB::SMB1::DataBlock
9
+ array :dialects, label: 'Dialects', type: :dialect, read_until: :eof
10
+ end
11
+
12
+ smb_header :smb_header
13
+ parameter_block :parameter_block
14
+ data_block :data_block
15
+
16
+ def initialize_instance
17
+ super
18
+ smb_header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
19
+ end
20
+
21
+ # Add an individual Dialect string to the list of
22
+ # Dialects in the packet.
23
+ #
24
+ # @param dialect_string [String] The string representing the Dialect to be negotiated
25
+ # @return [BinData::Array] A BinData array containing all the currently set dialects.
26
+ def add_dialect(dialect_string)
27
+ new_dialect = Dialect.new(dialect_string: dialect_string)
28
+ data_block.dialects << new_dialect
29
+ end
30
+
31
+ # Returns the Dialects array as a normal Ruby {Array}.
32
+ #
33
+ # @return [Array<Hash>] array of the set dialects on the packet
34
+ def dialects
35
+ data_block.dialects.to_a
36
+ end
37
+
38
+ # Sets the entire list of dialects for the Negotiate Request.
39
+ #
40
+ # @param dialect_array [Array<String>] An array of dialect strings to set on the packet
41
+ # @return [BinData::Array] A BinData array containing all the currently set dialects.
42
+ def set_dialects(dialect_array)
43
+ data_block.dialects.clear
44
+ dialect_array.each do |dialect_string|
45
+ add_dialect(dialect_string)
46
+ end
47
+ data_block.dialects
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,46 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+ # A SMB1 SMB_COM_NEGOTIATE Non-Extended Security Response Packet as defined in
5
+ # [2.2.4.5.2.2 Non-Extended Security Response](https://msdn.microsoft.com/en-us/library/cc246327.aspx)
6
+ class NegotiateResponse < RubySMB::GenericPacket
7
+ # An SMB_Parameters Block as defined by the {NegotiateResponse}.
8
+ class ParameterBlock < RubySMB::SMB1::ParameterBlock
9
+ uint16 :dialect_index, label: 'Dialect Index'
10
+ security_mode :security_mode
11
+ uint16 :max_mpx_count, label: 'Max Multiplex Count'
12
+ uint16 :max_number_vcs, label: 'Max Virtual Circuits'
13
+ uint32 :max_buffer_size, label: 'Max Buffer Size'
14
+ uint32 :max_raw_size, label: 'Max Raw Size'
15
+ uint32 :session_key, label: 'Session Key'
16
+ capabilities :capabilities
17
+ file_time :system_time, label: 'Server System Time'
18
+ int16 :server_time_zone, label: 'Server TimeZone'
19
+ uint8 :challenge_length, label: 'Challenge Length', initial_value: 0x08
20
+ end
21
+
22
+ # An SMB_Data Block as defined by the {NegotiateResponse}
23
+ class DataBlock < RubySMB::SMB1::DataBlock
24
+ string :challenge, label: 'Auth Challenge', length: 8
25
+ stringz16 :domain_name, label: 'Primary Domain'
26
+ stringz16 :server_name, label: 'Server Name'
27
+ end
28
+
29
+ smb_header :smb_header
30
+ parameter_block :parameter_block
31
+ data_block :data_block
32
+
33
+ def initialize_instance
34
+ super
35
+ header = smb_header
36
+ header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
37
+ header.flags.reply = 1
38
+ end
39
+
40
+ def valid?
41
+ smb_header.command == RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,47 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+ # A SMB1 SMB_COM_NEGOTIATE Extended Security Response Packet as defined in
5
+ # [2.2.4.5.2.1 Extended Security Response](https://msdn.microsoft.com/en-us/library/cc246326.aspx)
6
+ class NegotiateResponseExtended < RubySMB::GenericPacket
7
+ # An SMB_Parameters Block as defined by the {NegotiateResponseExtended}.
8
+ class ParameterBlock < RubySMB::SMB1::ParameterBlock
9
+ uint16 :dialect_index, label: 'Dialect Index'
10
+ security_mode :security_mode
11
+ uint16 :max_mpx_count, label: 'Max Multiplex Count'
12
+ uint16 :max_number_vcs, label: 'Max Virtual Circuits'
13
+ uint32 :max_buffer_size, label: 'Max Buffer Size'
14
+ uint32 :max_raw_size, label: 'Max Raw Size'
15
+ uint32 :session_key, label: 'Session Key'
16
+ capabilities :capabilities
17
+ file_time :system_time, label: 'Server System Time'
18
+ int16 :server_time_zone, label: 'Server TimeZone'
19
+ uint8 :challenge_length, label: 'Challenge Length', initial_value: 0x00
20
+ end
21
+
22
+ # An SMB_Data Block as defined by the {NegotiateResponseExtended}
23
+ class DataBlock < RubySMB::SMB1::DataBlock
24
+ string :server_guid, label: 'Server GUID', length: 16
25
+ rest :security_blob, label: 'GSS Security BLOB'
26
+ end
27
+
28
+ smb_header :smb_header
29
+ parameter_block :parameter_block
30
+ data_block :data_block
31
+
32
+ def initialize_instance
33
+ super
34
+ header = smb_header
35
+ header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
36
+ header.flags.reply = 1
37
+ end
38
+
39
+ def valid?
40
+ return false unless smb_header.command == RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
41
+ return false unless parameter_block.capabilities.extended_security == 1
42
+ true
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end