Digging Your Talons In – New Take On Password Guessing
Digging Your Talons In – New Take On Password Guessing
Passwords have always been the bane of IT admins, whether it be fighting the battle on the corporate side to improve the policy or getting users to use complex passwords that can’t be guessed in under 5 minutes. Attackers know this, and so this attack vector has often been the primary technique used to compromise companies. Vendors and researchers have developed significant techniques and tools to detect authentication-based attacks. But are they sufficient?
The process of executing a password guessing attack has, over time, become more complex as hackers have employed new techniques to remain undetected, but at the root of it all password attacks come down to the concept of trying multiple combinations of usernames and passwords until finding one that works. These types of attacks have been executed for many years, yielding a high success rate. The root cause of this is because people create passwords they can easily remember.
Password guessing attacks typically occur on the perimeter as a way of establishing a foothold. Password guessing attacks can also be executed from a post-exploitation perspective as an effective way to gain further access in an environment to move laterally. For our purposes, we are going to focus on that post-exploitation landscape and how attackers perform password guessing attacks inside an enterprise.
Monitoring mechanisms have evolved with trending threats. However, monitoring an enterprise environment isn’t easy and requires that these systems and the operators who manage them are capable of keeping up with the latest trends and threats. This becomes problematic when dealing with logical threats such as password guessing. Any interface that takes credentials can be the target of a password guessing attack; automated alerts and rules need to be highly customized for each environment to trigger accordingly.
Almost all of these controls rely on the Windows event ID 4625 (“An account failed to logon”); this event comes enabled by default and is generated when a user attempts to login but fails due to either a bad password or the account is locked. By ingesting these events into an enterprise monitoring system, rules and detections can be deployed to track for suspicious lockouts.
While this is a great way to detect traditional password attacks, this doesn’t provide enough information and can often trigger false positives if not tuned properly. Primary enterprises see a lot of false positives from improperly tuned alerts from this due to normal behavior such as when users mistype their passwords or if an authentication sync error occurs. In addition, this event ID only logs authentication failures for several services, including:
- Outlook Authentication
While these services encompass a lot of the typical authentication protocols found in any enterprise, this does not include all of them. For our purposes, we will just focus on two of the most common because they are present on all domain controllers and integrate into Microsoft Active Directory environment for authorization, which makes them perfect targets for attackers to focus on.
The first is Lightweight Directory Access Protocol (LDAP), which is used to access and modify information stored within active directory. LDAP can be used as a central directory accessible from anywhere on the network, allowing for simple, fast data query and retrieval. LDAP can also bridge the gap between non-Windows-based applications and services deployed in corporate environments, allowing them to communicate with the domain to view users, groups and system objects.
LDAP is an excellent service for attackers to perform password guessing, as this protocol is integrated into Active directory, but also because failed authentication attempts do not trigger the Windows event ID 4625. This creates a huge problem if your primary source of detecting bad authentication attempts stems from a Domain Controller’s event IDs. As a result, an attacker can perform bind requests against LDAP to validate credentials without triggering a single “An account failed to logon” alert.
The second is Kerberos. One of the key features of Kerberos is its alternative form of authentication; instead of transmitting credentials, Kerberos uses a ticket as a form of authentication. This Ticket Authentication works by a client sending a request for a ticket to the Key Distribution Center (KDC). The KDC creates a ticket-granting ticket (TGT) for the client, encrypts it using the client’s password as the key, and sends the encrypted TGT back to the client. The client then attempts to decrypt the TGT, using its password. If the client successfully decrypts the TGT (i.e., if the client gave the correct password), it keeps the decrypted TGT, which indicates proof of the client’s identity. Clients authenticate with a Key Distribution Center and get temporary keys to access locations on the network. This allows for strong and secure authentication without transmitting passwords. Windows environments typically use Kerberos for:
- Delegated authentication
- Single Sign On
- More efficient authentication to server
- Mutual authentication
Attackers cans utilize these two services integrated into Active Directory for authentication with lower visibility. Using both a combination of both LDAP and Kerberos protocols, attackers can perform password guessing by alternating between the two services, allowing the password attack traffic to be split across two protocols. This splits the number of potential events generated, as a result reducing the chance of an alert. We can then take this one step further, distributing a password attack against multiple domain controllers in an enterprise, alternating between LDAP and Kerberos each time to create an additional layer of obscurity. This forces blue teams to change how they typically handle and look at these types of events and how these events will trigger an alert.
Figure 1: Password Guessing Technique
Talon is an automated authentication tool for large scale attacks while remaining undetected. Talon has two main functions for performing successful password guessing attacks. The first is user enumeration to generate a list of valid users for attacks. Talon can provide more details about the valid users in a company’s active directory, giving you more information than just if the user exists or not. Talon utilizes Kerberos for enumeration.
The reason why Kerberos has this function is that without it, an attacker can send dummy requests, resulting in the KDC returning an encrypted TGT ticket. Attackers can take this TGT and brute force it offline without drawing further attention to themselves (from a SIEM point of view, it would like a single event, requesting a TGT). With pre-authentication enabled, attackers cannot directly request a TGT without first having their credentials checked. If a pre-authentication request fails, the client will receive a failure along with an Error ID code. These codes are heavily documented, but for our purposes, the ones we care about are:
|Error ID||Code Name||Reason|
|6||KDC_ERR_C_PRINCIPAL_UNKNOWN||The username doesn’t exist.|
|18||KDC_ERR_CLIENT_REVOKED||Account disabled, expired, or locked out.|
|24||KDC_ERR_PREAUTH_FAILED||Pre-authentication failed; usually means bad password|
For attackers, we really only focus on these error codes. It’s important to know that Kerberos responds with various error messages such as one that indicates if a user account has pre-auth disabled, if the user account uses DES encryption for Kerberos or if Smart card authentication is enabled for the user. These values are important to monitor as these are standard options found under the user’s settings in Active Directory; they also actually change the response from our pre-authentication significantly if an account has “Does not Require Preauth” enabled. It changes the pre-authentication response from:
KDC_Error: AS Exchange Error: kerberos error response from KDC: KRB Error: (24) KDC_ERR_PREAUTH_FAILED Pre-authentication information was invalid
KRBMessage_Handling_Error: AS Exchange Error: AS_REP is not valid or client password/keytab incorrect < Decrypting_Error: error decrypting EncPart of AS_REP < Decrypting_Error: error decrypting AS_REP encrypted part: error decrypting: integrity verification failed
As you can see, these are very two different messages, and if you’re not properly reading the responses or even receiving the full responses, you can create false negatives in your enumeration. However, by sending a request with a Pre-Authentication encryption type that will be rejected or unsupported by the KDC, we can still receive a response to determine if a user account exists based on the response sent by the KDC. These responses will change, no longer providing specific information as mentioned previously; rather they will be replaced with the following error:
KDC_Error: AS Exchange Error: kerberos error response from KDC: KRB Error: (14) KDC_ERR_ETYPE_NOSUPP KDC has no support for encryption type
This response helps identify if an account exists in Active Directory. This is due to the fact that the response indicates that the KDC does not support the encryption type selected by the client. This is clearly different than when a user does not exist, as shown below:
AS Exchange Error: kerberos error response from KDC: KRB Error: (6) KDC_ERR_C_PRINCIPAL_UNKNOWN Client not found in Kerberos database
Or accounts that are locked with the following error :
KDC_Error: AS Exchange Error: kerberos error response from KDC: KRB Error: (18) KDC_ERR_CLIENT_REVOKED Clients credentials have been revoked
The benefit to sending a TGT request without Pre-Authentication encryption type is that we can enumerate valid users without generating a failed lockout on the account.
Figure 2: Talon Detecting Valid Users Accounts in a Domain
Kerberos also has the capability to detect locked-out accounts. This response can help in identifying accounts that are already locked out, but moreso while password guessing attacks occur if an account becomes locked. The one downside is that this error code is specifically tied to Kerberos, not LDAP. LDAP does not have an “Account Locked” Flag at first glance. LDAP was designed to ensure the leakage of information from an unauthenticated perspective would be next to none. This is done with how the bind authentication process works in LDAP.
When an LDAP session is established, a client’s authorization state is set to anonymous. In any modern Active Directory deployments, in this state, a client can access no data. The only thing a client can do is perform a BIND request that can change the state of the session via the process of authorization (the process of verifying who a user is based on the provided credentials). If the authorization is successful, the BIND request will change the state of the connection to “Authenticated” giving the client access to view data stored in LDAP.
If the BIND is not successful, the connection state does not change, and the client receives a result code. When a client initiates a connection with either a “valid username but bad credentials” or an “invalid username and bad credentials” the LDAP result code is still the same (code 49 “Invalid Credentials”). This result code itself doesn’t give us any indication of what the cause was (i.e., bad username or password); by reviewing the actual error message, this information can’t be derived. While studying variations of these errors, we discovered a variation. When multiple bad password guesses against the same host occurred, the LDAP error message would be:
LDAP Result Code 49 "Invalid Credentials": 80090308: LdapErr: DSID-0C09042A, comment: AcceptSecurityContext error, data 52e, v3839
After five attempts, however the error message changes to:
LDAP Result Code 49 "Invalid Credentials": 80090308: LdapErr: DSID-0C09042A, comment: AcceptSecurityContext error, data 775, v3839
As this domain environment has a password policy of five password attempts before an account would be locked, we can deduce that the “775” dictates the lockout. We can verify this by capturing the handshake on the domain controller’s side, discovering that LDAP has multiple additional error codes for the Result Code 49.
Figure 3: Wireshark Sample Outlining the Result Code
After doing some further investigation, it turns out LDAP Result Code 49 “Invalid Credentials” was the original error code used for a bad authentication. As LDAP has grown and Active Directory has become more complicated with additional features and security controls, Microsoft created an additional subset of error messages.
|HEX Code||Error Message||Notes|
|525||LDAP_NO_SUCH_OBJECT||Entry does not exist.|
|52f||ERROR_ACCOUNT_RESTRICTION||Account Restrictions are preventing this user from signing in.|
|530||ERROR_INVALID_LOGON_HOURS||Logon time restriction violation|
|531||ERROR_INVALID_WORKSTATION||Not allowed to log on to this computer.|
|532||ERROR_PASSWORD_EXPIRED||Password Expired (Only works when valid username and credentials are entered)|
|533||ERROR_ACCOUNT_DISABLED||Disabled (Only works when valid username and credentials are entered)|
|568||ERROR_TOO_MANY_CONTEXT_IDS||During a logon attempt, the user’s security context accumulated too many security Identifiers.|
|701||ERROR_ACCOUNT_EXPIRED||LDAP password expiration|
|773||ERROR_PASSWORD_MUST_CHANGE||Password must be changed before continuing|
|775||ERROR_ACCOUNT_LOCKED_OUT||Entry is currently locked out and may not be logged on to.|
As a result, Talon can use both Kerberos and LDAP to read the responses as we perform a password guessing attack. Talon can detect account lockouts during an active password guessing attack by reading the response code from each password attempt, ensuring that an attacker doesn’t cause a massive lockout, which is critical when trying to remain undetected. It is important to note that when sending Kerberos pre-authentication requests, these attempts still go towards the user’s bad password count.
Figure 4: Sample Lock Out Detected
Talon can also perform a password guessing attack against the Kerberos and LDAPS (LDAP Secure) services. Talon can either use a single or multiple domain controllers to perform these attacks, randomizing each attempt between the domain controllers and services (LDAP or Kerberos) each time.
Figure 5: Diagram - Outlining How A Distributed Attack Would Look Across LDAP And Kerberos Against Multiple Domain Controllers
Figure 6: Sample Password Guessing Attack
Defending against this type of password guessing attack requires a few significant changes to an enterprise’s environment. First, event logging: since these events are not logged by default, enterprises need to modify their Active Directory Local Security policies to be able to see these events. Specifically, the “System Audit Policies – Local Group Policy Object” contains security-related rules used for detailed tracking of activities. These activities range from authentication, directory services, policy changes, and others.
Figure 7: Policy Options to Enable
With these options enabled, LDAP authentication requests will properly be generated with the event ID, as well as triggering Windows event ID 4625 “An account failed to logon.” Additionally, Kerberos pre-authentication failure attempts will then generate Windows event ID 4771 “Kerberos pre-authentication failed.”
While this is often a great start, the next steps are often more difficult for enterprises, requiring fine-tuning to ensure whatever SIEM or centralized logging event system employed is correctly reading these events and parsing the key data. This data is not just the account and source, but also the protocol used and time the event was triggered. Enterprises need to adjust how they ingest these events. The change here is to not look at each domain controller as its own separate entity but instead looking at them as one item, streaming the events from all domain controllers as one entity and creating alerts that trigger if the number of authentication attempts against LDAP and Kerberos exceeds above average usage in an environment.
There are many other features implemented into Talon that can be useful for performing password guessing attacks. The code for this project can be found on Optiv’s GitHub here.
Copyright © 2020 Optiv Security Inc. All rights reserved.
No license, express or implied, to any intellectual property or other content is granted or intended hereby.
This blog is provided to you for information purposes only. While the information contained in this site has been obtained from sources believed to be reliable, Optiv disclaims all warranties as to the accuracy, completeness or adequacy of such information.
Links to third party sites are provided for your convenience and do not constitute an endorsement by Optiv. These sites may not have the same privacy, security or accessibility standards.
Complaints / questions should be directed to Legal@optiv.com