Lucene search
K

Host Information Enumeration via NTLM Authentication

🗓️ 05 Sep 2013 18:04:23Reported by Brandon KnightType 
metasploit
 metasploit
🔗 www.rapid7.com👁 20 Views

Host Information Enumeration via NTLM Authentication, Enumerates type 2 message for Active Directory domain and NetBIOS nam

Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Auxiliary
  include Msf::Exploit::Remote::HttpClient
  include Msf::Auxiliary::Scanner
  include Msf::Auxiliary::Report

  def initialize
    super(
      'Name' => 'Host Information Enumeration via NTLM Authentication',
      'Description' => %q{
          This module makes requests to resources on the target server in
        an attempt to find resources which permit NTLM authentication. For
        resources which permit NTLM authentication, a blank NTLM type 1 message
        is sent to enumerate a type 2 message from the target server. The type
        2 message is then parsed for information such as the Active Directory
        domain and NetBIOS name.  A single URI can be specified with TARGET_URI
        and/or a file of URIs can be specified with TARGET_URIS_FILE (default).
      },
      'Author' => 'Brandon Knight',
      'License' => MSF_LICENSE
    )
    register_options(
      [
        OptString.new('TARGET_URI', [ false, 'Single target URI', nil]),
        OptPath.new('TARGET_URIS_FILE', [
          false, 'Path to list of URIs to request',
          File.join(Msf::Config.data_directory, 'wordlists', 'http_owa_common.txt')
        ]),
      ]
    )
  end

  def run_host(_ip)
    test_uris = []
    turi = datastore['TARGET_URI']
    turis_file = datastore['TARGET_URIS_FILE']
    if (!turi && !turis_file)
      # can't simply return here as we'll print an error for each host
      fail_with 'Either TARGET_URI or TARGET_URIS_FILE must be specified'
    end
    if (turi && !turi.blank?)
      test_uris << normalize_uri(turi)
    end
    if (turis_file && !turis_file.blank?)
      File.open(turis_file, 'rb') { |f| test_uris += f.readlines }
      test_uris.collect! do |test_uri|
        normalize_uri(test_uri.chomp)
      end
    end
    test_uris.each do |test_path|
      result = check_url(test_path)
      # no need to try the other uris if one of them works.
      return handle_result(test_path, result) if result
    end
  end

  def handle_result(path, result)
    message = "Enumerated info on #{peer}#{path} - "
    message << "(name:#{result[:nb_name]}) "
    message << "(domain:#{result[:nb_domain]}) "
    message << "(domain_fqdn:#{result[:dns_domain]}) "
    message << "(server_fqdn:#{result[:dns_server]}) "
    message << "(os_version:#{result[:os_version]})"
    print_good(message)
    report_note(
      host: rhost,
      port: rport,
      proto: 'tcp',
      sname: (ssl ? 'https' : 'http'),
      ntype: 'ntlm.enumeration.info',
      data: {
        uri: path,
        SMBName: result[:nb_name],
        SMBDomain: result[:nb_domain],
        FQDNDomain: result[:dns_domain],
        FQDNName: result[:dns_server]
      },
      update: :unique_data
    )
  end

  def check_url(test_uri)
    begin
      vprint_status("Checking #{peer} URL #{test_uri}")
      res = send_request_cgi({
        'encode' => true,
        'uri' => test_uri.to_s,
        'method' => 'GET',
        'headers' => { 'Authorization' => 'NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw==' }
      })
    rescue OpenSSL::SSL::SSLError
      vprint_error('SSL error')
      return
    rescue Errno::ENOPROTOOPT, Errno::ECONNRESET, ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::ArgumentError
      vprint_error('Unable to Connect')
      return
    rescue ::Timeout::Error, ::Errno::EPIPE
      vprint_error('Timeout error')
      return
    end

    return if res.nil?

    vprint_status("Status: #{res.code}")
    if res && res.code == 401 && res['WWW-Authenticate'] && res['WWW-Authenticate'].match(/^NTLM/i)
      hash = res['WWW-Authenticate'].split('NTLM ')[1]
      # Parse out the NTLM and just get the Target Information Data
      message = Net::NTLM::Message.parse(Base64.decode64(hash))
      version = message.os_version.bytes
      ti = Net::NTLM::TargetInfo.new(message.target_info)
      info = {}
      info[:nb_name] = ti.av_pairs[Net::NTLM::TargetInfo::MSV_AV_NB_COMPUTER_NAME]
      info[:nb_domain] = ti.av_pairs[Net::NTLM::TargetInfo::MSV_AV_NB_DOMAIN_NAME]
      info[:dns_server] = ti.av_pairs[Net::NTLM::TargetInfo::MSV_AV_DNS_COMPUTER_NAME]
      info[:dns_domain] = ti.av_pairs[Net::NTLM::TargetInfo::MSV_AV_DNS_DOMAIN_NAME]
      info[:os_version] = "#{version[0]}.#{version[1]}.#{version[2] | (version[3] << 8)}"

      info
    end
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation