When attempting to gain a foothold into a Windows Domain, an attacker will often attempt one or two likely passwords against every user in the Active Directory, a so-called horizontal password guessing attack.
2. Detecting Windows horizontal password
guessing attacks in near real-time
When attempting to gain a foothold into a Windows Domain, an attacker will
often attempt one or two likely passwords against every user in the Active
Directory, a so-called horizontal password guessing attack. A small number of
failed logons per user will usually not trigger a user account lockout policy and
can be very effective. This post will provide an example solution to detecting such
attacks in near real time, using only native Windows tools.
Even with password complexity requirements and custom filters there is no built-in
way to stop users choosing poor passwords. It is scary how may user accounts are
identified with the password Password1 for example. We need a method of
detecting password guessing attacks, preferably before someone takes control of
the Domain.
By following these instructions you can get hourly (can be trivially customised)
notifications of such horizontal password guessing attacks.
Note: The following method has been developed using Windows 2012.
3. Configuring the Domain Controller
First we need to configure the Active Directory
Domain Controller to log failed logon attempts:
From the Server Manager tool click Tools and
select Group Policy Management, as shown in
the screenshot :
4. Expand the nodes in the left hand pane so you
can see the policy Default Domain Controllers
Policy for Domain Controllers within the Domain.
Right-click it and select Edit, as shown :
In the Group Policy Management Editor expand
“Computer Configuration > Policies > Windows
Settings > Security Settings > Local Policies” and then
click “Audit Policy”
Right-click “Audit account logon events” and select
“Properties”, as shown below:
5. Ensure that both “Define these
policy settings” and “Failure” are
enabled then click “OK”. The
following screenshot shows both
“Success” and “Failure” are
selected:
6. When you click “OK” the
updated policy settings will be
visible. Next we force the server
to recognise the updated policy
settings by running the
command gpupdate /force by
pressing Windows key + r, as
shown:
7. Testing
To test that the policy has taken affect
we make a failed logon attempts (from
another system). Note the IP address of
the machine used in the screenshot:
8. By viewing the Event Viewer on the
Domain Controller we can see in the
following screenshot that failed logon
attempts now generate Audit
Failure events (in this case EventID 4771)
and that the IPAddress shown matches
the host from which the logon attempt
was made:
9. Parsing the event logs
PowerShell has a cmdlet called get-WinEvent that allows us to filter out all events with a specific
EventId within a given timespan.
Note: The backtick at the end of the first line is PowerShell’s multiline indicator and is required.
By running the above PowerShell command we get all events from the Security log with an ID
value of 4771 from the past hour. If we wanted to change the timespan we could replace
AddHours(-1) with AddMinutes(-30) for the last 30 minutes, or AddDays(-1) for the last 24 hours.
Those events will be accessed via the $events variable.
If we want to check additional EventIds we simply add extra calls to get-WinEvent like so:
Note the use of += to append the extra events.
10. Parsing the event logs continued…
We specify the parameter -EA silentlycontinue to avoid error messages if there are no events
returned.
Of course some of those events might well be innocent users who mis-typed their password.
Someone performing a horizontal password guessing attack against Active Directory users
will be running that attack from a single host on the network (E.g. an IP address). Or several
hosts might be being used, each testing a sub-set of user accounts and/or passwords. We
want to identify any IP address that failed to logon more than a specified number of times
within our timespan.
In order to obtain information from the event entry message we need to convert the event
to XML so that we can parse it. We will make a note of each IP address that generated the
failed logon event by looping through each event (remember we filtered only those events
we are interested in) and increment a counter specific for each unique IP address we
encounter.
Once we have counted each failed logon attempt originating from all the source IPs
referenced in the log event we simply report on any IP where the counted value exceeds
our specified threshold value by sending an email alert.
11. The Complete Script
The following PowerShell script implements the complete process:
The PowerShell script will
display information to the
PowerShell Console (if
visible) and send an email,
in this case to
ITSecurity@mydomain.com
from
alerts@mydomain.com,
using the Send-
MailMessage cmdlet.
12. Testing the Script
We can test the script with the following command :
Note: You may need to first enable external scripting within PowerShell:
For a more secure configuration of PowerShell you can specify Signed instead
of Unrestricted. More details on this can be found on Microsoft’s web site.
13. Running the script automatically
Now we need a method of running the script on the Domain Controller
each hour. We can use the task scheduler (as an Administrator):
Once we create the scheduled task we need to start it:
Note: For extra security you should create a service account with the minimum privileges required to access the
event log and send Emails, and specify that account in the /ru parameter, in place of NT
AUTHORITYLOCALSERVICE.
And that’s it. You may want to tweak the time period settings and the $mail_domainSr value, and the email settings
will need to be updated.
This solution can also be used to cover password attacks on local user accounts through the use of Centralised
Event Logging. Also see the National Security Agency’s (NSA)detailed paper on configuring centralised event
logging.