packetgen-plugin-smb 0.3.0 → 0.6.2

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 (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
@@ -0,0 +1,197 @@
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 NTLM
10
+ # NTLM Challenge message
11
+ # @author Sylvain Daubert
12
+ class Authenticate < NTLM
13
+ # void MIC
14
+ VOID_MIC = ([0] * 16).pack('C').freeze
15
+
16
+ update_field :type, default: NTLM::TYPES['authenticate']
17
+
18
+ # @!attribute lm_response
19
+ # A LM_RESPONSE or LMV2_RESPONSE structure that contains the computed
20
+ # LM response to the challenge.
21
+ # @return [PacketGen::Types::String]
22
+ # @!attribute lm_response_len
23
+ # 16-bit unsigned integer that defines the size in bytes of
24
+ # {#lm_response} in {#payload}.
25
+ # @return [Integer]
26
+ # @!attribute lm_response_maxlen
27
+ # 16-bit unsigned integer that should be equal to {#lm_response_len}.
28
+ # @return [Integer]
29
+ # @!attribute lm_response_offset
30
+ # A 32-bit unsigned integer that defines the offset, in bytes, from
31
+ # the beginning of the AUTHENTICATE MESSAGE to {#lm_response} in {#payload}.
32
+ # @return [Integer]
33
+ define_in_payload :lm_response, PacketGen::Types::String
34
+
35
+ # @!attribute nt_response
36
+ # A NTLM_RESPONSE or NTLMV2_RESPONSE structure that contains the computed
37
+ # NT response to the challenge.
38
+ # @return [Ntlmv2Response]
39
+ # @!attribute nt_response_len
40
+ # 16-bit unsigned integer that defines the size in bytes of
41
+ # {#nt_response} in {#payload}.
42
+ # @return [Integer]
43
+ # @!attribute nt_response_maxlen
44
+ # 16-bit unsigned integer that should be equal to {#nt_response_len}.
45
+ # @return [Integer]
46
+ # @!attribute nt_response_offset
47
+ # A 32-bit unsigned integer that defines the offset, in bytes, from
48
+ # the beginning of the AUTHENTICATE MESSAGE to {#nt_response} in {#payload}.
49
+ # @return [Integer]
50
+ define_in_payload :nt_response, Ntlmv2Response
51
+
52
+ # @!attribute domain_name
53
+ # Name of the client authentication domain.
54
+ # @return [SMB::String]
55
+ # @!attribute domain_name_len
56
+ # 2-byte {#domain_name} length
57
+ # @return [Integer]
58
+ # @!attribute domain_name_maxlen
59
+ # 2-byte {#domain_name} max length. Should be equal to {#domain_name_len}.
60
+ # @return [Integer]
61
+ # @!attribute domain_name_offset
62
+ # 4-byte {#domain_name} offset from the beginning of the AUTHENTICATE
63
+ # MESSAGE in {#payload}
64
+ # @return [Integer]
65
+ define_in_payload :domain_name, SMB::String, null_terminated: false
66
+
67
+ # @!attribute user_name
68
+ # Name of the user to be authenticated.
69
+ # @return [SMB::String]
70
+ # @!attribute user_name_len
71
+ # 2-byte {#user_name} length
72
+ # @return [Integer]
73
+ # @!attribute user_name_maxlen
74
+ # 2-byte {#user_name} max length. Should be equal to {#user_name_len}.
75
+ # @return [Integer]
76
+ # @!attribute user_name_offset
77
+ # 4-byte {#user_name} offset from the beginning of the AUTHENTICATE
78
+ # MESSAGE in {#payload}
79
+ # @return [Integer]
80
+ define_in_payload :user_name, SMB::String, null_terminated: false
81
+
82
+ # @!attribute workstation
83
+ # Name of the client machine.
84
+ # @return [SMB::String]
85
+ # @!attribute workstation_len
86
+ # 2-byte {#workstation} length
87
+ # @return [Integer]
88
+ # @!attribute workstation_maxlen
89
+ # 2-byte {#workstation} max length. Should be equal to {#workstation_len}.
90
+ # @return [Integer]
91
+ # @!attribute workstation_offset
92
+ # 4-byte {#workstation} offset from the beginning of the AUTHENTICATE
93
+ # MESSAGE in {#payload}
94
+ # @return [Integer]
95
+ define_in_payload :workstation, SMB::String, null_terminated: false
96
+
97
+ # @!attribute session_key
98
+ # The client's encrypted random session key. On
99
+ # @return [PacketGen::Types::String]
100
+ # @!attribute session_key_len
101
+ # 2-byte {#session_key} length
102
+ # @return [Integer]
103
+ # @!attribute session_key_maxlen
104
+ # 2-byte {#session_key} max length. Should be equal to {#session_key_len}.
105
+ # @return [Integer]
106
+ # @!attribute session_key_offset
107
+ # 4-byte {#session_key} offset from the beginning of the AUTHENTICATE
108
+ # MESSAGE in {#payload}.
109
+ # @return [Integer]
110
+ define_in_payload :session_key, PacketGen::Types::String
111
+
112
+ # @!attribute flags
113
+ # Negotiate flags
114
+ # @return [Integer]
115
+
116
+ # @!group Negotiate flags
117
+ # @!attribute nego56?
118
+ # Also known as +flags_w?+.
119
+ # @return [Boolean]
120
+ # @!attribute key_exch?
121
+ # Also known as +flags_v?+
122
+ # @return [Boolean]
123
+ # @!attribute nego128?
124
+ # Also known as +flags_u?+
125
+ # @return [Boolean]
126
+ # @!attribute version?
127
+ # Also known as +flags_t+
128
+ # @return [Integer]
129
+ # @!attribute target_info?
130
+ # Also known as +flags_s?+
131
+ # @return [Boolean]
132
+ # @!attribute non_nt_session_key?
133
+ # Also known as +flags_r?+
134
+ # @return [Boolean]
135
+ # @!attribute identify?
136
+ # Also known as +flags_q+
137
+ # @return [Boolean]
138
+ # @!attribute ext_session_security?
139
+ # Also known as +flags_p?+
140
+ # @return [Boolean]
141
+ # @!attribute target_type_server?
142
+ # Also known as +flags_o?+
143
+ # @return [Boolean]
144
+ # @!attribute target_type_domain?
145
+ # Also known as +flags_n?+
146
+ # @return [Boolean]
147
+ # @!attribute always_sign?
148
+ # Also known as +flags_m?+
149
+ # @return [Boolean]
150
+ # @!attribute oem_target_info_supplied?
151
+ # Also known as +flags_l?+
152
+ # @return [Boolean]
153
+ # @!attribute oem_domain_supplied?
154
+ # Also known as +flags_k?+
155
+ # @return [Boolean]
156
+ # @!attribute anonymous?
157
+ # Also known as +flags_j?+
158
+ # @return [Boolean]
159
+ # @!attribute ntlm?
160
+ # Also known as +flags_h?+
161
+ # @return [Boolean]
162
+ # @!attribute lm_key?
163
+ # Also known as +flags_g?+
164
+ # @return [Boolean]
165
+ # @!attribute datagram?
166
+ # Also known as +flags_f?+
167
+ # @return [Boolean]
168
+ # @!attribute seal?
169
+ # Also known as +flags_e?+
170
+ # @return [Boolean]
171
+ # @!attribute sign?
172
+ # Also known as +flags_d?+
173
+ # @return [Boolean]
174
+ # @!attribute request_target?
175
+ # Also known as +flags_c?+
176
+ # @return [Boolean]
177
+ # @!attribute oem?
178
+ # Also known as +flags_b?+
179
+ # @return [Boolean]
180
+ # @!attribute unicode?
181
+ # Also known as +flags_a?+
182
+ # @return [Boolean]
183
+ define_negotiate_flags
184
+ # @!endgroup Negotiate flags
185
+
186
+ # @!attribute version
187
+ # 8-byte version information
188
+ # @return [String]
189
+ define_field_before :payload, :version, PacketGen::Types::String, static_length: 8, default: VOID_VERSION
190
+
191
+ # @!attribute mic
192
+ # 16-byte message integrity code
193
+ # @return [String]
194
+ define_field_before :payload, :mic, PacketGen::Types::String, static_length: 16, default: VOID_MIC
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,115 @@
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 NTLM
10
+ # Known AvPair IDs
11
+ AVPAIR_TYPES = {
12
+ 'EOL' => 0,
13
+ 'ComputerName' => 1,
14
+ 'DomainName' => 2,
15
+ 'DnsComputerName' => 3,
16
+ 'DnsDomainName' => 4,
17
+ 'DnsTreeName' => 5,
18
+ 'Flags' => 6,
19
+ 'Timestamp' => 7,
20
+ 'SingleHost' => 8,
21
+ 'TargetName' => 9,
22
+ 'ChannelBindings' => 10
23
+ }.freeze
24
+
25
+ # AVPAIR structure, with value of type {SMB::String}.
26
+ AvPair = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16leEnum,
27
+ length_class: PacketGen::Types::Int16le,
28
+ value_class: SMB::String)
29
+ AvPair.define_type_enum AVPAIR_TYPES
30
+
31
+ class AvPair
32
+ def initialize(options={})
33
+ super
34
+ self[:value] = self[:value].class.new(null_terminated: false).read(self.value)
35
+ end
36
+ end
37
+
38
+ # EOL AVPAIR structure, with no value
39
+ EOLAvPair = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16leEnum,
40
+ length_class: PacketGen::Types::Int16le)
41
+ EOLAvPair.define_type_enum AVPAIR_TYPES
42
+
43
+ # Timestamp AVPAIR structure, with value of type {SMB::Filetime}.
44
+ TimestampAvPair = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16leEnum,
45
+ length_class: PacketGen::Types::Int16le,
46
+ value_class: SMB::Filetime)
47
+ TimestampAvPair.define_type_enum AVPAIR_TYPES
48
+
49
+ # Int32le AVPAIR structure, with value a {PacketGen::Types::Int32le}.
50
+ Int32leAvPair = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16leEnum,
51
+ length_class: PacketGen::Types::Int16le,
52
+ value_class: PacketGen::Types::Int32le)
53
+ Int32leAvPair.define_type_enum AVPAIR_TYPES
54
+
55
+ # String AVPAIR structure, with value a {PacketGen::Types::String}.
56
+ StringAvPair = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16leEnum,
57
+ length_class: PacketGen::Types::Int16le,
58
+ value_class: PacketGen::Types::String)
59
+ StringAvPair.define_type_enum AVPAIR_TYPES
60
+
61
+ # Specialized array containing {AvPair AvPairs}.
62
+ class ArrayOfAvPair < PacketGen::Types::Array
63
+ set_of AvPair
64
+
65
+ # Get unicode property
66
+ # @return [Boolean]
67
+ attr_reader :unicode
68
+ alias unicode? unicode
69
+
70
+ # Set unicode property
71
+ # @param [Boolean] unicode
72
+ # @return [Boolean]
73
+ def unicode=(unicode)
74
+ @unicode = unicode
75
+ each { |avpair| avpair.value.unicode = unicode if avpair.value.respond_to? :unicode= }
76
+ unicode
77
+ end
78
+
79
+ # @return [String]
80
+ def to_s
81
+ self.unicode = unicode
82
+ super
83
+ end
84
+
85
+ private
86
+
87
+ def record_from_hash(hsh)
88
+ obj = AvPair.new(type: hsh[:type])
89
+ klass = real_type(obj)
90
+
91
+ avpair = klass.new
92
+ avpair.type = hsh[:type]
93
+ avpair[:value].unicode = unicode? if avpair[:value].respond_to?(:unicode=)
94
+ avpair[:value].read(hsh[:value])
95
+ avpair.length = hsh[:length] || avpair[:value].sz
96
+ avpair
97
+ end
98
+
99
+ def real_type(obj)
100
+ case obj.type
101
+ when AVPAIR_TYPES['EOL']
102
+ EOLAvPair
103
+ when AVPAIR_TYPES['Timestamp']
104
+ TimestampAvPair
105
+ when AVPAIR_TYPES['Flags']
106
+ Int32leAvPair
107
+ when AVPAIR_TYPES['SingleHost'], AVPAIR_TYPES['ChannelBindings']
108
+ StringAvPair
109
+ else
110
+ AvPair
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,140 @@
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 NTLM
10
+ # NTLM Challenge message
11
+ # @author Sylvain Daubert
12
+ class Challenge < NTLM
13
+ update_field :type, default: NTLM::TYPES['challenge']
14
+
15
+ # @!attribute target_name
16
+ # Name of the server authentication realm. Must be expressed in the
17
+ # negotiated character set.
18
+ # @return [SMB::String]
19
+ # @!attribute target_name_len
20
+ # 16-bit unsigned integer that defines the size in bytes of
21
+ # {#target_name} in {#payload}. This field is set only if {#request_target?}
22
+ # is set.
23
+ # @return [Integer]
24
+ # @!attribute target_name_maxlen
25
+ # 16-bit unsigned integer that should be equal to {#target_name_len}.
26
+ # @return [Integer]
27
+ # @!attribute target_name_offset
28
+ # A 32-bit unsigned integer that defines the offset, in bytes, from
29
+ # the beginning of the CHALLENGE MESSAGE to {#target_name} in {#payload}.
30
+ # This field is set only if {#request_target?} is set.
31
+ # @return [Integer]
32
+ define_in_payload :target_name, SMB::String, null_terminated: false
33
+
34
+ # @!attribute flags
35
+ # Negotiate flags
36
+ # @return [Integer]
37
+
38
+ # @!group Negotiate flags
39
+ # @!attribute nego56?
40
+ # Also known as +flags_w?+.
41
+ # @return [Boolean]
42
+ # @!attribute key_exch?
43
+ # Also known as +flags_v?+
44
+ # @return [Boolean]
45
+ # @!attribute nego128?
46
+ # Also known as +flags_u?+
47
+ # @return [Boolean]
48
+ # @!attribute version?
49
+ # Also known as +flags_t+
50
+ # @return [Integer]
51
+ # @!attribute target_info?
52
+ # Also known as +flags_s?+
53
+ # @return [Boolean]
54
+ # @!attribute non_nt_session_key?
55
+ # Also known as +flags_r?+
56
+ # @return [Boolean]
57
+ # @!attribute identify?
58
+ # Also known as +flags_q+
59
+ # @return [Boolean]
60
+ # @!attribute ext_session_security?
61
+ # Also known as +flags_p?+
62
+ # @return [Boolean]
63
+ # @!attribute target_type_server?
64
+ # Also known as +flags_o?+
65
+ # @return [Boolean]
66
+ # @!attribute target_type_domain?
67
+ # Also known as +flags_n?+
68
+ # @return [Boolean]
69
+ # @!attribute always_sign?
70
+ # Also known as +flags_m?+
71
+ # @return [Boolean]
72
+ # @!attribute oem_target_info_supplied?
73
+ # Also known as +flags_l?+
74
+ # @return [Boolean]
75
+ # @!attribute oem_domain_supplied?
76
+ # Also known as +flags_k?+
77
+ # @return [Boolean]
78
+ # @!attribute anonymous?
79
+ # Also known as +flags_j?+
80
+ # @return [Boolean]
81
+ # @!attribute ntlm?
82
+ # Also known as +flags_h?+
83
+ # @return [Boolean]
84
+ # @!attribute lm_key?
85
+ # Also known as +flags_g?+
86
+ # @return [Boolean]
87
+ # @!attribute datagram?
88
+ # Also known as +flags_f?+
89
+ # @return [Boolean]
90
+ # @!attribute seal?
91
+ # Also known as +flags_e?+
92
+ # @return [Boolean]
93
+ # @!attribute sign?
94
+ # Also known as +flags_d?+
95
+ # @return [Boolean]
96
+ # @!attribute request_target?
97
+ # Also known as +flags_c?+
98
+ # @return [Boolean]
99
+ # @!attribute oem?
100
+ # Also known as +flags_b?+
101
+ # @return [Boolean]
102
+ # @!attribute unicode?
103
+ # Also known as +flags_a?+
104
+ # @return [Boolean]
105
+ define_negotiate_flags
106
+ # @!endgroup Negotiate flags
107
+
108
+ # @!attribute challenge
109
+ # 64-bit value containing the NTLM challenge.
110
+ # @return [String]
111
+ define_field_before :payload, :challenge, PacketGen::Types::String, static_length: 8, default: VOID_CHALLENGE
112
+ # @!attribute reserved
113
+ # 64-bit reserved field
114
+ # @return [Integer]
115
+ define_field_before :payload, :reserved, PacketGen::Types::Int64le
116
+
117
+ # @!attribute target_info
118
+ # @return [ArrayOfAvPair]
119
+ # @!attribute target_info_len
120
+ # 16-bit unsigned integer that defines the size in bytes of
121
+ # {#target_info} in {#payload}. This field is set only if {#target_info?}
122
+ # is set.
123
+ # @return [Integer]
124
+ # @!attribute target_info_maxlen
125
+ # 16-bit unsigned integer that should be equal to {#target_info_len}.
126
+ # @return [Integer]
127
+ # @!attribute target_info_offset
128
+ # A 32-bit unsigned integer that defines the offset, in bytes, from
129
+ # the beginning of the CHALLENGE MESSAGE to {#target_info} in {#payload}.
130
+ # This field is set only if {#target_info?} is set.
131
+ # @return [Integer]
132
+ define_in_payload :target_info, ArrayOfAvPair
133
+
134
+ # @!attribute version
135
+ # 8-byte version information
136
+ # @return [String]
137
+ define_field_before :payload, :version, PacketGen::Types::String, static_length: 8, default: VOID_VERSION
138
+ end
139
+ end
140
+ end