Class: PacketGen::Plugin::NTLM

Inherits:
BinStruct::Struct
  • Object
show all
Defined in:
lib/packetgen/plugin/ntlm.rb,
lib/packetgen/plugin/ntlm/av_pair.rb,
lib/packetgen/plugin/ntlm/challenge.rb,
lib/packetgen/plugin/ntlm/negotiate.rb,
lib/packetgen/plugin/ntlm/authenticate.rb,
lib/packetgen/plugin/ntlm/ntlmv2_response.rb

Overview

Base class for NTLM authentication protocol.

Author:

  • Sylvain Daubert

Direct Known Subclasses

Authenticate, Challenge, Negotiate

Defined Under Namespace

Classes: ArrayOfAvPair, Authenticate, AvPair, Challenge, Negotiate, Ntlmv2Response

Constant Summary collapse

AVPAIR_TYPES =

Known AvPair IDs

{
  'EOL' => 0,
  'ComputerName' => 1,
  'DomainName' => 2,
  'DnsComputerName' => 3,
  'DnsDomainName' => 4,
  'DnsTreeName' => 5,
  'Flags' => 6,
  'Timestamp' => 7,
  'SingleHost' => 8,
  'TargetName' => 9,
  'ChannelBindings' => 10
}.freeze
EOLAvPair =

EOL AVPAIR structure, with no value

BinStruct::AbstractTLV.create(type_class: BinStruct::Int16leEnum,
length_class: BinStruct::Int16le)
TimestampAvPair =

Timestamp AVPAIR structure, with value of type SMB::Filetime.

BinStruct::AbstractTLV.create(type_class: BinStruct::Int16leEnum,
length_class: BinStruct::Int16le,
value_class: SMB::Filetime)
Int32leAvPair =

Int32le AVPAIR structure, with value a BinStruct::Int32le.

BinStruct::AbstractTLV.create(type_class: BinStruct::Int16leEnum,
length_class: BinStruct::Int16le,
value_class: BinStruct::Int32le)
StringAvPair =

String AVPAIR structure, with value a BinStruct::String.

BinStruct::AbstractTLV.create(type_class: BinStruct::Int16leEnum,
length_class: BinStruct::Int16le,
value_class: BinStruct::String)
TYPES =

NTLM message types

{
  'negotiate' => 1,
  'challenge' => 2,
  'authenticate' => 3
}.freeze
SIGNATURE =

NTLM signature

"NTLMSSP\0"
VOID_VERSION =

void version

[0].pack('q').freeze
VOID_CHALLENGE =
VOID_VERSION

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ NTLM

This method is abstract.

This method is meaningful for PacketGen::Plugin::NTLM subclasses only.

Returns a new instance of NTLM.



129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/packetgen/plugin/ntlm.rb', line 129

def initialize(options={})
  super
  return if self.class.payload_fields.nil?

  self.class.payload_fields.each do |name, type_and_opt|
    type, options = type_and_opt
    content = if type.new.respond_to?(:unicode?)
                type.new(options.merge(unicode: unicode?))
              else
                type.new(options)
              end
    send(:"#{name}=", content)
  end
end

Class Attribute Details

.payload_fieldsHash

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Return fields defined in payload one.

Returns:

  • (Hash)


42
43
44
# File 'lib/packetgen/plugin/ntlm.rb', line 42

def payload_fields
  @payload_fields
end

Instance Attribute Details

#payloadString

Returns:

  • (String)


36
# File 'lib/packetgen/plugin/ntlm.rb', line 36

define_attr :payload, BinStruct::String

#signatureString

8-byte NTLM signature

Returns:

  • (String)


29
# File 'lib/packetgen/plugin/ntlm.rb', line 29

define_attr :signature, BinStruct::String, static_length: 8, default: SIGNATURE

#typeInteger

4-byte message type

Returns:

  • (Integer)


33
# File 'lib/packetgen/plugin/ntlm.rb', line 33

define_attr :type, BinStruct::Int32leEnum, enum: TYPES

Class Method Details

.define_in_payload(name, type = SMB::String, options = {}) ⇒ void

This method returns an undefined value.

Define a field in payload. Also add name_len, name_maxlen and name_offset fields.

Parameters:

  • name (Symbol)

    name of field.

  • type (Class, nil) (defaults to: SMB::String)

    type of name field.

  • options (Hash) (defaults to: {})

    type’s options needed at build time



116
117
118
119
120
121
122
123
124
125
# File 'lib/packetgen/plugin/ntlm.rb', line 116

def define_in_payload(name, type=SMB::String, options={})
  @payload_fields ||= {}
  @payload_fields[name] = [type, options]

  define_attr_before :payload, :"#{name}_len", BinStruct::Int16le
  define_attr_before :payload, :"#{name}_maxlen", BinStruct::Int16le
  define_attr_before :payload, :"#{name}_offset", BinStruct::Int32le

  attr_accessor name
end

.define_negotiate_flagsvoid

This method returns an undefined value.

Define a flags field.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/packetgen/plugin/ntlm.rb', line 58

def define_negotiate_flags # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
  define_bit_attr_before :payload, :flags, endian: :little, flags_w: 1, flags_v: 1, flags_u: 1, flags_r13: 3,
                                           flags_t: 1, flags_r4: 1, flags_s: 1, flags_r: 1,
                                           flags_r5: 1, flags_q: 1, flags_p: 1, flags_r6: 1,
                                           flags_o: 1, flags_n: 1, flags_m: 1, flags_r7: 1,
                                           flags_l: 1, flags_k: 1, flags_j: 1, flags_r8: 1,
                                           flags_h: 1, flags_r9: 1, flags_g: 1, flags_f: 1,
                                           flags_e: 1, flags_d: 1, flags_r10: 1, flags_c: 1,
                                           flags_b: 1, flags_a: 1
  alias_method :nego56?, :flags_w?
  alias_method :key_exch?, :flags_v?
  alias_method :nego128?, :flags_u?
  alias_method :version?, :flags_t?
  alias_method :target_info?, :flags_s?
  alias_method :non_nt_session_key?, :flags_r?
  alias_method :identify?, :flags_q?
  alias_method :ext_session_security?, :flags_p?
  alias_method :target_type_server?, :flags_o?
  alias_method :target_type_domain?, :flags_n?
  alias_method :always_sign?, :flags_m?
  alias_method :oem_workstation_supplied?, :flags_l?
  alias_method :oem_domain_supplied?, :flags_k?
  alias_method :anonymous?, :flags_j?
  alias_method :ntlm?, :flags_h?
  alias_method :lm_key?, :flags_g?
  alias_method :datagram?, :flags_f?
  alias_method :seal?, :flags_e?
  alias_method :sign?, :flags_d?
  alias_method :request_target?, :flags_c?
  alias_method :oem?, :flags_b?
  alias_method :unicode?, :flags_a?
  alias_method :old_flags_a=, :flags_a=
  alias_method :old_flags=, :flags=

  class_eval do
    def flags_a=(value)
      self.old_flags_a = value
      self.class.payload_fields.each_key do |name|
        attr = send(name)
        attr.unicode = value if attr.respond_to?(:unicode=)
      end

      value
    end

    def flags=(value)
      self.old_flags = value
      self.flags_a = value & 1
    end
  end
end

.read(str) ⇒ NTLM

Create a NTLM object from a binary string

Parameters:

  • str (String)

Returns:



47
48
49
50
51
52
53
54
# File 'lib/packetgen/plugin/ntlm.rb', line 47

def read(str)
  ntlm = self.new.read(str)
  type = TYPES.key(ntlm.type)
  return ntlm if type.nil?

  klass = NTLM.const_get(type.capitalize)
  klass.new.read(str)
end

Instance Method Details

#calc_lengthvoid

This method is abstract.

This class is meaningful for PacketGen::Plugin::NTLM subclasses only.

This method returns an undefined value.

Calculate and set len, maxlen and offset fields defined for fields in #payload.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/packetgen/plugin/ntlm.rb', line 172

def calc_length
  return self if self.class.payload_fields.nil?

  previous_len = 0
  self.class.payload_fields.each_key do |name|
    send(:"#{name}_len=", 0)
    send(:"#{name}_offset=", offset_of(:payload) + previous_len)

    field = send(name)
    next unless field && !field.empty?

    length = field.respond_to?(:sz) ? field.sz : field.size
    send(:"#{name}_len=", length)
    send(:"#{name}_maxlen=", length)
    previous_len = length
  end
end

#read(str) ⇒ self

This method is abstract.

This class is meaningful for PacketGen::Plugin::NTLM subclasses only.

Populate object from a binary string

Parameters:

  • str (String)

Returns:

  • (self)


148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/packetgen/plugin/ntlm.rb', line 148

def read(str) # rubocop:disable Metrics/AbcSize
  super
  return self if self.class.payload_fields.nil?

  self.class.payload_fields.each do |name, type_and_opt|
    type, options = type_and_opt
    offset_in_payload = send(:"#{name}_offset") - offset_of(:payload)
    length = send(:"#{name}_len")
    content = if type.new.respond_to?(:unicode?)
                type.new(options.merge(unicode: unicode?))
              else
                type.new(options)
              end
    content.read(payload[offset_in_payload, length]) if length.positive?
    send(:"#{name}=", content)
  end

  self
end

#to_sString

This method is abstract.

This class is meaningful for PacketGen::Plugin::NTLM subclasses only.

Returns:

  • (String)


192
193
194
195
196
197
198
199
200
201
202
# File 'lib/packetgen/plugin/ntlm.rb', line 192

def to_s
  s = super
  return s if self.class.payload_fields.nil?

  self.class.payload_fields.each_key do |name|
    attr = send(name)
    attr.unicode = unicode? if attr.respond_to?(:unicode=)
    s << attr.to_s unless attr.nil? || send("#{name}_len").zero?
  end
  s
end