packetgen-plugin-smb 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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'