packetgen-plugin-smb 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/packetgen-plugin-smb.rb +7 -5
  3. data/lib/packetgen/plugin/gssapi.rb +125 -0
  4. data/lib/packetgen/plugin/smb.rb +26 -32
  5. data/lib/packetgen/plugin/smb/blocks.rb +2 -2
  6. data/lib/packetgen/plugin/smb/browser.rb +3 -3
  7. data/lib/packetgen/plugin/smb/browser/domain_announcement.rb +3 -3
  8. data/lib/packetgen/plugin/smb/browser/host_announcement.rb +4 -4
  9. data/lib/packetgen/plugin/smb/browser/local_master_announcement.rb +3 -3
  10. data/lib/packetgen/plugin/smb/close.rb +9 -59
  11. data/lib/packetgen/plugin/smb/close/request.rb +45 -0
  12. data/lib/packetgen/plugin/smb/close/response.rb +36 -0
  13. data/lib/packetgen/plugin/smb/filetime.rb +10 -9
  14. data/lib/packetgen/plugin/smb/nt_create_and_x.rb +9 -264
  15. data/lib/packetgen/plugin/smb/ntcreateandx/request.rb +159 -0
  16. data/lib/packetgen/plugin/smb/ntcreateandx/response.rb +128 -0
  17. data/lib/packetgen/plugin/smb/string.rb +4 -4
  18. data/lib/packetgen/plugin/smb/trans.rb +9 -190
  19. data/lib/packetgen/plugin/smb/trans/request.rb +121 -0
  20. data/lib/packetgen/plugin/smb/trans/response.rb +94 -0
  21. data/lib/packetgen/plugin/smb2.rb +181 -0
  22. data/lib/packetgen/plugin/smb2/base.rb +31 -0
  23. data/lib/packetgen/plugin/smb2/error.rb +50 -0
  24. data/lib/packetgen/plugin/smb2/guid.rb +68 -0
  25. data/lib/packetgen/plugin/smb2/negotiate.rb +22 -0
  26. data/lib/packetgen/plugin/smb2/negotiate/context.rb +131 -0
  27. data/lib/packetgen/plugin/smb2/negotiate/request.rb +166 -0
  28. data/lib/packetgen/plugin/smb2/negotiate/response.rb +190 -0
  29. data/lib/packetgen/plugin/smb2/session_setup.rb +21 -0
  30. data/lib/packetgen/plugin/smb2/session_setup/request.rb +98 -0
  31. data/lib/packetgen/plugin/smb2/session_setup/response.rb +69 -0
  32. data/lib/packetgen/plugin/smb_version.rb +1 -1
  33. data/packetgen-plugin-smb.gemspec +2 -1
  34. metadata +42 -4
@@ -0,0 +1,94 @@
1
+ # This file is part of packetgen-plugin-smb.
2
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PacketGen::Plugin
9
+ class SMB
10
+ module Trans
11
+ # Transaction Response.
12
+ #
13
+ # See also {Blocks}, as {Response} is a specialization of {Blocks#words}
14
+ # and {Blocks#bytes}.
15
+ # @author Sylvain Daubert
16
+ class Response < PacketGen::Header::Base
17
+ # @!attribute word_count
18
+ # The size, in 2-byte words, of the SMB command parameters. It should
19
+ # be +14 + setup_count+.
20
+ # @return [Integer]
21
+ define_field :word_count, PacketGen::Types::Int8, default: 10
22
+ # @!attribute total_param_count
23
+ # The total number of transaction parameter bytes.
24
+ # @return [Integer]
25
+ define_field :total_param_count, PacketGen::Types::Int16le
26
+ # @!attribute total_data_count
27
+ # The total number of transaction data bytes.
28
+ # @return [Integer]
29
+ define_field :total_data_count, PacketGen::Types::Int16le
30
+ # @!attribute rsv1
31
+ # 16-bit reserved field
32
+ # @return [Integer]
33
+ define_field :rsv1, PacketGen::Types::Int16le, default: 0
34
+ # @!attribute param_count
35
+ # 16-bit number of transaction parameter bytes sent in this response.
36
+ # @return [Integer]
37
+ define_field :param_count, PacketGen::Types::Int16le
38
+ # @!attribute param_offset
39
+ # 16-bit offset (in bytes) from the start of the SMB header to the start of the
40
+ # transaction parameters.
41
+ # @return [Integer]
42
+ define_field :param_offset, PacketGen::Types::Int16le
43
+ # @!attribute param_displacement
44
+ # 16-bit offset (in bytes) relative to all of the transaction
45
+ # parameter bytes in this transaction response at which this block of
46
+ # parameter bytes SHOULD be placed.
47
+ # @return [Integer]
48
+ define_field :param_displacement, PacketGen::Types::Int16le
49
+ # @!attribute data_count
50
+ # 16-bit number of transaction data bytes sent in this response.
51
+ # @return [Integer]
52
+ define_field :data_count, PacketGen::Types::Int16le
53
+ # @!attribute data_offset
54
+ # 16-bit offset (in bytes) from the start of the SMB header to the start
55
+ # of the data field.
56
+ # @return [Integer]
57
+ define_field :data_offset, PacketGen::Types::Int16le
58
+ # @!attribute data_displacement
59
+ # 16-bit offset (in bytes) relative to all of the transaction data bytes in
60
+ # this transaction response at which this block of data bytes SHOULD be placed.
61
+ # @return [Integer]
62
+ define_field :data_displacement, PacketGen::Types::Int16le
63
+ # @!attribute setup_count
64
+ # 8-bit number of setup words (ie 16-bit words) contained in {#setup} field.
65
+ define_field :setup_count, PacketGen::Types::Int8
66
+ # @!attribute rsv3
67
+ # 8-bit reserved field
68
+ # @return [Integer]
69
+ define_field :rsv2, PacketGen::Types::Int8
70
+ # @!attribute setup
71
+ # Array of 2-byte words.
72
+ # @return [ArrayPacketGen::]
73
+ define_field :setup, PacketGen::Types::ArrayOfInt16le, builder: ->(h, t) { t.new(counter: h[:setup_count]) }
74
+ # @!attribute byte_count
75
+ # @return [Integer]
76
+ define_field :byte_count, PacketGen::Types::Int16le
77
+ # @!attribute pad1
78
+ # Padding before {#body} to align it on 32-bit boundary
79
+ # @return [Integer]
80
+ define_field :pad1, PacketGen::Types::String, default: "\0" * 4,
81
+ builder: ->(h, t) { t.new(length_from: -> { h.data_offset - SMB.new.sz - (h.offset_of(:byte_count) + h[:byte_count].sz) }) }
82
+ # @!attribute body
83
+ # @return [String]
84
+ define_field :body, PacketGen::Types::String
85
+
86
+ # Give protocol name for this class
87
+ # @return [String]
88
+ def protocol_name
89
+ 'SMB::Trans::Response'
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,181 @@
1
+ # This file is part of packetgen-plugin-smb.
2
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PacketGen::Plugin
9
+ # Server Message Block version 2 and 3 (SMB2) header.
10
+ # @author Sylvain Daubert
11
+ class SMB2 < PacketGen::Header::Base
12
+ # Known commands
13
+ COMMANDS = {
14
+ 'negotiate' => 0,
15
+ 'session_setup' => 1,
16
+ 'logoff' => 2,
17
+ 'tree_connect' => 3,
18
+ 'tree_disconnect' => 4,
19
+ 'create' => 5,
20
+ 'close' => 6,
21
+ 'flush' => 7,
22
+ 'read' => 8,
23
+ 'write' => 9,
24
+ 'lock' => 10,
25
+ 'ioctl' => 11,
26
+ 'cancel' => 12,
27
+ 'echo' => 13,
28
+ 'query_directory' => 14,
29
+ 'change_notify' => 15,
30
+ 'query_info' => 16,
31
+ 'set_info' => 17,
32
+ 'oplock_break' => 18
33
+ }.freeze
34
+
35
+ # SMB marker, on start of header
36
+ MARKER = PacketGen.force_binary("\xfeSMB").freeze
37
+
38
+ # SMB2 header size
39
+ HEADER_SIZE = 64
40
+
41
+ # @!attribute protocol
42
+ # This field must contain {MARKER SMB2 marker}
43
+ # @return [String]
44
+ define_field :protocol, PacketGen::Types::String, static_length: 4, default: MARKER
45
+ # @!attribute structure_size
46
+ # 16-bit SMB2 header size. Should be 64.
47
+ # @return [Integer]
48
+ define_field :structure_size, PacketGen::Types::Int16le, default: HEADER_SIZE
49
+ # @!attribute credit charge
50
+ # 16-bit credit charge field. Must not be used and must be set to 0.
51
+ # @return [Integer]
52
+ define_field :credit_charge, PacketGen::Types::Int16le
53
+ # @!attribute status
54
+ # 32-bit status field (SMB 2 dialect only).
55
+ # @return [Integer]
56
+ define_field :status, PacketGen::Types::Int32le
57
+ # @!attribute command
58
+ # 16-bit command field
59
+ # @return [Integer]
60
+ define_field :command, PacketGen::Types::Int16leEnum, enum: COMMANDS
61
+ # @!attribute credit
62
+ # 16-bit credit field. This is the number of credits a client is requesting in
63
+ # a request, and the number of credits granted in a response.
64
+ # @return [Integer]
65
+ define_field :credit, PacketGen::Types::Int16le
66
+ # @!attribute flags
67
+ # 32-bit flags field
68
+ # @return [Integer]
69
+ define_field :flags, PacketGen::Types::Int32le
70
+ # @!attribute next_command
71
+ # 32-bit offset from the beginning of this SMB2 header to the start of the subsequent
72
+ # 8-byte aligned SMB2 header (only for compounded requests).
73
+ # @return [Integer]
74
+ define_field :next_command, PacketGen::Types::Int32le
75
+ # @!attribute message_id
76
+ # 64-bit alue that identifies a message request and response uniquely across all
77
+ # messages that are sent on the same SMB 2 Protocol transport connection.
78
+ # @return [Integer]
79
+ define_field :message_id, PacketGen::Types::Int64le
80
+ # @!attribute async_id
81
+ # 64-bit unique ID that is created by the server to handle operations
82
+ # asynchronously. Only present for asynchronous messages.
83
+ # @return [Integer]
84
+ define_field :async_id, PacketGen::Types::Int64le, optional: ->(h) { h.flags & 2 == 2}
85
+ # @!attribute reserved
86
+ # 32-bit reserved field.
87
+ # Only present for synchronous messages.
88
+ # @return [Integer]
89
+ define_field :reserved, PacketGen::Types::Int32le, optional: ->(h) { (h.flags & 2).zero? }
90
+ # @!attribute tree_id
91
+ # 32-bit integer that uniquely identifies the tree connect for the command.
92
+ # Only present for synchronous messages.
93
+ # @return [Integer]
94
+ define_field :tree_id, PacketGen::Types::Int32le, optional: ->(h) { (h.flags & 2).zero? }
95
+ # @!attribute session_id
96
+ # 64-bit integer that uniquely identifies the established session for the command.
97
+ # @return [Integer]
98
+ define_field :session_id, PacketGen::Types::Int64le
99
+ # @!attribute signature
100
+ # 16-byte message signature
101
+ # @return [String]
102
+ define_field :signature, PacketGen::Types::String, static_length: 16, default: [0, 0].pack('qq')
103
+ # @!attribute body
104
+ # @return [String]
105
+ define_field :body, PacketGen::Types::String
106
+ # @!attribute flags_rsv1
107
+ # 2-bit reserved field
108
+ # @return [Integer]
109
+ # @!attribute flags_smb3_replay_op?
110
+ # When set, the command is a replay operation (only SMB 3 dialect).
111
+ # @return [Boolean]
112
+ # @!attribute flags_dsf_op?
113
+ # When set, the command is a Distributed File System (DFS) operation..
114
+ # @return [Boolean]
115
+ # @!attribute flags_rsv2
116
+ # 21-bit reserved field
117
+ # @return [Integer]
118
+ # @!attribute flags_smb3_priority
119
+ # 3-bit value of I/O priority (only SMB 3 dialect).
120
+ # @return [Integer]
121
+ # @!attribute flags_signed?
122
+ # When set, the message is signed.
123
+ # @return [Boolean]
124
+ # @!attribute flags_related_op?
125
+ # When set, the message is a related operation in a compounded chain.
126
+ # @return [Boolean]
127
+ # @!attribute flags_async?
128
+ # When set, the message is a asynchronous.
129
+ # @return [Boolean]
130
+ # @!attribute flags_response?
131
+ # When set, the message is a response from server to client.
132
+ # @return [Boolean]
133
+ define_bit_fields_on :flags, :flags_rsv1, 2, :flags_smb3_replay_op, :flags_dfs_op,
134
+ :flags_rsv2, 21, :flags_smb3_priority, 3,
135
+ :flags_signed, :flags_related_op, :flags_async,
136
+ :flags_response
137
+
138
+ # Helper to bind a SMB2 command to {SMB2} header.
139
+ # @param [String] command name
140
+ # @return [void]
141
+ def self.bind_command(command)
142
+ contantized = command.capitalize.gsub(/_(\w)/) { $1.upcase }
143
+ krequest = self.const_get("#{contantized}::Request")
144
+ kresponse = self.const_get("#{contantized}::Response")
145
+ PacketGen::Header.add_class krequest
146
+ self.bind krequest, command: SMB2::COMMANDS[command], flags: ->(v) { v.nil? ? 0 : (v & 1).zero? }
147
+ PacketGen::Header.add_class kresponse
148
+ self.bind kresponse, command: SMB2::COMMANDS[command], flags: ->(v) { v.nil? ? 0 : (v & 1 == 1) }
149
+ end
150
+
151
+ # @return [String]
152
+ def inspect
153
+ super do |attr|
154
+ next unless attr == :flags
155
+
156
+ value = bits_on(attr).reject { |_, v| v > 1 }
157
+ .keys
158
+ .select { |b| send("#{b}?") }
159
+ .map(&:to_s)
160
+ .join(',')
161
+ .gsub!(/#{attr}_/, '')
162
+ value = '%-16s (0x%02x)' % [value, self[attr].to_i]
163
+ str = PacketGen::Inspect.shift_level
164
+ str << PacketGen::Inspect::FMT_ATTR % [self[attr].class.to_s.sub(/.*::/, ''),
165
+ attr, value]
166
+ end
167
+ end
168
+ end
169
+ # TODO: move this in netbios file when packetgen3 will be out
170
+ PacketGen::Header::TCP.bind PacketGen::Header::NetBIOS::Session, dport: 445
171
+ PacketGen::Header::TCP.bind PacketGen::Header::NetBIOS::Session, sport: 445
172
+
173
+ PacketGen::Header.add_class SMB2
174
+ PacketGen::Header::NetBIOS::Session.bind SMB2, body: ->(val) { val.nil? ? SMB2::MARKER : val[0..3] == SMB2::MARKER }
175
+ PacketGen::Header::NetBIOS::Datagram.bind SMB2, body: ->(val) { val.nil? ? SMB2::MARKER : val[0..3] == SMB2::MARKER }
176
+ end
177
+
178
+ require_relative 'smb2/base'
179
+ require_relative 'smb2/negotiate'
180
+ require_relative 'smb2/session_setup'
181
+ require_relative 'smb2/error'
@@ -0,0 +1,31 @@
1
+ # This file is part of packetgen-plugin-smb.
2
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ require_relative 'guid'
9
+
10
+ module PacketGen::Plugin
11
+ class SMB2
12
+ # Helper class to ease definition of SMB2 classes
13
+ # @author Sylvain Daubert
14
+ class Base < PacketGen::Header::Base
15
+ # Helper to define pad fields used to align next field on 8-byte
16
+ # offset
17
+ # @param [Symbol] name name of padding field
18
+ # @return [void]
19
+ def self.define_smb2_pad_field(name)
20
+ prev_field = self.fields.last
21
+ lf = lambda do |hdr|
22
+ len = 8 - (hdr.offset_of(prev_field) + hdr[prev_field].sz) % 8
23
+ len = 0 if len == 8
24
+ len
25
+ end
26
+ define_field name, PacketGen::Types::String, default: [0].pack('q').freeze,
27
+ builder: ->(h, t) { t.new(length_from: -> { lf[h] }) }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,50 @@
1
+ # This file is part of packetgen-plugin-smb.
2
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PacketGen::Plugin
9
+ class SMB2
10
+ # SMB2 Error response structure
11
+ # 0 1 2 3
12
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
13
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
14
+ # | StructureSize | ContextCount | Reserved |
15
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
16
+ # | ByteCount |
17
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
18
+ # | ErrorData |
19
+ # + +
20
+ # | ... |
21
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
22
+ # @author Sylvain Daubert
23
+ class ErrorResponse < PacketGen::Header::Base
24
+ # @!attribute structure_size
25
+ # 16-bit error response structure. Should be 9.
26
+ # @return [Integer]
27
+ define_field :structure_size, PacketGen::Types::Int16le, default: 9
28
+ # !@attribute context_count
29
+ # Only for SMB3 dialect. If non zero, this is the number of element
30
+ # in {#data}, formatted as a variable length array.
31
+ # @return [Integer]
32
+ define_field :context_count, PacketGen::Types::Int8
33
+ # !@attribute reserved
34
+ # 8-bit reserved value
35
+ # @return [Integer]
36
+ define_field :reserved, PacketGen::Types::Int8
37
+ # @!attribute byte_count
38
+ # 32-bit value indicating the number of bytes contained in {#data}
39
+ # @return [Integer]
40
+ define_field :byte_count, PacketGen::Types::Int32le
41
+ # @!attribute data
42
+ # Variable-length data field.
43
+ # @return [String]
44
+ define_field :data, PacketGen::Types::String
45
+ end
46
+ end
47
+ PacketGen::Header.add_class SMB2::ErrorResponse
48
+ SMB2.bind SMB2::ErrorResponse, status: ->(v) { v > 0 }
49
+ end
50
+
@@ -0,0 +1,68 @@
1
+ # This file is part of packetgen-plugin-smb.
2
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module PacketGen::Plugin
9
+ class SMB2
10
+ # GUID, also known as UUID, is a 16-byte structure, intended to serve
11
+ # as a unique identifier for an object.
12
+ # 0 1 2 3
13
+ # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
14
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
15
+ # | Data1 |
16
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
17
+ # | Data2 | Data3 |
18
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
19
+ # | Data4 |
20
+ # + +
21
+ # | |
22
+ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
23
+ # @author Sylvain Daubert
24
+ class GUID < PacketGen::Types::Fields
25
+ # @!attribute data1
26
+ # 32-bit little-endian data1
27
+ # @return [Integer]
28
+ define_field :data1, PacketGen::Types::Int32le
29
+ # @!attribute data2
30
+ # 16-bit little-endian data2
31
+ # @return [Integer]
32
+ define_field :data2, PacketGen::Types::Int16le
33
+ # @!attribute data3
34
+ # 16-bit little-endian data3
35
+ # @return [Integer]
36
+ define_field :data3, PacketGen::Types::Int16le
37
+ # @!attribute data4
38
+ # 64-bit big-endian data4
39
+ # @return [Integer]
40
+ define_field :data4, PacketGen::Types::Int64
41
+
42
+ # Get a human-readable GUID, as specified in RFC 4122
43
+ # guid.to_human # => "7aedb437-01b9-41d4-a5f7-9e6c06e16c8a"
44
+ # @return [String]
45
+ def to_human
46
+ data4p1 = data4 >> 48
47
+ data4p2 = data4 & 0xffff_ffff_ffff
48
+ "%08x-%04x-%04x-%04x-%012x" % [data1, data2, data3, data4p1, data4p2]
49
+ end
50
+
51
+ # Set GUID from a human-readable string
52
+ # @param [String] guid
53
+ # @return [self]
54
+ def from_human(guid)
55
+ return self
56
+ values = guid.split('-')
57
+ return self if values.size != 5
58
+
59
+ self.data1 = values[0].to_i(16)
60
+ self.data2 = values[1].to_i(16)
61
+ self.data3 = values[2].to_i(16)
62
+ self.data4 = values[3].to_i(16) << 48 | values[4].to_i(16)
63
+ self
64
+ end
65
+ end
66
+ end
67
+ end
68
+
@@ -0,0 +1,22 @@
1
+ # This file is part of packetgen-plugin-smb.
2
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
+ # This program is published under MIT license.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ require_relative 'guid'
9
+
10
+ module PacketGen::Plugin
11
+ class SMB2
12
+ # Namespace for NEGOTIATE related classes
13
+ # @author Sylvain Daubert
14
+ module Negotiate; end
15
+ end
16
+ end
17
+
18
+ require_relative 'negotiate/context'
19
+ require_relative 'negotiate/request'
20
+ require_relative 'negotiate/response'
21
+
22
+ PacketGen::Plugin::SMB2.bind_command 'negotiate'