close up photo of ledger s list

NPS – log degli utenti connessi in VPN con MFA Microsoft

>>> Download: Scarica lo script da GitHub

Recentemente ho aggiunto la MFA di Microsoft usando Azure AD al sistema di VPN (basato su Fortigate) di un mio cliente, in modo che gli utenti siano costretti ad usare un secondo fattore di autenticazione prima di potersi connettere.

Dato che il firewall non è in gestione diretta al mio cliente, non avevamo a disposizione un sistema veloce per poter controllare chi si fosse connesso o meno, né c’era un sistema SIEM a disposizione cui poter affidare la cosa.

Mi è stato chiesto quindi di trovare un modo per poter avere velocemente a disposizione la lista degli utenti che si sono connessi con successo o meno in VPN nelle ultime 24 ore ed ho subito pensato alla PowerShell, dato che tutto il sistema si regge su un NPS su Windows Server ed è piuttosto facile filtrare l’event log Security per trovare le voci che ci interessano.

Ho sfruttato una funzione molto utile di Jeff Hicks, Convert-EventLogRecord, che mi permette di processare gli eventi estratti da una macchina Windows con la cmdlet Get-Winevent, e alcune funzioni che avevo scritto io in precedenza per il mio report mailbox di Exchange Online.

Combinando il tutto ho creato lo script Get-VpnConnectedUsers.ps1 che vedete qui sotto. Per funzionare correttamente, dovete piazzare nella stessa directory dello script il file Convert-EventLogRecord.ps1, che potete scaricare qui.

L’utilizzo è semplicissimo, basta specificare con la variabile $target il nome del server da cui estrarre i log. La macchina target deve avere abilitata la regola “Remote Event Log Management (RPC)” nel firewall di Windows (la trovate nella gestione avanzata del firewall), altrimenti lo script andrà in errore.

Il risultato può essere o un report a console oppure un file in formato HTML, basta cambiare la variabile relativa ($reportFormat) nella apposita sezione iniziale.

Lo script, al momento della esecuzione, richiederà delle credenziali amministrative della macchina cui ci si connette.

Il report contiene data e ora della connessione, username usato, indirizzo IP pubblico del client, risultato della connessione (Success/Failure) e Policy NPS usata. In futuro probabilmente lo rivedrò aggiungendo altre funzionalità.

Get-VpnConnectedUsers.ps1

#region Credits
# Author: Federico Lillacci - Coesione Srl - www.coesione.net
# GitHub: https://github.com/tsmagnum
# Version: 1.0
#endregion

[CmdletBinding()]
$creds = Get-Credential
$reportDate = Get-Date -UFormat %d%m%Y

#######################################
#region User-variables - General Settings
$target = "server" # insert your NPS server here
$reportFormat = "html" # "console","html"
$reportHtmlPath = "NPS_VPN_Report_"+ $reportDate +".html"
#endregion

#region HTML Code
$preContent = "<h2>VPN Report</h2>"
$postContent = "<p>Creation Date: $(Get-Date)<p>"
$title = "NPS VPN Report"
#endregion

#region CSS Code
$header = @"
<style>
    body
  {
      background-color: White;
      font-size: 12px;
      font-family: Arial, Helvetica, sans-serif;
  }

    table {
      border: 0.5px solid;
      border-collapse: collapse;
      width: 100%;
    }

    th {
        background-color: CornflowerBlue;
        color: white;
        padding: 6px;
        border: 0.5px solid;
        border-color: #000000;
    }

    tr:nth-child(even) {
            background-color: #f5f5f5;
        }

    td {
        padding: 6px;
        margin: 0px;
        border: 1px solid;
}

    h2{
        background-color: CornflowerBlue;
        color:white;
        text-align: center;
    }
</style>
"@
#endregion

#region Functions
function reportHtml {
        
        [CmdletBinding()]
        Param(
                [Parameter(Mandatory = $true)] $rawStats,
                [Parameter(Mandatory = $false)] [switch] $generateFile
        )
        
        if ($generateFile) 
        { 
                $rawStats | `
                ConvertTo-Html `
                        -PreContent $preContent `
                        -PostContent $postContent `
                        -Title $title `
                        -Head $header | `
                        Out-File -FilePath $reportHtmlPath
        }

        else 
        {
                $rawStats | `
                ConvertTo-Html `
                        -PreContent $preContent `
                        -PostContent $postContent `
                        -Title $title `
                        -Head $header 
        }
}

function reportConsole ($rawStats){
        $rawStats | Sort-Object -Property $sortBy -Descending | Format-Table -AutoSize -Wrap
}
#endregion
#######################################

#Dot-sourcing the required script to manage logs
. .\Convert-EventLogRecord.ps1

#Selecting the logs time frame
$date = (Get-Date).AddDays(-1)

#Getting logs
$rawData = Get-WinEvent -FilterHashtable @{Logname="Security"; ID='6272','6273','6274'; StartTime=$date} -Credential $creds -ComputerName $target

#Filtering and processing
$filteredData = $rawData | Convert-EventLogRecord | Select-Object `
            -Property @{Label="Time";Expression={$_.TimeCreated}},`
                    @{Label="User";Expression={$_.SubjectUserName}},`
                    @{Label="IP Address";Expression={$_.CallingStationID}},`
                    @{Label="Success-Fail";Expression={$_.Keywords}},`
                    @{Label="Policy";Expression={$_.ProxyPolicyName}}

#Generating the report
switch ($reportFormat) 
{
    console { reportConsole($filteredData)}
    html { reportHtml -rawStats $filteredData -generateFile }
}