Garantir a segurança dos sistemas de TI é uma tarefa crucial. A identificação de atividades suspeitas, como várias tentativas de login fracassadas, é uma medida importante para atenuar possíveis ameaças. O script fornecido, escrito no PowerShell, serve como uma ferramenta versátil para ajudar os profissionais de TI e MSPs a obter insights sobre eventos de login com falha.
Histórico
Compreender as tentativas de login com falha em um sistema pode fornecer insights cruciais para os administradores de TI. Eles podem detectar possíveis violações de segurança, monitorar o comportamento dos usuários e manter a integridade do sistema. O script do PowerShell fornecido obtém esses dados com eficiência, oferecendo uma solução robusta para profissionais. Nunca é demais enfatizar a importância dessa ferramenta. Com o aumento das ameaças à segurança cibernética, ter um método eficiente para detectar anomalias nos logins de usuários torna-se essencial para MSPs e profissionais de TI.
O roteiro
#Requires -Version 3.0 -RunAsAdministrator
<#
.SYNOPSIS
Returns the number of recent failed login attempts.
.DESCRIPTION
Returns the number of recent failed login attempts of all users or of a specific user. If a user is specified then just a number is returned.
.EXAMPLE
No parameters needed.
Returns all users, of the local machine, with a could of failed login attempts.
Output Example:
UserName FailedLoginAttempts
-------- -------------------
Fred 4
Bob 0
.EXAMPLE
-UserName "Fred"
Returns the number of failed login attempts of the user Fred on the local machine.
Output Example:
4
.EXAMPLE
-ComputerName "FredPC" -UserName "Fred"
Returns the number of failed login attempts of the user Fred on the computer named FredPC.
Output Example:
4
.EXAMPLE
-ComputerName "FredPC" -UserName "Fred" -Detailed
Returns the number of failed login attempts of the user Fred on the computer named FredPC, but will more details of each failed and successful logins.
Output Example:
TimeGenerated : 10/18/2019 7:52:43 AM
EventID : 4624
Category : 12544
ADUsername : Fred
Domain : FredPC
UserSID : S-1-0-0
Workstation : -
SourceIP : -
Port : -
FailureReason : Interactive
FailureStatus : Incorrect password
FailureSubStatus: Other
.EXAMPLE
PS C:> Monitor-Failed-Password-Attempts.ps1 -ComputerName "FredPC" -UserName "Fred"
Returns the number of failed login attempts of the user Fred on the computer named FredPC.
Output Example:
4
.OUTPUTS
System.Int32 Number of failed login attempts.
.OUTPUTS
PSCustomObject List of user names and a count of failed login attempts.
.NOTES
Minimum OS Architecture Supported: Windows 7, Windows Server 2012
If ComputerName is specified, then be sure that the computer that this script is running on has network and permissions to access the Event Log on the remote computer.
Release Notes:
Initial Release
By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms.
Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party.
Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider.
Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations.
Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks.
Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script.
EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
.COMPONENT
ManageUsers
#>
param (
# The name of a remote computer to get event logs for failed logins
[Parameter(Mandatory = $false)]
[String]
$ComputerName = [System.Net.Dns]::GetHostName(),
# A username
[Parameter(Mandatory = $false)]
[String]
$UserName,
# Returns all relevant events, sorted by TimeGenerated
[Switch]
$Detailed
)
# Support functions
# Returns the matching FailureReason like Incorrect password
function Get-FailureReason {
Param($FailureReason)
switch ($FailureReason) {
'0xC0000064' { "Account does not exist"; break; }
'0xC000006A' { "Incorrect password"; break; }
'0xC000006D' { "Incorrect username or password"; break; }
'0xC000006E' { "Account restriction"; break; }
'0xC000006F' { "Invalid logon hours"; break; }
'0xC000015B' { "Logon type not granted"; break; }
'0xc0000070' { "Invalid Workstation"; break; }
'0xC0000071' { "Password expired"; break; }
'0xC0000072' { "Account disabled"; break; }
'0xC0000133' { "Time difference at DC"; break; }
'0xC0000193' { "Account expired"; break; }
'0xC0000224' { "Password must change"; break; }
'0xC0000234' { "Account locked out"; break; }
'0x0' { "0x0"; break; }
default { "Other"; break; }
}
}
function Get-LogonType {
Param($LogonType)
switch ($LogonType) {
'0' { 'Interactive'; break; }
'2' { 'Interactive'; break; }
'3' { 'Network'; break; }
'4' { 'Batch'; break; }
'5' { 'Service'; break; }
'6' { 'Proxy'; break; }
'7' { 'Unlock'; break; }
'8' { 'Networkcleartext'; break; }
'9' { 'NewCredentials'; break; }
'10' { 'RemoteInteractive'; break; }
'11' { 'CachedInteractive'; break; }
'12' { 'CachedRemoteInteractive'; break; }
'13' { 'CachedUnlock'; break; }
Default {}
}
}
#-Newest $Records
$Events = Get-EventLog -ComputerName $ComputerName -LogName 'security' -InstanceId 4625, 4624 | Sort-Object -Property TimeGenerated | ForEach-Object {
if ($_.InstanceId -eq 4625) {
$_ | Select-Object -Property @(
@{Label = 'TimeGenerated'; Expression = { $_.TimeGenerated } },
@{Label = 'EventID'; Expression = { $_.InstanceId } },
@{Label = 'Category'; Expression = { $_.CategoryNumber } },
@{Label = 'Username'; Expression = { $_.ReplacementStrings[5] } },
@{Label = 'Domain'; Expression = { $_.ReplacementStrings[6] } },
@{Label = 'UserSID'; Expression = { (($_.Message -Split 'rn' | Select-String 'Security ID')[1] -Split 's+')[3] } },
# @{Label = 'UserSID'; Expression = { $_.ReplacementStrings[0] } },
@{Label = 'Workstation'; Expression = { $_.ReplacementStrings[13] } },
@{Label = 'SourceIP'; Expression = { $_.ReplacementStrings[19] } },
@{Label = 'Port'; Expression = { $_.ReplacementStrings[20] } },
@{Label = 'LogonType'; Expression = { $_.ReplacementStrings[8] } },
@{Label = 'FailureStatus'; Expression = { Get-FailureReason($_.ReplacementStrings[7]) } },
@{Label = 'FailureSubStatus'; Expression = { Get-FailureReason($_.ReplacementStrings[9]) } }
)
}
elseif ($_.InstanceId -eq 4624 -and (Get-LogonType($_.ReplacementStrings[8])) -notlike 'Service') {
$_ | Select-Object -Property @(
@{Label = 'TimeGenerated'; Expression = { $_.TimeGenerated } },
@{Label = 'EventID'; Expression = { $_.InstanceId } },
@{Label = 'Category'; Expression = { $_.CategoryNumber } },
@{Label = 'Username'; Expression = { $_.ReplacementStrings[5] } },
@{Label = 'Domain'; Expression = { $_.ReplacementStrings[6] } },
@{Label = 'UserSID'; Expression = { $_.ReplacementStrings[0] } },
@{Label = 'Workstation'; Expression = { $_.ReplacementStrings[11] } },
@{Label = 'SourceIP'; Expression = { $_.ReplacementStrings[18] } },
@{Label = 'Port'; Expression = { $_.ReplacementStrings[19] } },
@{Label = 'LogonType'; Expression = { Get-LogonType($_.ReplacementStrings[8]) } },
@{Label = 'LogonID'; Expression = { Get-FailureReason($_.ReplacementStrings[7]) } },
@{Label = 'LogonProcess'; Expression = { Get-FailureReason($_.ReplacementStrings[9]) } }
)
}
}
if ($Detailed) {
if ($UserName) {
$Events | Where-Object {
$_.Username -like $UserName
}
}
else {
$Events | Where-Object {
$_.Username -notlike "DWM*" -and
$_.Username -notlike "UMFD*" -and
$_.Username -notlike "SYSTEM"
}
}
}
else {
$UserNames = if ($UserName) {
($Events | Select-Object -Property Username -Unique).Username | Where-Object {
$_ -like "$UserName"
}
}
else {
($Events | Select-Object -Property Username -Unique).Username | Where-Object {
$_ -notlike "DWM*" -and
$_ -notlike "UMFD*" -and
$_ -notlike "SYSTEM"
}
}
$UserNames | ForEach-Object {
$CurrentUserName = $_
$FailedLoginCount = 0
for ($i = 0; $i -lt $Events.Count; $i++) {
if ($Events[$i].EventID -eq 4625 -and $Events[$i].Username -like $CurrentUserName) {
# User failed to login X times
# Count the number of failed logins
$FailedLoginCount++
}
elseif ($Events[$i].EventID -eq 4624 -and $Events[$i].Username -like $CurrentUserName) {
# User logged in successfully
# Reset the number of failed logins to 0
$FailedLoginCount = 0
}
}
if ($UserName) {
# If a UserName was specified, then return only the failed login count
$FailedLoginCount
}
else {
# If no UserName was specified, then return the user name and failed login count
[PSCustomObject]@{
UserName = $CurrentUserName
FailedLoginAttempts = $FailedLoginCount
}
}
}
}
Acesse mais de 300 scripts no NinjaOne Dojo
Análise detalhada do roteiro
Em sua essência, o script obtém dados dos logs de eventos de um determinado computador, visando IDs de eventos específicos que representam tentativas de login fracassadas e bem-sucedidas.
- Parâmetros: O script começa definindo parâmetros como ComputerName, UserName e Detailed. Isso permite que o usuário especifique a máquina, o usuário e o nível de detalhe das tentativas de login.
- Funções: Duas funções, Get-FailureReason e Get-LogonType, traduzem as informações codificadas dos registros de eventos em dados legíveis por humanos sobre o tipo de login e o motivo da falha no login.
- Obtenção de eventos: Em seguida, o script obtém os registros de eventos, filtrando-os para reter apenas as informações necessárias. Isso envolve selecionar as instâncias com as IDs de evento relevantes.
- Processamento: Dependendo da solicitação de dados detalhados, o script fornece um detalhamento abrangente de cada tentativa de login ou um resumo das tentativas fracassadas de cada usuário.
Casos de uso em potencial
Imagine um administrador de TI em uma empresa de médio porte. Recentemente, o departamento de TI notou um aumento no número de tentativas de login com falha, especialmente fora do horário de trabalho. Usando o script, o administrador pode verificar rapidamente quais usuários falharam nas tentativas de login e com que frequência. Ao descobrirem que uma única conta de usuário teve várias tentativas fracassadas em um curto período de tempo, eles puderam concluir que essa conta pode ter sido direcionada. Assim, o script ajuda na detecção precoce e na correção imediata.
Abordagem alternativa
Há vários métodos para rastrear tentativas de login fracassadas. A auditoria de segurança integrada do Windows, por exemplo, permite visualizar os registros de segurança por meio do Event Viewer. Embora essa abordagem seja simples, ela pode consumir muito tempo. Nosso script do PowerShell simplifica o processo, oferecendo uma solução mais eficiente e personalizável.
Implicações
Ao compreender o número de tentativas de login com falha, os administradores de TI podem evitar possíveis violações de segurança. Anomalias nos padrões de login geralmente são um sinal precoce de atividade mal-intencionada. Portanto, ao agir com base nesses dados, os profissionais podem reforçar seus sistemas contra possíveis ameaças.
Recomendações
- Verifique se você tem as permissões necessárias para obter registros de eventos.
- Execute o script regularmente, especialmente nos sistemas que contêm informações confidenciais.
- Investigue quaisquer padrões de logins com falha e notifique os usuários envolvidos.
Considerações finais
Na era das crescentes ameaças cibernéticas, ferramentas como o nosso script do PowerShell são essenciais. Para uma solução de segurança abrangente, plataformas como a NinjaOne podem ser integradas, garantindo o monitoramento e o gerenciamento em tempo real. O NinjaOne, combinado com scripts proativos como o discutido, fornece defesa adicional contra ameaças cibernéticas.