module Net::NTLM
Constants
- BLOB_SIGN
- DATA_REGEXP
Valid format for an NTLM hash composed of `'<LAN Manager hex digest>:<NT LAN Manager hex digest>'`.
- DEFAULT_FLAGS
- FLAGS
- FLAG_KEYS
- LAN_MANAGER_HEX_DIGEST_REGEXP
Valid format for LAN Manager hex digest portion: 32 hexadecimal characters.
- LM_MAGIC
- MAX64
- NT_LAN_MANAGER_HEX_DIGEST_REGEXP
Valid format for NT LAN Manager hex digest portion: 32 hexadecimal characters.
- SSP_SIGN
- TIME_OFFSET
Public Class Methods
# File lib/net/ntlm.rb, line 124 def apply_des(plain, keys) dec = OpenSSL::Cipher.new("des-cbc") dec.padding = 0 keys.map {|k| dec.key = k dec.encrypt.update(plain) + dec.final } end
Not sure what this is doing @param [String] str String to generate keys for @api private
# File lib/net/ntlm.rb, line 116 def gen_keys(str) split7(str).map{ |str7| bits = split7(str7.unpack("B*")[0]).inject('')\ {|ret, tkn| ret += tkn + (tkn.gsub('1', '').size % 2).to_s } [bits].pack("B*") } end
Takes a string and determines whether it is a valid NTLM Hash @param [String] the string to validate @return [Boolean] whether or not the string is a valid NTLM hash
# File lib/net/ntlm.rb, line 86 def is_ntlm_hash?(data) decoded_data = data.dup decoded_data = EncodeUtil.decode_utf16le(decoded_data) if DATA_REGEXP.match(decoded_data) true else false end end
Generates a Lan Manager Hash @param [String] password The password to base the hash on
# File lib/net/ntlm.rb, line 135 def lm_hash(password) keys = gen_keys password.upcase.ljust(14, "\0") apply_des(LM_MAGIC, keys).join end
# File lib/net/ntlm.rb, line 170 def lm_response(arg) begin hash = arg[:lm_hash] chal = arg[:challenge] rescue raise ArgumentError end chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) keys = gen_keys hash.ljust(21, "\0") apply_des(chal, keys).join end
# File lib/net/ntlm.rb, line 225 def lmv2_response(arg, opt = {}) key = arg[:ntlmv2_hash] chal = arg[:challenge] chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) if opt[:client_challenge] cc = opt[:client_challenge] else cc = rand(MAX64) end cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer) OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, chal + cc) + cc end
# File lib/net/ntlm.rb, line 241 def ntlm2_session(arg, opt = {}) begin passwd_hash = arg[:ntlm_hash] chal = arg[:challenge] rescue raise ArgumentError end chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) if opt[:client_challenge] cc = opt[:client_challenge] else cc = rand(MAX64) end cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer) keys = gen_keys(passwd_hash.ljust(21, "\0")) session_hash = OpenSSL::Digest::MD5.digest(chal + cc).slice(0, 8) response = apply_des(session_hash, keys).join [cc.ljust(24, "\0"), response] end
Generate a NTLM Hash @param [String] password The password to base the hash on @option opt :unicode (false) Unicode encode the password
# File lib/net/ntlm.rb, line 143 def ntlm_hash(password, opt = {}) pwd = password.dup unless opt[:unicode] pwd = EncodeUtil.encode_utf16le(pwd) end OpenSSL::Digest::MD4.digest pwd end
# File lib/net/ntlm.rb, line 182 def ntlm_response(arg) hash = arg[:ntlm_hash] chal = arg[:challenge] chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) keys = gen_keys hash.ljust(21, "\0") apply_des(chal, keys).join end
Generate a NTLMv2 Hash @param [String] user The username @param [String] password The password @param [String] target The domain or workstation to authenticate to @option opt :unicode (false) Unicode encode the domain
# File lib/net/ntlm.rb, line 156 def ntlmv2_hash(user, password, target, opt={}) if is_ntlm_hash? password decoded_password = EncodeUtil.decode_utf16le(password) ntlmhash = [decoded_password.upcase[33,65]].pack('H32') else ntlmhash = ntlm_hash(password, opt) end userdomain = user.upcase + target unless opt[:unicode] userdomain = EncodeUtil.encode_utf16le(userdomain) end OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, ntlmhash, userdomain) end
# File lib/net/ntlm.rb, line 190 def ntlmv2_response(arg, opt = {}) begin key = arg[:ntlmv2_hash] chal = arg[:challenge] ti = arg[:target_info] rescue raise ArgumentError end chal = NTLM::pack_int64le(chal) if chal.is_a?(Integer) if opt[:client_challenge] cc = opt[:client_challenge] else cc = rand(MAX64) end cc = NTLM::pack_int64le(cc) if cc.is_a?(Integer) if opt[:timestamp] ts = opt[:timestamp] else ts = Time.now.to_i end # epoch -> milsec from Jan 1, 1601 ts = 10_000_000 * (ts + TIME_OFFSET) blob = Blob.new blob.timestamp = ts blob.challenge = cc blob.target_info = ti bb = blob.serialize OpenSSL::HMAC.digest(OpenSSL::Digest::MD5.new, key, chal + bb) + bb end
Conver the value to a 64-Bit Little Endian Int @param [String] val The string to convert
# File lib/net/ntlm.rb, line 98 def pack_int64le(val) [val & 0x00000000ffffffff, val >> 32].pack("V2") end
Builds an array of strings that are 7 characters long @param [String] str The string to split @api private
# File lib/net/ntlm.rb, line 105 def split7(str) s = str.dup until s.empty? (ret ||= []).push s.slice!(0, 7) end ret end