packetgen-plugin-smb 0.3.0 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/specs.yml +28 -0
  3. data/.rubocop.yml +8 -1
  4. data/Gemfile +15 -3
  5. data/README.md +59 -3
  6. data/Rakefile +10 -4
  7. data/examples/llmnr-responder +110 -0
  8. data/examples/smb-responder +233 -0
  9. data/lib/packetgen-plugin-smb.rb +5 -2
  10. data/lib/packetgen/plugin/gssapi.rb +11 -6
  11. data/lib/packetgen/plugin/llmnr.rb +58 -0
  12. data/lib/packetgen/plugin/netbios.rb +19 -0
  13. data/lib/packetgen/plugin/netbios/datagram.rb +108 -0
  14. data/lib/packetgen/plugin/netbios/name.rb +64 -0
  15. data/lib/packetgen/plugin/netbios/session.rb +72 -0
  16. data/lib/packetgen/plugin/ntlm.rb +211 -0
  17. data/lib/packetgen/plugin/ntlm/authenticate.rb +197 -0
  18. data/lib/packetgen/plugin/ntlm/av_pair.rb +115 -0
  19. data/lib/packetgen/plugin/ntlm/challenge.rb +140 -0
  20. data/lib/packetgen/plugin/ntlm/negotiate.rb +127 -0
  21. data/lib/packetgen/plugin/ntlm/ntlmv2_response.rb +59 -0
  22. data/lib/packetgen/plugin/smb.rb +27 -15
  23. data/lib/packetgen/plugin/smb/blocks.rb +2 -4
  24. data/lib/packetgen/plugin/smb/browser.rb +8 -8
  25. data/lib/packetgen/plugin/smb/browser/domain_announcement.rb +2 -7
  26. data/lib/packetgen/plugin/smb/browser/host_announcement.rb +10 -7
  27. data/lib/packetgen/plugin/smb/browser/local_master_announcement.rb +2 -7
  28. data/lib/packetgen/plugin/smb/close.rb +2 -2
  29. data/lib/packetgen/plugin/smb/close/request.rb +3 -3
  30. data/lib/packetgen/plugin/smb/close/response.rb +3 -3
  31. data/lib/packetgen/plugin/smb/filetime.rb +30 -3
  32. data/lib/packetgen/plugin/smb/negotiate.rb +20 -0
  33. data/lib/packetgen/plugin/smb/negotiate/dialect.rb +39 -0
  34. data/lib/packetgen/plugin/smb/negotiate/request.rb +35 -0
  35. data/lib/packetgen/plugin/smb/negotiate/response.rb +29 -0
  36. data/lib/packetgen/plugin/smb/nt_create_and_x.rb +2 -2
  37. data/lib/packetgen/plugin/smb/ntcreateandx/request.rb +5 -5
  38. data/lib/packetgen/plugin/smb/ntcreateandx/response.rb +3 -3
  39. data/lib/packetgen/plugin/smb/string.rb +60 -23
  40. data/lib/packetgen/plugin/smb/trans.rb +2 -2
  41. data/lib/packetgen/plugin/smb/trans/request.rb +4 -4
  42. data/lib/packetgen/plugin/smb/trans/response.rb +3 -3
  43. data/lib/packetgen/plugin/smb2.rb +20 -9
  44. data/lib/packetgen/plugin/smb2/base.rb +5 -7
  45. data/lib/packetgen/plugin/smb2/error.rb +3 -4
  46. data/lib/packetgen/plugin/smb2/guid.rb +6 -4
  47. data/lib/packetgen/plugin/smb2/negotiate.rb +2 -2
  48. data/lib/packetgen/plugin/smb2/negotiate/context.rb +28 -27
  49. data/lib/packetgen/plugin/smb2/negotiate/request.rb +16 -12
  50. data/lib/packetgen/plugin/smb2/negotiate/response.rb +25 -14
  51. data/lib/packetgen/plugin/smb2/session_setup.rb +2 -2
  52. data/lib/packetgen/plugin/smb2/session_setup/request.rb +12 -7
  53. data/lib/packetgen/plugin/smb2/session_setup/response.rb +13 -8
  54. data/lib/packetgen/plugin/smb_version.rb +3 -1
  55. data/packetgen-plugin-smb.gemspec +10 -15
  56. metadata +28 -81
  57. data/.travis.yml +0 -12
@@ -1,15 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of packetgen-plugin-smb.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
5
  # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen::Plugin
9
9
  class SMB
10
10
  # SMB FILETIME.
11
11
  # @author Sylvain Daubert
12
12
  class Filetime
13
+ include PacketGen::Types::Fieldable
14
+
13
15
  # Base time for SMB FILETIME.
14
16
  # This value also indicate no time.
15
17
  NO_TIME = Time.utc(1601).freeze
@@ -17,6 +19,17 @@ module PacketGen::Plugin
17
19
  # Numbers of 100ns in one second
18
20
  ONE_SEC = 10_000_000
19
21
 
22
+ # String to format time
23
+ FORMAT_TIME_STR = '%Y-%m-%d %H:%M:%S.%9N %Z'
24
+ # String to parse time
25
+ PARSE_TIME_STR = '%Y-%m-%d %H:%M:%S.%N %Z'
26
+
27
+ # Return a new Filetime object initialized to current time.
28
+ # @return [Filetime]
29
+ def self.now
30
+ new(time: Time.now.utc)
31
+ end
32
+
20
33
  # @param [Hash] options
21
34
  # @option options [Integer] :filetime
22
35
  # @option options [Time] :time
@@ -49,10 +62,24 @@ module PacketGen::Plugin
49
62
  if no_time?
50
63
  'no time'
51
64
  else
52
- @time.strftime("%Y-%m-%d %H:%M:%S.%9N %Z")
65
+ @time.strftime(FORMAT_TIME_STR)
53
66
  end
54
67
  end
55
68
 
69
+ # @return [self]
70
+ def from_human(str)
71
+ return self if str.nil?
72
+
73
+ @time = if str == 'no time'
74
+ Time.at(NO_TIME)
75
+ else
76
+ DateTime.strptime(str, PARSE_TIME_STR).to_time
77
+ end
78
+ @int.value = time2filetime
79
+
80
+ self
81
+ end
82
+
56
83
  # Get filetime integer value
57
84
  # @return [Integer]
58
85
  def to_i
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of packetgen-plugin-smb.
4
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
5
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
6
+ # This program is published under MIT license.
7
+
8
+ module PacketGen::Plugin
9
+ class SMB
10
+ # Namespace for NEGOTIATE related classes
11
+ # @author Sylvain Daubert
12
+ module Negotiate; end
13
+ end
14
+ end
15
+
16
+ require_relative 'negotiate/dialect'
17
+ require_relative 'negotiate/request'
18
+ require_relative 'negotiate/response'
19
+
20
+ PacketGen::Plugin::SMB.bind_command 'negotiate'
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of packetgen-plugin-smb.
4
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
5
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
6
+ # This program is published under MIT license.
7
+
8
+ module PacketGen::Plugin
9
+ class SMB
10
+ module Negotiate
11
+ # A SMB_Dialect struct containing:
12
+ # * a 8-bit {#format} field, which should be set to 0x02,
13
+ # * a null-terminated string identifying a SMB dialect.
14
+ # @author Sylvain Daubert
15
+ class Dialect < PacketGen::Types::Fields
16
+ # @!attribute format
17
+ # 8-bit format. Should be +2+ to indicate a null-terminated string for
18
+ # {#dialect} field.
19
+ # @return [Integer]
20
+ define_field :format, PacketGen::Types::Int8, default: 2
21
+ # @!attribute dialect
22
+ # Null-terminated string identifying a SMB dialect.
23
+ # @return [String]
24
+ define_field :dialect,PacketGen::Types::CString
25
+
26
+ # @return [String]
27
+ def to_human
28
+ self[:dialect].to_human
29
+ end
30
+ end
31
+
32
+ # Specialized {PacketGen::Types::Array} to embed {Dialect Dialects}.
33
+ # @author Sylvain Daubert
34
+ class ArrayOfDialect < PacketGen::Types::Array
35
+ set_of Dialect
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of packetgen-plugin-smb.
4
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
5
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
6
+ # This program is published under MIT license.
7
+
8
+ module PacketGen::Plugin
9
+ class SMB
10
+ module Negotiate
11
+ # SMB Negotiation Request header.
12
+ #
13
+ # See also {Blocks}, as {Negotiate::Request} is a specialization of {Blocks#words}
14
+ # and {Blocks#bytes}.
15
+ # @author Sylvain Daubert
16
+ class Request < PacketGen::Header::Base
17
+ # @!attribute word_count
18
+ # The size, in 2-byte words, of the SMB command parameters. It should
19
+ # be +0+ setup_count+.
20
+ # @return [Integer]
21
+ define_field :word_count, PacketGen::Types::Int8, default: 0
22
+ # @!attribute byte_count
23
+ # @return [Integer]
24
+ define_field :byte_count, PacketGen::Types::Int16le
25
+ # @!attribute dialects
26
+ # @return [ArrayOfDialect]
27
+ define_field :dialects, ArrayOfDialect
28
+
29
+ def self.protocol_name
30
+ 'SMB::Negotiate::Request'
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of packetgen-plugin-smb.
4
+ # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
5
+ # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
6
+ # This program is published under MIT license.
7
+
8
+ module PacketGen::Plugin
9
+ class SMB
10
+ module Negotiate
11
+ # SMB Negotiation Response header.
12
+ #
13
+ # See also {Blocks}, as {Negotiate::Response} is a specialization of {Blocks#words}
14
+ # and {Blocks#bytes}.
15
+ # @author Sylvain Daubert
16
+ class Response < Blocks
17
+ # Get index of the dialect selected by the server from the list presented in the request.
18
+ # @return [Integer]
19
+ def dialect_index
20
+ words.first.to_i
21
+ end
22
+
23
+ def self.protocol_name
24
+ 'SMB::Negotiate::Response'
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of packetgen-plugin-smb.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
5
  # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen::Plugin
9
9
  class SMB
10
10
  # Namespace for NT_CREATE_ANDX related classes
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of packetgen-plugin-smb.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
5
  # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen::Plugin
9
9
  class SMB
10
10
  # Namespace for NT_CREATE_ANDX related classes
@@ -128,7 +128,7 @@ module PacketGen::Plugin
128
128
  # Padding before {#filename} to align it on 16-bit boundary. Only present
129
129
  # if {SMB#flags2_unicode?} is +true+.
130
130
  # @return [Integer]
131
- define_field :pad1, PacketGen::Types::Int8, optional: ->(h) { h.packet && h.packet.smb.flags2_unicode? }
131
+ define_field :pad1, PacketGen::Types::Int8, optional: ->(h) { h&.packet&.smb&.flags2_unicode? }
132
132
  # @!attribute filename
133
133
  # A string that represents the fully qualified name of the file
134
134
  # relative to the supplied TID
@@ -141,7 +141,7 @@ module PacketGen::Plugin
141
141
 
142
142
  # Give protocol name for this class
143
143
  # @return [String]
144
- def protocol_name
144
+ def self.protocol_name
145
145
  'SMB::NtCreateAndX::Request'
146
146
  end
147
147
 
@@ -154,6 +154,6 @@ module PacketGen::Plugin
154
154
  self.byte_count = bcount
155
155
  end
156
156
  end
157
- end
157
+ end
158
158
  end
159
159
  end
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of packetgen-plugin-smb.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
5
  # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen::Plugin
9
9
  class SMB
10
10
  # Namespace for NT_CREATE_ANDX related classes
@@ -101,7 +101,7 @@ module PacketGen::Plugin
101
101
 
102
102
  # Give protocol name for this class
103
103
  # @return [String]
104
- def protocol_name
104
+ def self.protocol_name
105
105
  'SMB::NtCreateAndX::Response'
106
106
  end
107
107
 
@@ -1,28 +1,39 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of packetgen-plugin-smb.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
5
  # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
8
+ require 'forwardable'
7
9
 
8
10
  module PacketGen::Plugin
9
11
  class SMB
10
- # SMB strings (UTF-16 little-endian).
12
+ # SMB strings (UTF-16 little-endian or OEM).
11
13
  # @author Sylvain Daubert
12
- class String < PacketGen::Types::CString
13
- # @param [Boolean] value
14
+ class String
15
+ extend Forwardable
16
+ include PacketGen::Types::Fieldable
17
+
18
+ def_delegators :@string, :[], :length, :size, :inspect, :==, :<<,
19
+ :unpack, :force_encoding, :encoding, :index, :empty?,
20
+ :encode
21
+
22
+ # @return [::String]
23
+ attr_reader :string
24
+ # @param [Boolean] null_terminated
14
25
  # @return [Boolean]
15
- attr_writer :unicode
26
+ attr_writer :null_terminated
16
27
 
17
28
  # @param [Hash] options
18
- # @option options [Integer] :static_length set a static length for this string
19
29
  # @option options [Boolean] :unicode If +true+, string is encoded as a UTF-16
20
30
  # unicode string. If +false+, string is encode in ASCII. Defaults to +true+.
31
+ # @option options [Boolean] :null_terminated If +true+, string is null-terminated.
32
+ # If +false+, string is not null-terminated. Defaults to +true+.
21
33
  def initialize(options={})
22
- super
23
34
  @unicode = options.key?(:unicode) ? options[:unicode] : true
24
- self.encode!('UTF-16LE') if @unicode
25
- self.encode!('ASCII-8BIT') unless @unicode
35
+ @null_terminated = options.key?(:null_terminated) ? options[:null_terminated] : true
36
+ @string = +''.encode(self_encoding)
26
37
  end
27
38
 
28
39
  # @return [Boolean]
@@ -30,6 +41,19 @@ module PacketGen::Plugin
30
41
  @unicode
31
42
  end
32
43
 
44
+ # @param [Boolean] bool
45
+ # @return [Boolean]
46
+ def unicode=(bool)
47
+ @unicode = bool
48
+ @string.force_encoding(self_encoding)
49
+ bool
50
+ end
51
+
52
+ # @return [Boolean]
53
+ def null_terminated?
54
+ @null_terminated
55
+ end
56
+
33
57
  # @param [::String] str
34
58
  # @return [String] self
35
59
  def read(str)
@@ -37,34 +61,47 @@ module PacketGen::Plugin
37
61
 
38
62
  str2 = case str.encoding
39
63
  when Encoding::BINARY
40
- binidx = nil
41
- 0.step(to: str.size, by: 2) do |i|
42
- binidx = i if str[i, 2] == binary_terminator
43
- end
44
- s = if binidx.nil?
45
- str
46
- else
47
- str[0, binidx]
48
- end
49
- s.force_encoding(self_encoding)
64
+ str.dup.force_encoding(self_encoding)
50
65
  else
51
66
  str.encode(self_encoding)
52
67
  end
53
- str2 = str2[0, @static_length / 2] if @static_length.is_a? Integer
54
68
  idx = str2.index(+"\x00".encode(self_encoding))
55
69
  str2 = str2[0, idx] unless idx.nil?
56
- self.replace str2
70
+ @string = str2
57
71
  self
58
72
  end
59
73
 
74
+ # @return [String]
75
+ def to_s
76
+ str = string.dup.force_encoding('BINARY')
77
+ return str unless null_terminated?
78
+
79
+ str << binary_terminator.force_encoding('BINARY')
80
+ end
81
+
82
+ # Populate String from a human readable (ie UTF-8) string
83
+ # @param [String] str
84
+ # @return [self]
85
+ def from_human(str)
86
+ return self if str.nil?
87
+
88
+ @string = str.encode(self_encoding)
89
+ self
90
+ end
91
+
92
+ # @return [String]
93
+ def to_human
94
+ string.encode('UTF-8')
95
+ end
96
+
60
97
  private
61
98
 
62
99
  def self_encoding
63
- @unicode ? Encoding::UTF_16LE : Encoding:: ASCII_8BIT
100
+ @unicode ? Encoding::UTF_16LE : Encoding::ASCII_8BIT
64
101
  end
65
102
 
66
103
  def binary_terminator
67
- @unicode ? "\x00\x00" : "\x00"
104
+ [0].pack('C').encode(self_encoding)
68
105
  end
69
106
  end
70
107
  end
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of packetgen-plugin-smb.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
5
  # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen::Plugin
9
9
  class SMB
10
10
  # Namespace for TRANS related classes
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of packetgen-plugin-smb.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
5
  # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen::Plugin
9
9
  class SMB
10
10
  module Trans
@@ -96,7 +96,7 @@ module PacketGen::Plugin
96
96
  # 8-bit optional padding to align {#name} on a 2-byte boundary. Only present
97
97
  # if {SMB#flags2_unicode?} is +true+.
98
98
  # @return [Integer]
99
- define_field :padname, PacketGen::Types::Int8, optional: ->(h) { h.packet && h.packet.smb.flags2_unicode? }
99
+ define_field :padname, PacketGen::Types::Int8, optional: ->(h) { h&.packet&.smb&.flags2_unicode? }
100
100
  # @!attribute name
101
101
  # Pathname of the mailslot or named pipe.
102
102
  # @return [String]
@@ -112,7 +112,7 @@ module PacketGen::Plugin
112
112
 
113
113
  # Give protocol name for this class
114
114
  # @return [String]
115
- def protocol_name
115
+ def self.protocol_name
116
116
  'SMB::Trans::Request'
117
117
  end
118
118
  end
@@ -1,10 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file is part of packetgen-plugin-smb.
2
4
  # See https://github.com/sdaubert/packetgen-plugin-smb for more informations
3
5
  # Copyright (C) 2018 Sylvain Daubert <sylvain.daubert@laposte.net>
4
6
  # This program is published under MIT license.
5
7
 
6
- # frozen_string_literal: true
7
-
8
8
  module PacketGen::Plugin
9
9
  class SMB
10
10
  module Trans
@@ -85,7 +85,7 @@ module PacketGen::Plugin
85
85
 
86
86
  # Give protocol name for this class
87
87
  # @return [String]
88
- def protocol_name
88
+ def self.protocol_name
89
89
  'SMB::Trans::Response'
90
90
  end
91
91
  end