Garantire la sicurezza dei sistemi informatici è un’attività cruciale. Identificare attività sospette, come ad esempio numerosi tentativi di login falliti, è una misura importante per ridurre i rischi delle potenziali minacce. Lo script fornito, scritto in PowerShell, è uno strumento versatile per aiutare i professionisti IT e gli MSP a ottenere informazioni sui tentativi di login non riusciti.
Background
Tracciare i tentativi di login non riusciti su un sistema può fornire informazioni cruciali per gli amministratori IT. Questi tentativi possono fornire informazioni su possibili violazioni della sicurezza, aiutare a monitorare i comportamenti degli utenti e a mantenere l’integrità del sistema. Lo script PowerShell fornito recupera in modo efficiente questi dati, offrendo una soluzione sicura per i professionisti. L’importanza di questo strumento non sarà mai sottolineata abbastanza. Con l’aumento delle minacce alla sicurezza informatica, disporre di un metodo efficiente per rilevare le anomalie nei login degli utenti diventa essenziale per gli MSP e i professionisti IT.
Lo script per ottenere informazioni sui tentativi di login non riusciti
#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 } } } }
Accedi a oltre 700 script nel Dojo di NinjaOne
Descrizione dettagliata dello script
Nella sua funzione principale, lo script recupera i dati dai log degli eventi di un determinato computer, cercando specifici ID evento che rappresentano i tentativi di accesso falliti e riusciti.
- Parametri: Lo script inizia definendo parametri come ComputerName, UserName e Detailed. Consente all’utente di specificare il computer, l’utente e il livello di dettaglio dei tentativi di accesso.
- Funzioni: Due funzioni, Get-FailureReason e Get-LogonType traducono le informazioni codificate dei log degli eventi in dati leggibili relativi al tipo di login e al motivo di un login fallito.
- Recupero degli eventi: Lo script recupera quindi i log degli eventi, filtrandoli per conservare solo le informazioni necessarie. Si tratta di selezionare le istanze con gli ID evento rilevanti.
- Elaborazione: Se vengono richiesti dati dettagliati, lo script fornisce un’analisi completa di ogni tentativo di accesso, altrimenti viene visualizzato un riepilogo dei tentativi falliti per ogni utente.
Possibili casi d’uso
Immagina un amministratore IT di un’azienda di medie dimensioni. Di recente, il reparto IT ha notato un incremento del numero di tentativi di accesso falliti, soprattutto durante le ore non lavorative. Utilizzando lo script, l’amministratore può verificare rapidamente quali utenti hanno effettuato tentativi di accesso non riusciti e con quale frequenza. Nel riscontrare che un singolo account utente ha fallito più tentativi in un breve intervallo di tempo, l’amministratore può concludere che questo account potrebbe essere stato compromesso. In questo modo, lo script favorisce il rilevamento tempestivo di un possibile problema e una pronta risoluzione.
Approccio alternativo
Esistono diversi metodi per tracciare i tentativi di login non riusciti. Il monitoraggio di sicurezza integrato di Windows, per esempio, consente di visualizzare i log di sicurezza tramite il Visualizzatore eventi. Sebbene questo approccio sia semplice, può richiedere molto tempo. Il nostro script PowerShell semplifica il processo, offrendo una soluzione più efficiente e personalizzabile.
Domande frequenti
- Come fa lo script a identificare un’attività di login fallita?
Lo script cerca ID evento specifici nel log eventi, ad esempio 4625 per i login non riusciti. - È possibile recuperare i dati da un computer remoto?
Sì, fornendo il parametro ComputerName è possibile ottenere dati da un computer remoto.
Implicazioni
Individuando i tentativi di accesso falliti, gli amministratori IT possono prevenire potenziali minacce alla sicurezza. Le anomalie nei modelli di login sono spesso un primo segnale di attività pericolose. Pertanto, agendo su questi dati, i professionisti possono rendere i loro sistemi più sicuri contro le potenziali minacce.
Raccomandazioni
- Assicurati di disporre delle autorizzazioni necessarie per recuperare i log degli eventi.
- Esegui lo script con regolarità, soprattutto per i sistemi che contengono informazioni sensibili.
- Esamina eventuali modelli di accessi non riusciti e informa gli utenti interessati.
Considerazioni finali
Nell’era delle crescenti minacce informatiche, strumenti come il nostro script PowerShell sono essenziali. Per una soluzione di sicurezza completa, è possibile implementare piattaforme come NinjaOne, che garantiscono il monitoraggio e la gestione in tempo reale. NinjaOne in combinazione con script proattivi come quello di cui abbiamo parlato, permette di ottenere un livello ulteriore di difesa contro le minacce informatiche.