Monitoraggio degli accessi tramite PowerShell

Come ho illustrato nel post Hardening di un server Remote Desktop PowerShell può tornare davvero utile come strumento per monitorare gli accessi ad un server particolarmente importante sotto il profilo della sicurezza.

Di seguito un semplice script PowerShell che può essere schedulato ad esempio ogni 30 minuti per analizzare l’EventViewer e verificare se vi sono stati accessi con l’utente Administrator o se vi sono stati tentativi di accesso falliti.

Lo script genera uno report che viene inviato tramite mail e permette le seguenti impostazioni:

  • $LastMinutes = Numero di minuti precedenti all’ora corrente da cui analizzare gli eventi
  • $FailedAccessThreshold = Numero di eventi di accesso fallito oltre cui inviare la mail di notifica
  • $AdminAccessThreshold = Numero di eventi di accesso con utente Administrator oltre cui inviare la mail di notifica
  • $SmtpServer = Sever SMTP a cui connettersi per inviare la mail
  • $MailFrom = Indirizzo mail da cui inviare il report
  • $MailTo = Indirizzo mail da cui inviare il report

# *** Impostazioni ***
$LastMinutes = 30
$FailedAccessThreshold = 15
$AdminAccessThreshold = 1
$SmtpServer = “Nome o IP Server SMTP
$MailFrom = “MailFromAddress
$MailTo = “MailToAddress
# ********************

#Ricerca tentativi di accesso con credenziali errate
$FailedAccessEvents = Get-EventLog -LogName Security -InstanceId 4625 -EntryType FailureAudit -After (Get-Date).AddMinutes(-1*$LastMinutes) -ErrorAction SilentlyContinue
$FailedAccessEventsCount = 0
If($FailedAccessEvents -ne $null) {$FailedAccessEventsCount = ($FailedAccessEvents | Measure).Count}

#Ricerca accessi con utente Administrator
$AdminAccessEvents = Get-EventLog -LogName Security -InstanceId 4624 -EntryType SuccessAudit -After (Get-Date).AddMinutes(-1*$LastMinutes) -ErrorAction SilentlyContinue
If($AdminAccessEvents -ne $null) {$AdminAccessEvents = $AdminAccessEvents | Where {$_.Message.Contains(“Administrator”) -And $_.Message.Contains(“winlogon.exe”)}}
$AdminAccessEventsCount = 0
If($AdminAccessEvents -ne $null) {$AdminAccessEventsCount = ($AdminAccessEvents | Measure).Count}

If($FailedAccessEventsCount -ge $FailedAccessThreshold -Or $AdminAccessEventsCount -ge $AdminAccessThreshold)
{
  # Invio Mail
  $MailSubject = “Allarme: $AdminAccessEventsCount accessi amministrativi e $FailedAccessEventsCount accessi falliti negli ultimi ” + $LastMinutes + ” minuti”
  If ($AdminAccessEventsCount -ne 0)
  {
    $MailBody = “Accessi con account Administrator:`n”
    ForEach ($event In $AdminAccessEvents) {
     $MailBody = $MailBody + $event.TimeGenerated + “`t da IP: ” + $event.ReplacementStrings[18] + “`n”
    }
  }

  If($FailedAccessEventsCount -ne 0)
  {
    $MailBody = $MailBody + “`n”
    $MailBody = $MailBody + “Tentativi di accesso con credenziali errate:`n”
    ForEach ($event In $FailedAccessEvents) {
      $MailBody = $MailBody + $event.TimeGenerated + “`t da IP: ” + $event.ReplacementStrings[19].PadRight(15) + “`t Utente: ”  + $event.ReplacementStrings[5] + “`n”
    }
  }

  Send-MailMessage -To $MailTo -Subject $MailSubject -From $MailFrom -Body $MailBody -SmtpServer $SmtpServer
}

Di seguito un esempio del report ricevuto:

image

E’ possibile schedulare lo script tramite un file cmd contente un comando di questo tipo:

%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe C:\Scripts\AnalisiAccessi.ps1

Per evitare che la finestra del prompt del dos venga visualizzata quando l’operazione schedulata viene eseguita mentre si è connessi in console impostare l’esecuzione del file cmd tramite l’utente System.

Lo script è stato testato su un sistema WS2008 R2 Sp1 potrebbe essere necessario ritoccare su altri sistemi il numero degli eventi analizzati (4625 per i tentativi di accesso e 4624 per gli accessi riusciti) oppure l’indice della proprietà ReplacementStrings che rappresenta l’array dei valori specifici per l’evento all’interno del testo fisso del messaggio.

Di seguito alcuni link che possono tornare utili per la compresione dello script:

[Update 01]

Aggiunta del common parameter –ErrorAction SilentlyContinue al CmdLet Get-EventLog per gestire il caso in cui non siano presenti gli eventi 4624 e 4625 senza generare errori.