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
@@ -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