Como usar o PowerShell para auditar configurações de segurança

1. Introdução à auditoria de segurança com PowerShell

A auditoria de configurações de segurança é o processo sistemático de verificar se os sistemas estão configurados de acordo com políticas e padrões estabelecidos. Automatizar esse processo com PowerShell oferece vantagens significativas sobre ferramentas gráficas: repetibilidade, escalabilidade, capacidade de gerar relatórios padronizados e integração com pipelines de DevOps.

O PowerShell permite auditar centenas de máquinas em minutos, comparar configurações atuais com baselines de segurança (como CIS Benchmarks ou STIGs) e gerar relatórios detalhados sem intervenção manual.

Pré-requisitos:
- Execute o PowerShell como Administrador
- Habilite a execução de scripts: Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
- Verifique se os módulos necessários estão disponíveis: Get-Module -ListAvailable

2. Coletando informações de políticas de segurança locais

O comando secedit e o módulo SecurityPolicy permitem exportar e analisar políticas de segurança locais.

Exportando a política de segurança atual:

secedit /export /cfg C:\Temp\secpol.inf
Get-Content C:\Temp\secpol.inf | Select-String "PasswordComplexity|MinimumPasswordLength|LockoutBadCount"

Analisando políticas de senha com PowerShell puro:

$policy = Get-CimInstance -ClassName Win32_AccountPolicy -Namespace root\rsop\computer
$policy | Select-Object Name, Value | Format-Table -AutoSize

Comparação com baseline de segurança:

$baseline = @{
    "PasswordComplexity" = 1
    "MinimumPasswordLength" = 14
    "LockoutThreshold" = 5
}

$current = Get-CimInstance -ClassName Win32_AccountPolicy -Namespace root\rsop\computer
foreach ($item in $current) {
    if ($baseline.ContainsKey($item.Name)) {
        if ($item.Value -ne $baseline[$item.Name]) {
            Write-Warning "Configuração fora do baseline: $($item.Name) = $($item.Value) (esperado: $($baseline[$item.Name]))"
        }
    }
}

3. Verificando permissões de arquivos e pastas críticas

O Get-Acl é a ferramenta principal para auditar permissões NTFS.

Auditando diretórios críticos:

$criticalPaths = @(
    "C:\Windows\System32",
    "C:\Windows\System32\config",
    "C:\Program Files",
    "C:\Program Files (x86)"
)

foreach ($path in $criticalPaths) {
    $acl = Get-Acl -Path $path
    Write-Host "=== $path ===" -ForegroundColor Cyan
    $acl.Access | Where-Object { $_.FileSystemRights -match "FullControl|Modify" } | 
        Select-Object IdentityReference, FileSystemRights | Format-Table -AutoSize
}

Identificando proprietários inesperados:

Get-ChildItem C:\Windows\System32 -Recurse -ErrorAction SilentlyContinue | 
    Where-Object { $_.PSIsContainer -eq $false } | 
    ForEach-Object {
        $owner = (Get-Acl $_.FullName).Owner
        if ($owner -notlike "NT AUTHORITY\*" -and $owner -notlike "BUILTIN\*") {
            [PSCustomObject]@{
                Path = $_.FullName
                Owner = $owner
            }
        }
    } | Export-Csv C:\Temp\owners_anomalos.csv -NoTypeInformation

4. Auditando serviços e processos do Windows

Listando serviços vulneráveis ou desnecessários:

Get-Service | Where-Object { 
    $_.StartType -eq "Automatic" -and 
    $_.Status -eq "Running" -and
    $_.Name -match "RemoteRegistry|Telnet|FTP"
} | Select-Object Name, DisplayName, Status | Format-Table -AutoSize

Verificando assinaturas digitais de processos:

Get-Process | Where-Object { $_.MainModule.FileName -ne $null } | 
    ForEach-Object {
        $signature = Get-AuthenticodeSignature -FilePath $_.MainModule.FileName -ErrorAction SilentlyContinue
        [PSCustomObject]@{
            ProcessName = $_.ProcessName
            PID = $_.Id
            FilePath = $_.MainModule.FileName
            Status = $signature.Status
            SignerCertificate = $signature.SignerCertificate.Subject
        }
    } | Where-Object { $_.Status -ne "Valid" } | Export-Csv C:\Temp\processos_sem_assinatura.csv -NoTypeInformation

Detectando serviços com contas de alto privilégio:

Get-CimInstance -ClassName Win32_Service | 
    Where-Object { $_.StartName -match "LocalSystem|NetworkService|LocalService" } | 
    Select-Object Name, StartName, State | Format-Table -AutoSize

5. Análise de configurações de rede e firewall

Auditando regras de firewall ativas:

Get-NetFirewallRule | Where-Object { $_.Enabled -eq $true -and $_.Direction -eq "Inbound" } | 
    Select-Object DisplayName, Direction, Action, Profile | Format-Table -AutoSize

Verificando portas abertas e conexões ativas:

Get-NetTCPConnection | 
    Where-Object { $_.State -eq "Listen" } | 
    Select-Object LocalPort, OwningProcess | 
    Sort-Object LocalPort | Format-Table -AutoSize

Identificando regras de bloqueio ausentes:

$criticalPorts = @(22, 3389, 445, 135, 1433)
$existingRules = Get-NetFirewallRule | Where-Object { $_.Direction -eq "Inbound" -and $_.Action -eq "Block" }

foreach ($port in $criticalPorts) {
    $ruleExists = $existingRules | Where-Object { 
        ($_ | Get-NetFirewallPortFilter).LocalPort -eq $port 
    }
    if (-not $ruleExists) {
        Write-Warning "Porta $port sem regra de bloqueio explícita"
    }
}

6. Verificando contas de usuário e grupos de segurança

Listando membros de grupos privilegiados:

$privilegedGroups = @("Administradores", "Administradores de Domínio", "Operadores de Contas", "Operadores de Backup")
foreach ($group in $privilegedGroups) {
    try {
        $members = Get-LocalGroupMember -Group $group -ErrorAction Stop
        Write-Host "=== $group ===" -ForegroundColor Yellow
        $members | Select-Object Name, PrincipalSource | Format-Table -AutoSize
    } catch {
        Write-Warning "Grupo $group não encontrado"
    }
}

Auditando contas inativas e senhas expiradas:

Get-LocalUser | Where-Object { $_.Enabled -eq $true } | 
    ForEach-Object {
        $user = $_
        $lastLogon = (Get-CimInstance -ClassName Win32_UserProfile | 
            Where-Object { $_.SID -eq $user.SID }).LastUseTime
        [PSCustomObject]@{
            UserName = $user.Name
            SID = $user.SID
            PasswordExpired = $user.PasswordExpired
            LastLogon = $lastLogon
            DaysSinceLastLogon = if ($lastLogon) { (Get-Date) - $lastLogon | Select-Object -ExpandProperty Days } else { "Nunca" }
        }
    } | Where-Object { $_.DaysSinceLastLogon -gt 90 -or $_.DaysSinceLastLogon -eq "Nunca" } | 
    Export-Csv C:\Temp\contas_inativas.csv -NoTypeInformation

7. Gerando relatórios e dashboards de auditoria

Exportando resultados para CSV:

$report = @()
$report += Get-LocalUser | Select-Object Name, Enabled, PasswordExpired, LastLogon
$report += Get-Service | Select-Object Name, Status, StartType
$report += Get-NetFirewallRule | Select-Object DisplayName, Direction, Action, Enabled
$report | Export-Csv C:\Temp\auditoria_completa.csv -NoTypeInformation -Encoding UTF8

Gerando relatório HTML com formatação:

$htmlHeader = @"
<!DOCTYPE html>
<html>
<head>
    <title>Relatório de Auditoria de Segurança</title>
    <style>
        body { font-family: Arial, sans-serif; margin: 20px; }
        table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
        th { background-color: #4CAF50; color: white; padding: 8px; text-align: left; }
        td { border: 1px solid #ddd; padding: 8px; }
        tr:nth-child(even) { background-color: #f2f2f2; }
        h2 { color: #333; border-bottom: 2px solid #4CAF50; padding-bottom: 5px; }
        .warning { background-color: #ff9800; color: white; padding: 10px; margin: 10px 0; }
    </style>
</head>
<body>
    <h1>Relatório de Auditoria de Segurança</h1>
    <p>Gerado em: $(Get-Date)</p>
"@

$htmlFooter = "</body></html>"

$usuarios = Get-LocalUser | Select-Object Name, Enabled, PasswordExpired | ConvertTo-Html -Fragment
$servicos = Get-Service | Where-Object { $_.Status -eq "Running" } | Select-Object Name, DisplayName | ConvertTo-Html -Fragment
$firewall = Get-NetFirewallRule | Where-Object { $_.Enabled -eq $true } | Select-Object DisplayName, Direction, Action | ConvertTo-Html -Fragment

$htmlBody = @"
    <h2>Usuários Locais</h2>
    $usuarios
    <h2>Serviços em Execução</h2>
    $servicos
    <h2>Regras de Firewall Ativas</h2>
    $firewall
"@

$htmlHeader + $htmlBody + $htmlFooter | Out-File C:\Temp\auditoria_seguranca.html -Encoding UTF8

Agendando auditoria recorrente com Task Scheduler:

$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-File C:\Scripts\auditoria.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "02:00AM"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName "AuditoriaSegurancaDiaria" -Action $action -Trigger $trigger -Principal $principal

Referências