ruby_smb 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
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