Active Directory is widely used, regardless of the size of the company or organization, to control access to internal resources.
However, there are still very few organizations that perform security assessments tailored to the specific characteristics of Active Directory services.
Key focus areas for an Active Directory security assessment include the Domain Controller, Group Policy, user accounts, and event logs.
In a recent vulnerability assessment for a global organization operating Active Directory, we focused on AD user accounts and identified several noteworthy security issues. AD user objects contain multiple important security-related attributes, and various assessment checkpoints (scenarios) can be derived by leveraging these attributes. The simple script below uses one of the account security attributes, badPwdCount, to identify AD user accounts that have attempted a bad password more than a specified threshold and exports the results to a CSV file. The higher the badPwdCount value, the more likely it is that the account is being targeted by password guessing attacks, so it is important to closely monitor the account’s basic information as well as fields such as Last Logon.
[ PowerShell version 1 ]
# BadPwdAccounts.ps1
Import-Module ActiveDirectory
# Enter the minimum badPwd count
$wiki = Read-Host -P ">>> Please INPUT ex)10 "
# Current DC Definition
$D = [system.directoryservices.activedirectory.Domain]::GetCurrentDomain()
$PDC = $D.PdcRoleOwner
$Domain = [ADSI]"LDAP://$D"
$csvFile = ".\the_Results.csv"
# DirectorySearcher Property Definition
$Searcher = New-Object System.DirectoryServices.DirectorySearcher
$Searcher.PageSize = 200
$Searcher.SearchScope = "subtree"
$Searcher.Filter = "(badPwdCount>=" + $wiki + ")"
# Filtering Property Definition
$Searcher.PropertiesToLoad.Add("distinguishedName") > $Null
$Searcher.PropertiesToLoad.Add("sAMAccountName") > $Null
$Searcher.PropertiesToLoad.Add("badPwdCount") > $Null
$Searcher.PropertiesToLoad.Add("badPasswordTime") > $Null
$Searcher.PropertiesToLoad.Add("logonCount") > $Null
# Dataset Initialization
$csvCont = @()
$csvCont += "no;sAMAccountName;badPwdCount;logonCount;badPasswordTime;distinguishedName `r`n"
# Dataset Query
ForEach ($DC In $D.DomainControllers)
{
$Server = $DC.Name
$Results = $Null
$i = 0
$csvCont = "=== DC: $Server (PDCe) `r`n"
$Base = "LDAP://$Server/" + $Domain.distinguishedName
$Searcher.SearchRoot = $Base
$Results = $Searcher.FindAll()
If($Results)
{
ForEach ($Result In $Results)
{
$i += 1
$DN = $Result.Properties.Item("distinguishedName")
$NTName = $Result.Properties.Item("sAMAccountName")
$BadCount = $Result.Properties.Item("badPwdCount")
$LogonCount = $Result.Properties.Item("logonCount")
$Time = $Result.Properties.Item("badPasswordTime")
$BadTime = ([DateTime]$Time.Item(0)).AddYears(1600).ToLocalTime()
$csvCont += "$i;$NTName;$BadCount;$LogonCount;$BadTime;""$DN"" `r`n"
}
}
Else
{
Write-Host "ERROR: Connection fail($Server)"
"<DC not found>"
}
# Export to Excel File
$csvCont += ">> The number of AD User accounts that attempt to have bad password over " + $wiki + " times is " + $i + ". `r`n"
$csvCont | out-file $csvFile -encoding UTF8
}
