packetgen-plugin-smb 0.3.0 → 0.4.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -1
- data/Gemfile +0 -3
- data/README.md +18 -1
- data/lib/packetgen-plugin-smb.rb +1 -0
- data/lib/packetgen/plugin/gssapi.rb +3 -2
- data/lib/packetgen/plugin/netbios.rb +17 -0
- data/lib/packetgen/plugin/netbios/datagram.rb +108 -0
- data/lib/packetgen/plugin/netbios/name.rb +64 -0
- data/lib/packetgen/plugin/netbios/session.rb +71 -0
- data/lib/packetgen/plugin/smb.rb +2 -2
- data/lib/packetgen/plugin/smb/browser.rb +6 -6
- data/lib/packetgen/plugin/smb/browser/domain_announcement.rb +0 -5
- data/lib/packetgen/plugin/smb/browser/host_announcement.rb +8 -5
- data/lib/packetgen/plugin/smb/browser/local_master_announcement.rb +0 -5
- data/lib/packetgen/plugin/smb/close/request.rb +1 -1
- data/lib/packetgen/plugin/smb/close/response.rb +1 -1
- data/lib/packetgen/plugin/smb/filetime.rb +20 -1
- data/lib/packetgen/plugin/smb/ntcreateandx/request.rb +1 -1
- data/lib/packetgen/plugin/smb/ntcreateandx/response.rb +1 -1
- data/lib/packetgen/plugin/smb/trans/request.rb +1 -1
- data/lib/packetgen/plugin/smb/trans/response.rb +1 -1
- data/lib/packetgen/plugin/smb2.rb +7 -5
- data/lib/packetgen/plugin/smb2/negotiate/context.rb +12 -24
- data/lib/packetgen/plugin/smb2/negotiate/request.rb +6 -6
- data/lib/packetgen/plugin/smb2/negotiate/response.rb +7 -6
- data/lib/packetgen/plugin/smb2/session_setup/request.rb +1 -1
- data/lib/packetgen/plugin/smb2/session_setup/response.rb +1 -1
- data/lib/packetgen/plugin/smb_version.rb +1 -1
- data/packetgen-plugin-smb.gemspec +1 -1
- metadata +8 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f3f0164d4068b3b829fac802f5ce944c33bf86275fb90aa46150e57926a236f3
|
4
|
+
data.tar.gz: 001d57bf0ec000e0e738b25d1116ea0b73bc7a2c0de61b68e6c16ef75a130d4b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 661c09099b29c3c747e5b4d1831b05fb3945123e1d5ff7aaabc053221c100ed1113fd04a72af5fdbc245a9d0789419f6b6fc1c8a37a558c64da53ef1b30c4e8e
|
7
|
+
data.tar.gz: 06b857556ca716b954a4fb935ec3e6e91ab2a0416442b31e3ad7e9eec7631fe33d6c3bb96814fd949fbffd2d58c97fc80fbbd18dd4b66cd5a603663f58169bb9
|
data/.rubocop.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -3,7 +3,20 @@
|
|
3
3
|
|
4
4
|
# Packetgen::Plugin::SMB
|
5
5
|
|
6
|
-
This is a plugin for [PacketGen gem](https://github.com/sdaubert/packetgen). It adds some support for SMB protocol suite
|
6
|
+
This is a plugin for [PacketGen gem](https://github.com/sdaubert/packetgen). It adds some support for SMB protocol suite:
|
7
|
+
|
8
|
+
* SMB:
|
9
|
+
* SMB common header,
|
10
|
+
* Close command,
|
11
|
+
* NtCreateAndX command,
|
12
|
+
* Trans command,
|
13
|
+
* Browser subprotocol,
|
14
|
+
* SMB2:
|
15
|
+
* SMB2 common header (support 2.x and 3.x dialects),
|
16
|
+
* Negotiate command,
|
17
|
+
* SessionSetup command,
|
18
|
+
* GSSAPI, used to transport negotiation over SMB2 commands.
|
19
|
+
|
7
20
|
|
8
21
|
## Installation
|
9
22
|
|
@@ -25,6 +38,10 @@ Or install it yourself as:
|
|
25
38
|
|
26
39
|
TODO
|
27
40
|
|
41
|
+
## See also
|
42
|
+
|
43
|
+
API documentation: http://www.rubydoc.info/gems/packetgen-plugin-smb
|
44
|
+
|
28
45
|
## License
|
29
46
|
|
30
47
|
MIT License (see [LICENSE](https://github.com/sdaubert/packetgen-plugin-smb/blob/master/LICENSE))
|
data/lib/packetgen-plugin-smb.rb
CHANGED
@@ -86,7 +86,7 @@ module PacketGen::Plugin
|
|
86
86
|
'accept-incomplete' => 1,
|
87
87
|
'reject' => 2,
|
88
88
|
'request-mic' => 3
|
89
|
-
}
|
89
|
+
}.freeze
|
90
90
|
sequence :token, explicit: 1, class: :context, constructed: true,
|
91
91
|
content: [enumerated(:negstate, enum: NEG_STATES, explicit: 0, class: :context, constructed: true, optional: true),
|
92
92
|
objectid(:supported_mech, explicit: 1, class: :context, constructed: true, optional: true),
|
@@ -106,8 +106,9 @@ module PacketGen::Plugin
|
|
106
106
|
def initialize(args={})
|
107
107
|
token = args.delete(:token)
|
108
108
|
super
|
109
|
-
self[:gssapi].chosen =
|
109
|
+
self[:gssapi].chosen = token == :init ? 0 : 1
|
110
110
|
end
|
111
|
+
|
111
112
|
# Populate Object from +str+
|
112
113
|
# @param [String] str
|
113
114
|
# @return [self]
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen-plugin-smb for more informations
|
3
|
+
# Copyright (C) 2016 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
|
+
# Module to group all NetBIOS headers
|
10
|
+
# @author Sylvain Daubert
|
11
|
+
module NetBIOS
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require_relative 'netbios/name'
|
16
|
+
require_relative 'netbios/session'
|
17
|
+
require_relative 'netbios/datagram'
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen-plugin-smb for more informations
|
3
|
+
# Copyright (C) 2016 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
|
+
# Module to group all NetBIOS headers
|
10
|
+
# @author Sylvain Daubert
|
11
|
+
module NetBIOS
|
12
|
+
# NetBIOS Session Service messages.
|
13
|
+
# @author Sylvain Daubert
|
14
|
+
class Datagram < PacketGen::Header::Base
|
15
|
+
# Give protocol name
|
16
|
+
# @return [String]
|
17
|
+
def self.protocol_name
|
18
|
+
'NetBIOS::Datagram'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Port number for NetBIOS Session Service over TCP
|
22
|
+
UDP_PORT = 138
|
23
|
+
|
24
|
+
# Datagram packet types
|
25
|
+
TYPES = {
|
26
|
+
'direct_unique' => 0x10,
|
27
|
+
'direct_group' => 0x11,
|
28
|
+
'broadcast' => 0x12,
|
29
|
+
'error' => 0x13,
|
30
|
+
'query_request' => 0x14,
|
31
|
+
'positive_query_resp' => 0x15,
|
32
|
+
'negative_query_resp' => 0x16,
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
# @!attribute type
|
36
|
+
# 8-bit session packet type
|
37
|
+
# @return [Integer]
|
38
|
+
define_field :type, PacketGen::Types::Int8Enum, enum: TYPES
|
39
|
+
# @!attribute flags
|
40
|
+
# 8-bit flags
|
41
|
+
# @return [Integer]
|
42
|
+
define_field :flags, PacketGen::Types::Int8
|
43
|
+
# @!attribute dgm_id
|
44
|
+
# 16-bit next transaction ID for datagrams
|
45
|
+
# @return [Integer]
|
46
|
+
define_field :dgm_id, PacketGen::Types::Int16
|
47
|
+
# @!attribute src_ip
|
48
|
+
# Source IP address
|
49
|
+
# @return [IP::Addr]
|
50
|
+
define_field :src_ip, PacketGen::Header::IP::Addr
|
51
|
+
# @!attribute src_port
|
52
|
+
# Source port
|
53
|
+
# @return [IP::Addr]
|
54
|
+
define_field :src_port, PacketGen::Types::Int16
|
55
|
+
# @!attribute dgm_length
|
56
|
+
# Length of data + second level of encoded names. Not present in error datagram.
|
57
|
+
# @return [Integer]
|
58
|
+
define_field :dgm_length, PacketGen::Types::Int16, optional: ->(h) { h.type != 0x13 }
|
59
|
+
# @!attribute packet_offset
|
60
|
+
# Not present in error datagram.
|
61
|
+
# @return [Integer]
|
62
|
+
define_field :packet_offset, PacketGen::Types::Int16, optional: ->(h) { h.type != 0x13 }
|
63
|
+
# @!attribute error_code
|
64
|
+
# Error code. Only present in error datagrams.
|
65
|
+
# @return [Integer]
|
66
|
+
define_field :error_code, PacketGen::Types::Int16, optional: ->(h) { h.type == 0x13 }
|
67
|
+
# @!attribute src_name
|
68
|
+
# NetBIOS source name. Only present in direct_unique, direct_group and broadcast datagrams.
|
69
|
+
# @return []
|
70
|
+
define_field :src_name, Name, default: '', optional: ->(h) { (h.type >= 0x10) && (h.type <= 0x12) }
|
71
|
+
# @!attribute dst_name
|
72
|
+
# NetBIOS destination name. Present in all but error datagrams.
|
73
|
+
# @return []
|
74
|
+
define_field :dst_name, Name, default: '', optional: ->(h) { h.type != 0x13 }
|
75
|
+
# @!attribute body
|
76
|
+
# User data. Ony present in direct_unique, direct_group and broadcast datagrams.
|
77
|
+
# @return [String]
|
78
|
+
define_field :body, PacketGen::Types::String, optional: ->(h) { (h.type >= 0x10) && (h.type <= 0x12) }
|
79
|
+
|
80
|
+
# @!attribute :rsv
|
81
|
+
# 4-bit rsv field. 4 upper bits of {#flags}
|
82
|
+
# @return [Integer]
|
83
|
+
# @!attribute :snt
|
84
|
+
# 2-bit SNT (Source end-Node Type) field from {#flags}.
|
85
|
+
# @return [Integer]
|
86
|
+
# @!attribute f
|
87
|
+
# First packet flag. If set then this is first
|
88
|
+
# (and possibly only) fragment of NetBIOS datagram.
|
89
|
+
# @return [Boolean]
|
90
|
+
# @!attribute m
|
91
|
+
# More flag. If set then more NetBIOS datagram
|
92
|
+
# fragments follow.
|
93
|
+
# @return [Boolean]
|
94
|
+
define_bit_fields_on :flags, :rsv, 4, :snt, 2, :f, :m
|
95
|
+
|
96
|
+
# Compute and set {#dgm_length} field
|
97
|
+
# @return [Integer] calculated length
|
98
|
+
def calc_length
|
99
|
+
length = self[:body].sz
|
100
|
+
length += self[:src_name].sz if present?(:src_name)
|
101
|
+
length += self[:dst_name].sz if present?(:dst_name)
|
102
|
+
self.dgm_length = length
|
103
|
+
end
|
104
|
+
end
|
105
|
+
PacketGen::Header.add_class Datagram
|
106
|
+
PacketGen::Header::UDP.bind Datagram, dport: Datagram::UDP_PORT, sport: Datagram::UDP_PORT
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen-plugin-smb for more informations
|
3
|
+
# Copyright (C) 2016 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
|
+
# Module to group all NetBIOS headers
|
10
|
+
# @author Sylvain Daubert
|
11
|
+
module NetBIOS
|
12
|
+
# NetBIOS Name.
|
13
|
+
# @author Sylvain Daubert
|
14
|
+
class Name < PacketGen::Header::DNS::Name
|
15
|
+
# Size, in bytes, of an encoded NetBIOS name
|
16
|
+
ENCODED_NAME_SIZE = 32
|
17
|
+
|
18
|
+
# Read a NetBIOS name from a string
|
19
|
+
# @param [String] str
|
20
|
+
# @return [Name] self
|
21
|
+
def from_human(str)
|
22
|
+
clear
|
23
|
+
return self if str.nil?
|
24
|
+
|
25
|
+
encoded_name = encode_name(str)
|
26
|
+
super(encoded_name)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Get a human readable string
|
30
|
+
# @return [String]
|
31
|
+
def to_human
|
32
|
+
encoded_name = super
|
33
|
+
decode_name(encoded_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def encode_name(name)
|
39
|
+
basename, *scope_id = name.split('.')
|
40
|
+
basename = '' if basename.nil?
|
41
|
+
scope_id = scope_id.join('.')
|
42
|
+
encoded_name = +''
|
43
|
+
basename.each_byte do |byte|
|
44
|
+
a = (byte >> 4) + 0x41
|
45
|
+
b = (byte & 0xf) + 0x41
|
46
|
+
encoded_name << [a, b].pack('C2')
|
47
|
+
end
|
48
|
+
encoded_name << 'CA' * ((ENCODED_NAME_SIZE - encoded_name.size) / 2) if encoded_name.size < ENCODED_NAME_SIZE
|
49
|
+
encoded_name << ".#{scope_id}" if scope_id
|
50
|
+
encoded_name
|
51
|
+
end
|
52
|
+
|
53
|
+
def decode_name(encoded_name)
|
54
|
+
name = +''
|
55
|
+
encoded_name.partition('.').first.scan(/../).map do |duo|
|
56
|
+
a = (duo[0].ord - 0x41) & 0xf
|
57
|
+
b = (duo[1].ord - 0x41) & 0xf
|
58
|
+
name << (a << 4 | b).chr
|
59
|
+
end
|
60
|
+
name.strip
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# This file is part of PacketGen
|
2
|
+
# See https://github.com/sdaubert/packetgen-plugin-smb for more informations
|
3
|
+
# Copyright (C) 2016 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
|
+
# Module to group all NetBIOS headers
|
10
|
+
# @author Sylvain Daubert
|
11
|
+
module NetBIOS
|
12
|
+
# NetBIOS Session Service messages.
|
13
|
+
# @author Sylvain Daubert
|
14
|
+
class Session < PacketGen::Header::Base
|
15
|
+
# Give protocol name
|
16
|
+
# @return [String]
|
17
|
+
def self.protocol_name
|
18
|
+
'NetBIOS::Session'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Port number for NetBIOS Session Service over TCP
|
22
|
+
TCP_PORT = 139
|
23
|
+
# Port number for NetBIOS Session Service over TCP (mainly used yb {SMB2})
|
24
|
+
TCP_PORT2 = 445
|
25
|
+
|
26
|
+
# Session packet types
|
27
|
+
TYPES = {
|
28
|
+
'message' => 0,
|
29
|
+
'request' => 0x81,
|
30
|
+
'positive_response' => 0x82,
|
31
|
+
'negative_response' => 0x83,
|
32
|
+
'retarget_response' => 0x84,
|
33
|
+
'keep_alive' => 0x85,
|
34
|
+
}.freeze
|
35
|
+
|
36
|
+
# @!attribute type
|
37
|
+
# 8-bit session packet type
|
38
|
+
# @return [Integer]
|
39
|
+
define_field :type, PacketGen::Types::Int8Enum, enum: TYPES
|
40
|
+
# @!attribute length
|
41
|
+
# 17-bit session packet length
|
42
|
+
# @return [Integer]
|
43
|
+
define_field :length, PacketGen::Types::Int24
|
44
|
+
# @!attribute body
|
45
|
+
# @return [String]
|
46
|
+
define_field :body, PacketGen::Types::String
|
47
|
+
|
48
|
+
# Compute and set {#length} field
|
49
|
+
# @return [Integer] calculated length
|
50
|
+
def calc_length
|
51
|
+
PacketGen::Header::Base.calculate_and_set_length(self, header_in_size: false)
|
52
|
+
end
|
53
|
+
|
54
|
+
# @api private
|
55
|
+
# @note This method is used internally by PacketGen and should not be
|
56
|
+
# directly called
|
57
|
+
# @since 2.7.0 Set TCP sport according to bindings, only if sport is 0.
|
58
|
+
# Needed by new bind API.
|
59
|
+
def added_to_packet(packet)
|
60
|
+
return unless packet.is? 'TCP'
|
61
|
+
return unless packet.tcp.sport.zero?
|
62
|
+
packet.tcp.sport = TCP_PORT
|
63
|
+
end
|
64
|
+
end
|
65
|
+
PacketGen::Header.add_class Session
|
66
|
+
PacketGen::Header::TCP.bind Session, dport: Session::TCP_PORT
|
67
|
+
PacketGen::Header::TCP.bind Session, sport: Session::TCP_PORT
|
68
|
+
PacketGen::Header::TCP.bind Session, dport: Session::TCP_PORT2
|
69
|
+
PacketGen::Header::TCP.bind Session, sport: Session::TCP_PORT2
|
70
|
+
end
|
71
|
+
end
|
data/lib/packetgen/plugin/smb.rb
CHANGED
@@ -190,8 +190,8 @@ module PacketGen::Plugin
|
|
190
190
|
end
|
191
191
|
end
|
192
192
|
PacketGen::Header.add_class SMB
|
193
|
-
|
194
|
-
|
193
|
+
NetBIOS::Session.bind SMB, body: ->(val) { val.nil? ? SMB::MARKER : val[0..3] == SMB::MARKER }
|
194
|
+
NetBIOS::Datagram.bind SMB, body: ->(val) { val.nil? ? SMB::MARKER : val[0..3] == SMB::MARKER }
|
195
195
|
end
|
196
196
|
|
197
197
|
require_relative 'smb/string'
|
@@ -11,6 +11,12 @@ module PacketGen::Plugin
|
|
11
11
|
# See subclasses.
|
12
12
|
# @author Sylvain Daubert
|
13
13
|
class Browser < PacketGen::Header::Base
|
14
|
+
# Give protocol name for this class
|
15
|
+
# @return [String]
|
16
|
+
def self.protocol_name
|
17
|
+
'SMB::Browser'
|
18
|
+
end
|
19
|
+
|
14
20
|
OPCODES = {
|
15
21
|
'HostAnnouncement' => 1,
|
16
22
|
'HostAnnouncementReq' => 2,
|
@@ -57,12 +63,6 @@ module PacketGen::Plugin
|
|
57
63
|
end
|
58
64
|
end
|
59
65
|
|
60
|
-
# Give protocol name for this class
|
61
|
-
# @return [String]
|
62
|
-
def protocol_name
|
63
|
-
'SMB::Browser'
|
64
|
-
end
|
65
|
-
|
66
66
|
# Callback called when a Browser header is added to a packet.
|
67
67
|
# Here, add +#smb_browser+ method as a shortcut to existing
|
68
68
|
# +#smb_browser_*+ method.
|
@@ -20,11 +20,6 @@ module PacketGen::Plugin
|
|
20
20
|
alias browser_conf_ver_min os_ver_min
|
21
21
|
alias machine_group server_name
|
22
22
|
alias local_master_name comment
|
23
|
-
|
24
|
-
# @return [String]
|
25
|
-
def protocol_name
|
26
|
-
'SMB::Browser::DomainAnnouncement'
|
27
|
-
end
|
28
23
|
end
|
29
24
|
PacketGen::Header.add_class DomainAnnouncement
|
30
25
|
SMB::Trans::Request.bind DomainAnnouncement, name: '\\MAILSLOT\\BROWSE', body: ->(v) { v[0] == OPCODES['DomainAnnouncement'] }
|
@@ -14,6 +14,14 @@ module PacketGen::Plugin
|
|
14
14
|
# specify the types of resources and services it supports.
|
15
15
|
# @author Sylvain Daubert
|
16
16
|
class HostAnnouncement < Browser
|
17
|
+
# @return [String]
|
18
|
+
def self.protocol_name
|
19
|
+
return @protocol_name if @protocol_name
|
20
|
+
|
21
|
+
basename = to_s.sub(/^.*::/, '')
|
22
|
+
@protocol_name = "SMB::Browser::#{basename}"
|
23
|
+
end
|
24
|
+
|
17
25
|
remove_field :body
|
18
26
|
update_field :opcode, default: 1
|
19
27
|
# @!attribute update_count
|
@@ -58,11 +66,6 @@ module PacketGen::Plugin
|
|
58
66
|
# Null-terminated ASCII string.
|
59
67
|
# @return [String]
|
60
68
|
define_field :comment, PacketGen::Types::CString
|
61
|
-
|
62
|
-
# @return [String]
|
63
|
-
def protocol_name
|
64
|
-
'SMB::Browser::HostAnnouncement'
|
65
|
-
end
|
66
69
|
end
|
67
70
|
PacketGen::Header.add_class HostAnnouncement
|
68
71
|
SMB::Trans::Request.bind HostAnnouncement, name: '\\MAILSLOT\\BROWSE', body: ->(v) { v[0] == OPCODES['HostAnnouncement'] }
|
@@ -15,11 +15,6 @@ module PacketGen::Plugin
|
|
15
15
|
# @author Sylvain Daubert
|
16
16
|
class LocalMasterAnnouncement < HostAnnouncement
|
17
17
|
update_field :opcode, default: 15
|
18
|
-
|
19
|
-
# @return [String]
|
20
|
-
def protocol_name
|
21
|
-
'SMB::Browser::LocalMasterAnnouncement'
|
22
|
-
end
|
23
18
|
end
|
24
19
|
PacketGen::Header.add_class LocalMasterAnnouncement
|
25
20
|
SMB::Trans::Request.bind LocalMasterAnnouncement, name: '\\MAILSLOT\\BROWSE', body: ->(v) { v[0] == OPCODES['LocalMasterAnnouncement'] }
|
@@ -17,6 +17,11 @@ module PacketGen::Plugin
|
|
17
17
|
# Numbers of 100ns in one second
|
18
18
|
ONE_SEC = 10_000_000
|
19
19
|
|
20
|
+
# String to format time
|
21
|
+
FORMAT_TIME_STR = '%Y-%m-%d %H:%M:%S.%9N %Z'
|
22
|
+
# String to parse time
|
23
|
+
PARSE_TIME_STR = '%Y-%m-%d %H:%M:%S.%N %Z'
|
24
|
+
|
20
25
|
# @param [Hash] options
|
21
26
|
# @option options [Integer] :filetime
|
22
27
|
# @option options [Time] :time
|
@@ -49,10 +54,24 @@ module PacketGen::Plugin
|
|
49
54
|
if no_time?
|
50
55
|
'no time'
|
51
56
|
else
|
52
|
-
@time.strftime(
|
57
|
+
@time.strftime(FORMAT_TIME_STR)
|
53
58
|
end
|
54
59
|
end
|
55
60
|
|
61
|
+
# @return [self]
|
62
|
+
def from_human(str)
|
63
|
+
return self if str.nil?
|
64
|
+
|
65
|
+
@time = if str == 'no time'
|
66
|
+
Time.at(NO_TIME)
|
67
|
+
else
|
68
|
+
DateTime.strptime(str, PARSE_TIME_STR).to_time
|
69
|
+
end
|
70
|
+
@int.value = time2filetime
|
71
|
+
|
72
|
+
self
|
73
|
+
end
|
74
|
+
|
56
75
|
# Get filetime integer value
|
57
76
|
# @return [Integer]
|
58
77
|
def to_i
|
@@ -148,6 +148,12 @@ module PacketGen::Plugin
|
|
148
148
|
self.bind kresponse, command: SMB2::COMMANDS[command], flags: ->(v) { v.nil? ? 0 : (v & 1 == 1) }
|
149
149
|
end
|
150
150
|
|
151
|
+
# Invert {#flags_response?}
|
152
|
+
# @return [self]
|
153
|
+
def reply!
|
154
|
+
self.flags_response = !flags_response?
|
155
|
+
end
|
156
|
+
|
151
157
|
# @return [String]
|
152
158
|
def inspect
|
153
159
|
super do |attr|
|
@@ -166,13 +172,9 @@ module PacketGen::Plugin
|
|
166
172
|
end
|
167
173
|
end
|
168
174
|
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
175
|
|
173
176
|
PacketGen::Header.add_class SMB2
|
174
|
-
|
175
|
-
PacketGen::Header::NetBIOS::Datagram.bind SMB2, body: ->(val) { val.nil? ? SMB2::MARKER : val[0..3] == SMB2::MARKER }
|
177
|
+
NetBIOS::Session.bind SMB2, body: ->(val) { val.nil? ? SMB2::MARKER : val[0..3] == SMB2::MARKER }
|
176
178
|
end
|
177
179
|
|
178
180
|
require_relative 'smb2/base'
|
@@ -47,31 +47,11 @@ module PacketGen::Plugin
|
|
47
47
|
# @!attribute pad
|
48
48
|
# Padding to align next context on a 8-byte offset
|
49
49
|
# @return [String]
|
50
|
-
define_field :pad, PacketGen::Types::String, builder: ->(h, t) { t.new(length_from: -> {
|
50
|
+
define_field :pad, PacketGen::Types::String, builder: ->(h, t) { t.new(length_from: -> { (8 - (h.offset_of(:data) + h.data_length) % 8) % 8 }) }
|
51
51
|
|
52
52
|
# @private
|
53
53
|
alias old_read read
|
54
54
|
|
55
|
-
# Populate object from a binary string
|
56
|
-
# @param [String] str
|
57
|
-
# @return [Context]
|
58
|
-
def read(str)
|
59
|
-
return self if str.nil?
|
60
|
-
if self.instance_of? Context
|
61
|
-
self[:type].read str[0, 2]
|
62
|
-
name = TYPES.key(type)
|
63
|
-
return old_read(str) if name.nil?
|
64
|
-
|
65
|
-
klassname = name.downcase.capitalize.gsub(/_(\w)/) { $1.upcase }
|
66
|
-
return old_read(str) unless Negotiate.const_defined? klassname
|
67
|
-
|
68
|
-
klass = Negotiate.const_get(klassname)
|
69
|
-
klass.new.read str
|
70
|
-
else
|
71
|
-
old_read str
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
55
|
# Get human-readable type
|
76
56
|
# @return [String]
|
77
57
|
def human_type
|
@@ -104,7 +84,7 @@ module PacketGen::Plugin
|
|
104
84
|
# Salt value for hash
|
105
85
|
# @return [String]
|
106
86
|
define_field_before :pad, :salt, PacketGen::Types::String, builder: ->(h, t) { t.new(length_from: h[:salt_length]) }
|
107
|
-
update_field :pad, builder: ->(h, t) { t.new(length_from: -> {
|
87
|
+
update_field :pad, builder: ->(h, t) { t.new(length_from: -> { (8 - (h.offset_of(:salt) + h.salt_length) % 8) % 8 }) }
|
108
88
|
end
|
109
89
|
|
110
90
|
class EncryptionCap < Context
|
@@ -118,14 +98,22 @@ module PacketGen::Plugin
|
|
118
98
|
# algorithms
|
119
99
|
# @return [PacketGen::Types::ArrayOfInt16le]
|
120
100
|
define_field_before :pad, :ciphers, PacketGen::Types::ArrayOfInt16le, builder: ->(h, t) { t.new(counter: h[:hash_alg_count]) }
|
121
|
-
update_field :pad, builder: ->(h, t) { t.new(length_from: -> {
|
101
|
+
update_field :pad, builder: ->(h, t) { t.new(length_from: -> { (8 - (h.offset_of(:cipher_count) + h[:cipher_count].sz) % 8) % 8 }) }
|
122
102
|
end
|
123
103
|
|
124
104
|
# Array of {Context}
|
125
105
|
# @author Sylvain Daubert
|
126
106
|
class ArrayOfContext < PacketGen::Types::Array
|
127
107
|
set_of Context
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def real_type(ctx)
|
112
|
+
name = Context::TYPES.key(ctx.type)
|
113
|
+
klassname = name.downcase.capitalize.gsub(/_(\w)/) { $1.upcase }
|
114
|
+
Negotiate.const_defined?(klassname) ? Negotiate.const_get(klassname) : ctx.class
|
115
|
+
end
|
128
116
|
end
|
129
117
|
end
|
130
118
|
end
|
131
|
-
end
|
119
|
+
end
|
@@ -124,6 +124,12 @@ module PacketGen::Plugin
|
|
124
124
|
# @return [ArrayOfContext]
|
125
125
|
define_field :context_list, ArrayOfContext, builder: ->(h, t) { t.new(counter: h[:context_count]) }
|
126
126
|
|
127
|
+
# Protocol name
|
128
|
+
# @return [String]
|
129
|
+
def self.protocol_name
|
130
|
+
'SMB2::Negotiate::Request'
|
131
|
+
end
|
132
|
+
|
127
133
|
# @return [String]
|
128
134
|
def inspect
|
129
135
|
super do |attr|
|
@@ -154,12 +160,6 @@ module PacketGen::Plugin
|
|
154
160
|
def calc_length
|
155
161
|
self.context_offset = SMB2.new.sz + offset_of(:context_list)
|
156
162
|
end
|
157
|
-
|
158
|
-
# Protocol name
|
159
|
-
# @return [String]
|
160
|
-
def protocol_name
|
161
|
-
'SMB2::Negotiate::Request'
|
162
|
-
end
|
163
163
|
end
|
164
164
|
end
|
165
165
|
end
|
@@ -152,10 +152,17 @@ module PacketGen::Plugin
|
|
152
152
|
# @return [ArrayOfContext]
|
153
153
|
define_field :context_list, ArrayOfContext, builder: ->(h, t) { t.new(counter: h[:context_count]) }
|
154
154
|
|
155
|
+
# Protocol name
|
156
|
+
# @return [String]
|
157
|
+
def self.protocol_name
|
158
|
+
'SMB2::Negotiate::Response'
|
159
|
+
end
|
160
|
+
|
155
161
|
# @return [String]
|
156
162
|
def inspect
|
157
163
|
super do |attr|
|
158
164
|
next unless attr == :capabilities
|
165
|
+
|
159
166
|
value = bits_on(attr).reject { |_, v| v > 1 }
|
160
167
|
.keys
|
161
168
|
.select { |b| send("#{b}?") }
|
@@ -178,12 +185,6 @@ module PacketGen::Plugin
|
|
178
185
|
self.buffer_length = buffer.sz
|
179
186
|
context_list.each { |ctx| ctx.calc_length if ctx.respond_to? :calc_length }
|
180
187
|
end
|
181
|
-
|
182
|
-
# Protocol name
|
183
|
-
# @return [String]
|
184
|
-
def protocol_name
|
185
|
-
'SMB2::Negotiate::Response'
|
186
|
-
end
|
187
188
|
end
|
188
189
|
end
|
189
190
|
end
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
|
20
20
|
spec.required_ruby_version = '>= 2.3.0'
|
21
21
|
|
22
|
-
spec.add_dependency 'packetgen', '~>
|
22
|
+
spec.add_dependency 'packetgen', '~>3.0'
|
23
23
|
spec.add_dependency 'rasn1', '~>0.6', '>= 0.6.7'
|
24
24
|
|
25
25
|
spec.add_development_dependency 'bundler', '~> 1.16'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: packetgen-plugin-smb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sylvain Daubert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-10-
|
11
|
+
date: 2018-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: packetgen
|
@@ -16,20 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
- - ">="
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 2.8.7
|
19
|
+
version: '3.0'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - "~>"
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
30
|
-
- - ">="
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 2.8.7
|
26
|
+
version: '3.0'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: rasn1
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +130,10 @@ files:
|
|
136
130
|
- Rakefile
|
137
131
|
- lib/packetgen-plugin-smb.rb
|
138
132
|
- lib/packetgen/plugin/gssapi.rb
|
133
|
+
- lib/packetgen/plugin/netbios.rb
|
134
|
+
- lib/packetgen/plugin/netbios/datagram.rb
|
135
|
+
- lib/packetgen/plugin/netbios/name.rb
|
136
|
+
- lib/packetgen/plugin/netbios/session.rb
|
139
137
|
- lib/packetgen/plugin/smb.rb
|
140
138
|
- lib/packetgen/plugin/smb/blocks.rb
|
141
139
|
- lib/packetgen/plugin/smb/browser.rb
|