# # An NTLM Authentication Library for Ruby # # This code is a derivative of "dbf2.rb" written by yrock # and Minero Aoki. You can find original code here: # http://jp.rubyist.net/magazine/?0013-CodeReview # ------------------------------------------------------------- # Copyright (c) 2005,2006 yrock # # This program is free software. # You can distribute/modify this program under the terms of the # Ruby License. # # 2011-02-23 refactored by Alexandre Maloteaux for Metasploit Project # ------------------------------------------------------------- # # 2006-02-11 refactored by Minero Aoki # ------------------------------------------------------------- # # All protocol information used to write this code stems from # "The NTLM Authentication Protocol" by Eric Glass. The author # would thank to him for this tremendous work and making it # available on the net. # http://davenport.sourceforge.net/ntlm.html # ------------------------------------------------------------- # Copyright (c) 2003 Eric Glass # # Permission to use, copy, modify, and distribute this document # for any purpose and without any fee is hereby granted, # provided that the above copyright notice and this list of # conditions appear in all copies. # ------------------------------------------------------------- # # The author also looked Mozilla-Firefox-1.0.7 source code, # namely, security/manager/ssl/src/nsNTLMAuthModule.cpp and # Jonathan Bastien-Filiatrault's libntlm-ruby. # "http://x2a.org/websvn/filedetails.php? # repname=libntlm-ruby&path=%2Ftrunk%2Fntlm.rb&sc=1" # The latter has a minor bug in its separate_keys function. # The third key has to begin from the 14th character of the # input string instead of 13th:) #-- # $Id: ntlm.rb 11678 2011-01-30 19:26:35Z hdm $ #++ #this class defines the base type needed for other modules like message and crypt require 'rex/proto/ntlm/constants' module Rex module Proto module NTLM class Base CONST = Rex::Proto::NTLM::Constants # base classes for primitives class Field attr_accessor :active, :value def initialize(opts) @value = opts[:value] @active = opts[:active].nil? ? true : opts[:active] end def size @active ? @size : 0 end end class String < Field def initialize(opts) super(opts) @size = opts[:size] end def parse(str, offset=0) if @active and str.size >= offset + @size @value = str[offset, @size] @size else 0 end end def serialize if @active @value else "" end end def value=(val) @value = val @size = @value.nil? ? 0 : @value.size @active = (@size > 0) end end class Int16LE < Field def initialize(opt) super(opt) @size = 2 end def parse(str, offset=0) if @active and str.size >= offset + @size @value = str[offset, @size].unpack("v")[0] @size else 0 end end def serialize [@value].pack("v") end end class Int32LE < Field def initialize(opt) super(opt) @size = 4 end def parse(str, offset=0) if @active and str.size >= offset + @size @value = str.slice(offset, @size).unpack("V")[0] @size else 0 end end def serialize [@value].pack("V") if @active end end class Int64LE < Field def initialize(opt) super(opt) @size = 8 end def parse(str, offset=0) if @active and str.size >= offset + @size d, u = str.slice(offset, @size).unpack("V2") @value = (u * 0x100000000 + d) @size else 0 end end def serialize [@value & 0x00000000ffffffff, @value >> 32].pack("V2") if @active end end # base class of data structure class FieldSet class << FieldSet def define(&block) c = Class.new(self) def c.inherited(subclass) proto = @proto subclass.instance_eval { @proto = proto } end c.module_eval(&block) c end def string(name, opts) add_field(name, String, opts) end def int16LE(name, opts) add_field(name, Int16LE, opts) end def int32LE(name, opts) add_field(name, Int32LE, opts) end def int64LE(name, opts) add_field(name, Int64LE, opts) end def security_buffer(name, opts) add_field(name, SecurityBuffer, opts) end def prototypes @proto end def names @proto.map{|n, t, o| n} end def types @proto.map{|n, t, o| t} end def opts @proto.map{|n, t, o| o} end private def add_field(name, type, opts) (@proto ||= []).push [name, type, opts] define_accessor name end def define_accessor(name) module_eval(<<-End, __FILE__, __LINE__ + 1) def #{name} self['#{name}'].value end def #{name}=(val) self['#{name}'].value = val end End end end #self def initialize @alist = self.class.prototypes.map{ |n, t, o| [n, t.new(o)] } end def serialize @alist.map{|n, f| f.serialize }.join end def parse(str, offset=0) @alist.inject(offset){|cur, a| cur += a[1].parse(str, cur)} end def size @alist.inject(0){|sum, a| sum += a[1].size} end def [](name) a = @alist.assoc(name.to_s.intern) raise ArgumentError, "no such field: #{name}" unless a a[1] end def []=(name, val) a = @alist.assoc(name.to_s.intern) raise ArgumentError, "no such field: #{name}" unless a a[1] = val end def enable(name) self[name].active = true end def disable(name) self[name].active = false end end Blob = FieldSet.define { int32LE :blob_signature, {:value => CONST::BLOB_SIGN} int32LE :reserved, {:value => 0} int64LE :timestamp, {:value => 0} string :challenge, {:value => "", :size => 8} int32LE :unknown1, {:value => 0} string :target_info, {:value => "", :size => 0} int32LE :unknown2, {:value => 0} } SecurityBuffer = FieldSet.define { int16LE :length, {:value => 0} int16LE :allocated, {:value => 0} int32LE :offset, {:value => 0} } class SecurityBuffer attr_accessor :active def initialize(opts) super() @value = opts[:value] @active = opts[:active].nil? ? true : opts[:active] @size = 8 end def parse(str, offset=0) if @active and str.size >= offset + @size super(str, offset) @value = str[self.offset, self.length] @size else 0 end end def serialize super if @active end def value @value end def value=(val) @value = val self.length = self.allocated = val.size end def data_size @active ? @value.size : 0 end end end end end end