0x00 Introduction

---

In domain penetration, if some domain user passwords have been obtained, the common approach is to identify password patterns, generate dictionary files, and attempt brute-force attacks on other domain user passwords.

From a defensive perspective, it is necessary to ensure that domain users do not use weak passwords with identifiable patterns and to detect brute-force attempts against domain user passwords.

This article will introduce common methods for brute-forcing domain user passwords both inside and outside the domain, along with attack methodologies and detection techniques.

0x01 Overview

---

This article will cover the following topics:

  • Methods for brute-forcing domain user passwords within the domain
  • Methods for brute-forcing domain user passwords from outside the domain
  • Detection methods

0x02 Considerations for Brute-Forcing Domain User Passwords

---

Multiple incorrect password attempts will result in user account lockout, with the default threshold set to 5 attempts

After a user account is locked, it typically requires a 30-minute waiting period by default before it can be used again.

The time of the last incorrect password entry is recorded and cannot be cleared by modifying LDAP data, with the following prompt:

Error 0x209A Access to the attribute is not permitted because the attribute is owned by the Security Accounts Manager (SAM).

After a user account is locked, even if the correct password is entered, a password error prompt will still appear.

0x03 Methods for brute-forcing domain user passwords within the domain.

---

1. Obtain the password policy for users within the domain to avoid account lockouts.

For detailed methods on obtaining password policies, refer to the previous article 'Penetration Basics - Obtaining Domain User Password Policies'.

2. Obtain a list of all domain users.

For detailed methods on obtaining this, refer to the earlier article 'Penetration Basics - Obtaining Active Directory Information'.

Here, additional judgment on user attributes is required to filter out disabled and locked users.

(1) Identifying disabled users.

The flag indicating whether a user is disabled is located in the userAccountControl attribute, specifically at position 0x0002.

As shown in the figure below.

Alt text

References:

https://support.microsoft.com/en-us/help/305144/how-to-use-useraccountcontrol-to-manipulate-user-account-properties

Use PowerView to view the ACCOUNTDISABLE attribute for all users with the following command:

Get-NetUser | select name,useraccountcontrol

The output is as shown in the figure below

Alt text

To view the specific value of the ACCOUNTDISABLE attribute for a specified user, use the following command:

Get-NetUser test2| select useraccountcontrol | ConvertFrom-UACValue -ShowAll

The output is as shown in the figure below

Alt text

It can be determined that user test2 has the following attributes:

  • ACCOUNTDISABLE
  • NORMAL_ACCOUNT
  • DONT_EXPIRE_PASSWORD

(2) Identify locked users

Although the user's ACCOUNTDISABLE attribute is marked as LOCKOUT at offset 0x0010, as shown in the figure below

Alt text

However, the value at this location cannot be used to determine whether the current user is locked out

We can determine by reading the user's badPwdCount attribute and lockoutTime attribute

Use PowerView to view the badPwdCount and lockoutTime attributes of all users, with the following command:

Get-NetUser | select name,badPwdCount,lockoutTime

The output result is shown in the figure below

Alt text

Clearly, it can be seen that user testa is in a locked state

3. Use DomainPasswordSpray for password spraying

Address:

https://github.com/dafthack/DomainPasswordSpray

Principle: Attempt LDAP queries through ADSI (Active Directory Services Interface) to obtain results

Example as follows:

Invoke-DomainPasswordSpray -UserList .\users.txt -Password DomainUser123! -Verbose

The output result is as shown in the figure below

Alt text

Note:

DomainPasswordSpray supports the function of filtering users, obtaining a list of all users, and excluding disabled and locked-out users

The command is as follows:

Get-DomainUserList -RemoveDisabled -RemovePotentialLockouts

In my test environment (dc: Server2012R2), this function encountered a bug and could not identify the locked-out user testa

As shown in the figure below

Alt text

In reality, the status of user testa is locked, as shown in the figure below

Alt text

Alt text

Personal speculation on the cause of the bug is as follows:

DomainPasswordSpray determines whether a user is locked by checking the ACCOUNTDISABLE attribute at offset 0x0010 (marked as LOCKOUT). The corresponding code location is: https://github.com/dafthack/DomainPasswordSpray/blob/master/DomainPasswordSpray.ps1#L408

Based on my test environment, the conclusion is that this value cannot be used for judgment. The correct method is to identify it through the badPwdCount attribute and lockoutTime attribute

0x04 Methods for brute-forcing domain user passwords from outside the domain

---

1. Brute-forcing domain user passwords using ldapsearch on Kali system

A previous article 'Penetration Basics - Obtaining Active Directory Information' introduced the method of connecting to an LDAP server using ldapsearch on Kali system

Here, a simple loop can be added to achieve brute-forcing. The complete bash command is as follows:

for i in $(cat test.txt); do echo -e "\n$i";ldapsearch -x -H ldap://192.168.1.1:389 -D "CN="$i",CN=Users,DC=test,DC=com" -w DomainUser123! -b "DC=test,DC=com" |grep "# numEntrie";done

test.txt stores all usernames. If the password is correct, it outputs the count of query results; if the password is wrong, it returns an authentication error: ldap_bind: Invalid credentials (49)

The output result is shown in the figure below

Alt text

Successfully brute-forced the password for user testb

2. Brute-forcing domain user passwords from outside the domain using Invoke-DomainPasswordSprayOutsideTheDomain on Windows system

DomainPasswordSpray has relatively complete functionality but does not support usage outside the domain. Therefore, I made some modifications based on DomainPasswordSpray to enable its use outside the domain

The specific modifications are as follows:

Modify the LDAP query statement in the original version:

$DomainContext = New-Object System.DirectoryServices.ActiveDirectory.DirectoryContext("domain",$Domain)
$DomainObject = [System.DirectoryServices.ActiveDirectory.Domain]::GetDomain($DomainContext)
$CurrentDomain = "LDAP://" + ([ADSI]"LDAP://$Domain").distinguishedName

Replace with LDAP query statement, example: "192.168.1.1/DC=test,DC=com"

The final complete query statement is: LDAP://192.168.1.1/DC=test,DC=com

Since brute-forcing is performed outside the domain and domain user password policies cannot be obtained, I removed the functionality to retrieve password policies from DomainPasswordSpray

I have uploaded the modified code to GitHub, address as follows:

An open-source project

Example command for use outside the domain:

Invoke-DomainPasswordSprayOutsideTheDomain -Domain "192.168.1.1/DC=test,DC=com" -UserList .\user.txt -Password DomainUser123! -Verbose

Output result as shown in the figure below

Alt text

0x05 Exploitation Approach

---

1. Brute-force domain user passwords within the domain

Process as follows:

(1) Obtain the password policy for domain users

Determine the number of attempts based on the value of lockoutThreshold to avoid account lockout

(2) Obtain the domain user list

After listing all domain users, it is necessary to evaluate user attributes and exclude disabled and locked users

(3) Attempt to crack

2. Brute-force cracking of domain user passwords from outside the domain

If a user's password has already been obtained, the domain user password policy and user list can first be retrieved using the same method as above

If no user passwords are available, only blind attempts can be made

0x06 Detection Methods

---

The lastbadpasswordattempt attribute in domain user properties records the last login time with an incorrect password, which can serve as a basis for identifying brute-force attacks

The badPwdCount attribute records the number of incorrect password attempts, but it resets to zero after the user enters the correct password, making it unreliable as a basis for judgment

If the attacker launches the attack from within the domain, they have already obtained the domain user password policy and user list. From a defense perspective, it is essential to ensure that domain user passwords are not predictable and to prevent multiple users from using the same password

Logs (4625 - An account failed to log on) can record login failure events, such as logs generated when a Kali system brute-forces domain user passwords via ldapsearch, as shown in the figure below

Alt text

Using kerbrute for brute force does not generate logs (4625 - An account failed to log on), but can be recorded via logs (4768 - A Kerberos authentication ticket (TGT) was requested and 4771 - Kerberos pre-authentication failed).

0x07 Summary

---

This article introduced common methods for brute-forcing domain user passwords both inside and outside the domain, discussed a bug I discovered while testing DomainPasswordSpray (which requires further testing in more environments), implemented out-of-domain brute force based on DomainPasswordSpray, and presented detection methods in combination with exploitation approaches.