kbase.pt  |  Segurança

Segurança Active Directory: Prevenir Escalação de Privilégios entre Florestas em 2026

Autor: Duarte Spínola

Data: 2026-07-02

Tags: Active Directory · Segurança · Escalação de Privilégios · SID History · RODC · Tier 0

O Risco da Escalação de Privilégios no Active Directory

O Active Directory (AD) permanece, em 2026, o pilar de identidade da maioria das organizações portuguesas e europeias. Apesar do avanço das soluções em nuvem como o Microsoft Entra ID, o AD on-premises continua a ser o alvo preferencial de atacantes que procuram obter controlo total sobre o ambiente corporativo. A escalação de privilégios — o processo pelo qual um atacante eleva os seus direitos de um utilizador comum para administrador de domínio ou administrador de empresa — é a técnica mais devastadora no arsenal de um adversário.

O risco é particularmente grave em ambientes multi-floresta, onde trusts entre florestas podem ser abusados para saltar de uma floresta menos protegida para outra contendo recursos críticos. Em 2026, com o aumento de ataques de ransomware orientados por identidade (como os associados ao Microsoft Threat Intelligence), a proteção contra escalação entre florestas deixou de ser uma recomendação opcional e passou a ser um requisito de conformidade.

Perigo crítico: Um único trust mal configurado pode permitir que um atacante comprometa uma floresta periférica e, a partir dela, obtenha privilégios de Administrador de Empresa na floresta principal. Este é o cenário de pior caso, conhecido como cross-forest privilege escalation.

As estatísticas são claras: mais de 80% dos ataques bem-sucedidos contra infraestruturas AD envolvem alguma forma de escalação de privilégios, seja através de kerberoasting, abuso de SID History, delegação excessiva de permissões ou exploração de contas de serviço com privilégios excessivos. Este artigo aborda, de forma prática e orientada para administradores portugueses de PME, as medidas essenciais para prevenir a escalação de privilégios entre florestas no Active Directory em 2026.

Como Funciona a Escalação entre Florestas

Para compreender como prevenir a escalação entre florestas, é fundamental entender o mecanismo de ataque. O AD usa o protocolo Kerberos para autenticação, e os trusts entre florestas estabelecem relações de confiança que permitem que utilizadores de uma floresta acedam a recursos noutra. No entanto, esta conveniência vem com riscos significativos.

Quando um trust de floresta é estabelecido entre a Floresta A e a Floresta B, o Kerberos permite a emissão de TGTs (Ticket-Granting Tickets) cruzados. Um atacante que comprometa uma conta com privilégios elevados na Floresta A pode, dependendo da configuração do trust, solicitar service tickets para recursos na Floresta B. Se o trust permitir autenticação selectiva (selective authentication) ou se a filtragem de SID estiver desactivada, o atacante pode herdar os privilégios associados aos SIDs na sua PAC (Privilege Attribute Certificate), incluindo SIDs armazenados no atributo sIDHistory.

O fluxo típico de um ataque de escalação entre florestas segue estes passos:

Fase Acção do Atacante Vetor
1. Reconhecimento Mapeia trusts e permissões com BloodHound LDAP queries
2. Compromisso inicial Obtém credenciais de conta comum na Floresta A Phishing / spray
3. Escalação local Eleva para admin de domínio na Floresta A Kerberoasting / ACL abuse
4. Abuso de trust Solicita TGT para Floresta B via trust SID History / delegation
5. Compromisso total Obtém Enterprise Admin na Floresta B Cross-forest TGT

O conceito chave é que um trust de floresta não é uma relação simétrica de confiança total por omissão. Existem configurações que podem limitar significativamente o impacto de um compromisso, nomeadamente a filtragem de SID (SID filtering), a autenticação selectiva (selective authentication) e a quarentena de trust (quarantine). Veremos cada uma destas em detalhe nas próximas secções.

Nota importante: Em 2026, a Microsoft recomenda oficialmente que qualquer trust entre florestas com diferentes níveis de sensibilidade seja configurado com filtragem de SID activa e autenticação selectiva. O trust deve ser tratado como um limite de segurança, não como uma conveniência administrativa.

SID History e os Perigos da Migração

O atributo sIDHistory foi introduzido pela Microsoft para permitir migrações entre domínios e florestas, preservando o acesso a recursos. Quando um utilizador é migrado de um domínio para outro, o seu novo SID é diferente do original, e o SID antigo é adicionado ao sIDHistory para que continue a ter acesso aos recursos que já tinha permissão para aceder.

O problema surge quando este atributo é maliciosamente manipulado ou permanece populado após a migração estar concluída. Um atacante que comprometa uma conta pode injetar SIDs administrativos no sIDHistory, efetivamente escalando privilégios sem alterar a pertença a grupos. Esta técnica é conhecida como SID History Injection e foi popularizada por ferramentas como Mimikatz (comando sid:add).

A filtragem de SID é a defesa primária contra este ataque. Quando activada, o controlador de domínio da floresta receptora remove quaisquer SIDs no sIDHistory que pertençam a outra floresta antes de os incluir na PAC do ticket Kerberos. No entanto, a filtragem nem sempre está activa por omissão, especialmente em trusts legados.

# Verificar o estado da filtragem de SID num trust de floresta
Get-ADTrust -Filter "Direction -ne 'Disabled'" -Properties * |
  Select-Object Name, Direction, SIDFilteringForestAware,
    QuarantineOn, SelectiveAuthentication,
    ForestTransitive, InboundTrust, OutboundTrust |
  Format-Table -AutoSize

# Activar filtragem de SID num trust existente (inbound)
Set-ADTrust -Identity "floresta-parceiro.local" `
  -SIDFilteringForestAware $true

# Verificar contas com SIDHistory populado
Get-ADUser -LDAPFilter "(sIDHistory=*)" -Properties sIDHistory |
  Select-Object Name, SAMAccountName, SID, sIDHistory |
  Format-Table -AutoSize

# Contar contas com SIDHistory em todo o domínio
(Get-ADUser -LDAPFilter "(sIDHistory=*)").Count

Atenção: Se encontrar contas com sIDHistory populado numa floresta onde não ocorreram migrações recentes, isto pode indicar compromisso. Investigue imediatamente a origem dos SIDs no atributo e compare com os SIDs esperados das migrações legítimas.

A limpeza do sIDHistory deve ser feita após a migração estar completamente validada e todos os recursos actualizados para usar o novo SID. A Microsoft fornece a ferramenta SID History Clean-up através do PowerShell para esta operação:

# Remover SID History de uma conta específica após migração validada
# Requer ferramentas ADMT ou script customizado

$user = Get-ADUser -Identity "joao.silva" -Properties sIDHistory
foreach ($oldSid in $user.sIDHistory) {
    Write-Host "A remover SID: $oldSid" -ForegroundColor Yellow
    # Usar ADSI para limpar o atributo
    $dn = $user.DistinguishedName
    $adsi = [ADSI]"LDAP://$dn"
    $adsi.PutEx(1, "sIDHistory", $null)
    $adsi.SetInfo()
    Write-Host "SID removido com sucesso." -ForegroundColor Green
}

# Verificar que foi limpo
Get-ADUser -Identity "joao.silva" -Properties sIDHistory |
  Select-Object Name, sIDHistory

Trusts de Floresta: Configuração Segura

Os trusts de floresta são necessários quando múltiplas florestas precisam de partilhar recursos, mas devem ser configurados com o princípio do menor privilégio. As três configurações de segurança essenciais são:

Configuração Função Recomendação 2026
SID Filtering Remove SIDs estrangeiros da PAC Sempre activo
Selective Authentication Exige permissão explícita por servidor Recomendado para florestas de menor confiança
Quarantine (EnableQuarantine) Bloqueia todas as SIDs excepto os da floresta local Para trusts de menor confiança
Forest Transitive Permite transitividade entre todos os domínios Avaliar caso a caso
# Listar todos os trusts do domínio com propriedades de segurança
Get-ADTrust -Filter * -Properties * |
  Select-Object Name, Direction, TrustType,
    ForestTransitive, SelectiveAuthentication,
    SIDFilteringForestAware, QuarantineOn |
  Sort-Object Name |
  Format-Table -AutoSize

# Activar autenticação selectiva num trust de floresta
Set-ADTrust -Identity "filial.local" `
  -SelectiveAuthentication $true

# Activar quarentena (filtragem total) num trust
# netdom é necessário para esta operação específica
netdom trust floresta-parceiro.local /Domain:corp.local `
  /Quarantine:Yes

# Verificar que a quarentena está activa
netdom trust floresta-parceiro.local /Domain:corp.local /Quarantine

A combinação de autenticação selectiva com filtragem de SID cria um modelo de defesa em profundidade. Com a autenticação selectiva, os administradores têm de conceder explicitamente permissão Allowed to Authenticate a cada servidor individual, reduzindo drasticamente a superfície de ataque.

# Conceder permissão "Allowed to Authenticate" a um grupo
# de uma floresta confiada para um servidor específico

$serverDN = "CN=SRV-FICHEIROS,OU=Servidores,DC=corp,DC=local"
$groupSID = "S-1-5-21-1234567890-1234567890-1234567890-1234"
$group = New-Object System.Security.Principal.SecurityIdentifier($groupSID)

$acl = Get-Acl "AD:\$serverDN"
$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule(
    $group,
    [System.DirectoryServices.ActiveDirectoryRights]::ExtendedRight,
    [System.Security.AccessControl.AccessControlType]::Allow,
    [System.Guid]"7b2fe635-e082-46f6-B2D0-89CE9B79E2AD"
)
$acl.AddAccessRule($ace)
Set-Acl -Path "AD:\$serverDN" -AclObject $acl

Write-Host "Permissão 'Allowed to Authenticate' concedida." -ForegroundColor Green

Dica: O GUID 7b2fe635-e082-46f6-B2D0-89CE9B79E2AD corresponde ao direito estendido “Allowed to Authenticate”. Esta é a forma programática de conceder a permissão sem usar a GUI do Active Directory Users and Computers.

Modelo Tier 0 da Microsoft

O Modelo Tier (Tier Model) é a arquitetura de segurança recomendada pela Microsoft para proteger contas e recursos administrativos do Active Directory. Foi introduzido como parte da documentação de Privileged Access Management (PAM) e permanece, em 2026, a referência para segmentação administrativa.

O modelo divide a infraestrutura em três camadas (tiers), cada uma com um nível de controlo distinto:

Tier Âmbito Exemplos de Recursos Contas Típicas
Tier 0 Controlo total do AD DCs, KRBTGT, grupos Domain Admins, Enterprise Admins, Schema Admins Admin-T0-nome
Tier 1 Servidores e aplicações Servidores de ficheiros, SQL, Exchange, SharePoint Admin-T1-nome
Tier 2 Workstations e utilizadores PCs, portáteis, dispositivos de utilizador Admin-T2-nome

A regra fundamental do modelo é a proibição de fluxo descendente de controlo: uma conta de Tier 0 nunca deve autenticar-se num servidor de Tier 1 ou numa workstation de Tier 2. Se o fizer, e se essa máquina estiver comprometida, as credenciais de Tier 0 podem ser roubadas (por exemplo, com credential theft via Mimikatz), comprometendo todo o AD.

# Identificar membros de grupos Tier 0 (contas críticas)
$tier0Groups = @(
    "Domain Admins",
    "Enterprise Admins",
    "Schema Admins",
    "Administrators",
    "Account Operators",
    "Backup Operators",
    "Server Operators",
    "Print Operators",
    "Cert Publishers",
    "DnsAdmins"
)

foreach ($group in $tier0Groups) {
    $members = Get-ADGroupMember -Identity $group -Recursive -ErrorAction SilentlyContinue
    $count = if ($members) { $members.Count } else { 0 }
    Write-Host "$group : $count membros" -ForegroundColor Cyan
    if ($count -gt 0) {
        $members | Select-Object Name, ObjectClass, SID |
          Format-Table -AutoSize
    }
}
# Criar estrutura de OU para o modelo Tier na organização
$domain = (Get-ADDomain).DistinguishedName

# OU Admin Tier 0
New-ADOrganizationalUnit -Name "Admin-Tier0" `
  -Path "OU=Admin,OU=TierModel,$domain" `
  -Description "Contas e grupos administrativos Tier 0" `
  -ProtectedFromAccidentalDeletion $true

# OU Admin Tier 1
New-ADOrganizationalUnit -Name "Admin-Tier1" `
  -Path "OU=Admin,OU=TierModel,$domain" `
  -Description "Contas administrativas de servidores Tier 1" `
  -ProtectedFromAccidentalDeletion $true

# OU Servidores Tier 1
New-ADOrganizationalUnit -Name "Servidores-Tier1" `
  -Path "OU=TierModel,$domain" `
  -Description "Servidores geridos por contas Tier 1" `
  -ProtectedFromAccidentalDeletion $true

# OU Workstations Tier 2
New-ADOrganizationalUnit -Name "Workstations-Tier2" `
  -Path "OU=TierModel,$domain" `
  -Description "Workstations de utilizadores Tier 2" `
  -ProtectedFromAccidentalDeletion $true

Write-Host "Estrutura de OU Tier criada com sucesso." -ForegroundColor Green

Regra de ouro: Um administrador de Tier 0 deve ter duas contas distintas — uma para uso diário (sem privilégios) e uma para tarefas administrativas (Tier 0). A conta administrativa nunca deve ser usada para aceder a email, navegação web ou workstations de utilizadores. Considere usar Privileged Access Workstations (PAWs) para todas as tarefas de Tier 0.

Contas de Emergência (Break Glass)

As contas de emergência, ou Break Glass, são contas administrativas que existem especificamente para acesso de último recurso quando todos os outros métodos de autenticação falham — por exemplo, quando o MFA está indisponível, o Entra Connect está em baixo, ou um ataque de ransomware comprometeu todas as contas administrativas normais.

Estas contas devem seguir regras rigorosas de configuração e gestão:

  • Devem ser armazenadas num cofre físico (por exemplo, um safe na sala de servidores) com registo de acesso assinado por duas pessoas.
  • A password deve ter pelo menos 30 caracteres, ser gerada aleatoriamente e nunca ser conhecida por uma única pessoa (dividir em duas partes, cada uma guardada por pessoa diferente).
  • Não devem ter MFA associado, para garantir acesso em qualquer cenário.
  • Devem ser monitorizadas: qualquer logon deve gerar um alerta imediato para a equipa de segurança.
  • Devem ser validadas periodicamente (pelo menos trimestralmente) sem que a password seja divulgada.
# Criar contas Break Glass no Active Directory
$domain = (Get-ADDomain).DNSRoot

# Gerar password aleatória de 32 caracteres
$chars = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789!@#%^&*"
$password = -join ((1..32) | ForEach-Object {
    $chars[(Get-Random -Maximum $chars.Length)]
})
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force

# Criar conta Break Glass 1
New-ADUser -Name "BG-Admin-Emergencia-01" `
  -SamAccountName "bg-admin-01" `
  -Path "OU=Admin,OU=TierModel,DC=corp,DC=local" `
  -AccountPassword $securePassword `
  -Enabled $true `
  -Description "CONTA BREAK GLASS - NÃO USAR SEM AUTORIZAÇÃO" `
  -PasswordNeverExpires $true `
  -CannotChangePassword $true `
  -SmartcardLogonRequired $false

# Adicionar a Domain Admins
Add-ADGroupMember -Identity "Domain Admins" -Members "bg-admin-01"

# Configurar logon restrito a Domain Controllers apenas
Set-ADUser -Identity "bg-admin-01" `
  -LogonWorkstations "DC01,DC02,DC03"

Write-Host "Conta Break Glass criada. Guardar password em cofre físico!" -ForegroundColor Red
Write-Host "NÃO exibir a password no ecrã - usar cofre seguro." -ForegroundColor Yellow
# Configurar alerta para qualquer logon de conta Break Glass
# Via Windows Event Forwarding (WEF) ou regra de Defender para Identidade

# Verificar eventos de logon das contas Break Glass nos últimos 7 dias
$bgAccounts = @("bg-admin-01", "bg-admin-02")
$startDate = (Get-Date).AddDays(-7)

foreach ($account in $bgAccounts) {
    $events = Get-WinEvent -FilterHashtable @{
        LogName = 'Security'
        Id = 4624
        StartTime = $startDate
    } -ErrorAction SilentlyContinue |
      Where-Object { $_.Properties[5].Value -match $account }

    $count = if ($events) { $events.Count } else { 0 }
    Write-Host "$account : $count logons nos últimos 7 dias" -ForegroundColor Cyan

    if ($count -gt 0) {
        Write-Host "ALERTA: Conta Break Glass usada! Verificar legitimidade." -ForegroundColor Red
        $events | Select-Object TimeCreated, Id,
          @{N='Conta';E={$_.Properties[5].Value}},
          @{N='Origem';E={$_.Properties[11].Value}} |
          Format-Table -AutoSize
    }
}

Recomendação: Crie pelo menos duas contas Break Glass independentes. Se uma estiver comprometida ou inacessível, a outra funciona como backup. Ambas devem seguir o mesmo protocolo de cofre físico e auditoria.

Proteger o KRBTGT

A conta KRBTGT é a conta de serviço do Kerberos que assina e cifra todos os TGTs emitidos num domínio. Quem possuir a password do KRBTGT pode forjar TGTs arbitrários, concedendo-se a si próprio qualquer privilégio no domínio — é o chamado ataque Golden Ticket. Se um atacante comprometer a conta KRBTGT, o compromisso persiste mesmo depois de todas as outras passwords serem alteradas.

A protecção do KRBTGT envolve várias camadas:

  • Rotação periódica da password: A Microsoft recomenda rodar a password do KRBTGT pelo menos duas vezes por ano. Após um compromisso confirmado, a password deve ser rodada duas vezes (para invalidar todos os tickets anteriores, incluindo os que usam a password mais antiga em cache).
  • Monitorização de uso: Qualquer logon da conta KRBTGT fora dos controladores de domínio é altamente suspeito.
  • Desactivação da conta: A conta KRBTGT deve permanecer desactivada para logon interactivo (é usada apenas internamente pelo Kerberos).
  • Windows Server 2025+: Nas versões mais recentes, o KRBTGT suporta chaves AES-256 por omissão, melhorando a resistência contra offline cracking.
# Verificar estado da conta KRBTGT
Get-ADUser -Identity "krbtgt" -Properties * |
  Select-Object Name, Enabled, LastLogonDate, PasswordLastSet,
    PasswordNeverExpires, SID, whenCreated |
  Format-List

# Verificar a última vez que a password do KRBTGT foi alterada
$krbtgt = Get-ADUser -Identity "krbtgt" -Properties PasswordLastSet
$daysSinceChange = (Get-Date) - $krbtgt.PasswordLastSet
Write-Host "Última alteração da password KRBTGT: $($krbtgt.PasswordLastSet)" -ForegroundColor Cyan
Write-Host "Dias desde a alteração: $($daysSinceChange.Days)" -ForegroundColor Yellow
if ($daysSinceChange.Days -gt 180) {
    Write-Host "ALERTA: Passou mais de 180 dias. Rodar a password!" -ForegroundColor Red
}
# Rodar a password do KRBTGT (operação normal - 1x)
# ATENÇÃO: Numa resposta a incidente, executar DUAS VEZES com
# intervalo suficiente para replicação (verificar replicação entre DCs)

Reset-ADServiceAccount -Identity "krbtgt"

# Verificar replicação da nova password para todos os DCs
Get-ADDomainController -Filter * |
  ForEach-Object {
    $dc = $_.HostName
    try {
      $result = Invoke-Command -ComputerName $dc -ScriptBlock {
        Get-ADUser -Identity "krbtgt" -Properties PasswordLastSet
      } -ErrorAction Stop
      Write-Host "$dc : PasswordLastSet = $($result.PasswordLastSet)" -ForegroundColor Green
    } catch {
      Write-Host "$dc : ERRO - Não foi possível verificar" -ForegroundColor Red
    }
  }

Procedimento de resposta a incidente Golden Ticket: Se confirmar um ataque Golden Ticket, deve rodar a password do KRBTGT duas vezes. A primeira rotação invalida tickets assinados com a password actual. A segunda rotação (após replicação completa) invalida tickets assinados com a password anterior, que estava em cache. Entre as duas rotações, deve aguardar que a replicação do AD complete em todos os DCs — tipicamente 1 a 10 horas dependendo da topologia.

Configurar RODC (Read-Only Domain Controller)

Um RODC (Read-Only Domain Controller) é um controlador de domínio que mantém uma réplica de leitura da base de dados do AD e não armazena passwords de contas, excepto as explicitamente autorizadas. O RODC é ideal para localizações fisicamente inseguras, como filiais sem sala de servidores dedicada ou escritórios remotos com controlo de acesso limitado.

As vantagens do RODC para prevenção de escalação de privilégios são significativas:

  • Se um RODC for fisicamente comprometido, o atacante não obtém hashes de passwords administrativas.
  • O RODC não pode ser usado para replicar alterações para outros DCs, limitando a propagação de alterações maliciosas.
  • As credenciais em cache são controladas por uma Password Replication Policy (PRP), permitindo escolher exactamente quais contas podem ter a password em cache.
  • O RODC tem um modo de encaminhamento de autenticação que envia pedidos de contas não autorizadas para um DC gravável.
# Pré-preparar a instalação de um RODC no domínio
# Executar no DC gravável com privilégios de Domain Admin

# Criar a conta do RODC antes da instalação (staged RODC)
New-ADDSReadOnlyDomainControllerAccount `
  -DomainControllerAccountName "RODC-FILIAL-01" `
  -DomainName "corp.local" `
  -SiteName "Site-Filial-Porto" `
  -AllowPasswordReplicationAccountName @(
      "CORP\RODC-Admins-Filial",
      "CORP\computadores-filial$"
  ) `
  -DenyPasswordReplicationAccountName @(
      "CORP\Domain Admins",
      "CORP\Enterprise Admins",
      "CORP\Schema Admins",
      "CORP\krbtgt",
      "CORP\bg-admin-01",
      "CORP\bg-admin-02"
  )

Write-Host "Conta RODC pré-criada. Proceder à instalação no servidor." -ForegroundColor Green
# Verificar a Password Replication Policy (PRP) de um RODC existente
Get-ADDomainControllerPasswordReplicationPolicy `
  -Identity "RODC-FILIAL-01" |
  Format-List

# Listar contas cujas passwords estão actualmente em cache no RODC
Get-ADDomainControllerAccountPasswordReplicationPolicy `
  -Identity "RODC-FILIAL-01" |
  Select-Object Name, SAMAccountName, ObjectClass, LastLogonDate |
  Format-Table -AutoSize

# Adicionar um grupo à lista de permissão de replicação de passwords
Add-ADDomainControllerPasswordReplicationPolicy `
  -Identity "RODC-FILIAL-01" `
  -AllowedList "CORP\Utilizadores-Filial-Porto"

# Verificar contas negadas (devem incluir todos os grupos Tier 0)
Get-ADDomainControllerPasswordReplicationPolicy `
  -Identity "RODC-FILIAL-01" -DeniedList |
  Select-Object Name, SAMAccountName |
  Format-Table -AutoSize

Boa prática: Configure a lista de negação (Denied List) do RODC com todos os grupos Tier 0, contas de serviço com privilégios e contas Break Glass. A lista de permissão (Allowed List) deve conter apenas contas de utilizadores comuns da filial que precisam de autenticar mesmo sem conectividade ao DC principal.

Auditar Alterações de Privilégios

A auditoria de alterações de privilégios é uma das defesas mais importantes contra escalação silenciosa. O AD regista alterações de grupo e de permissões nos Event Logs de Segurança, mas é necessário activar as subcategorias de auditoria correctas e monitorizar os eventos relevantes.

As subcategorias de auditoria essenciais para detecção de escalação de privilégios são:

Subcategoria Event IDs O que detecta
Audit User Account Management 4720, 4722, 4723, 4724, 4738 Criação/alteração/activação de contas
Audit Security Group Management 4728, 4729, 4730, 4732, 4733 Adição/remoção de membros de grupos
Audit Directory Service Access 4662, 5136, 5137, 5141 Alterações a objectos do AD (ACLs, atributos)
Audit Authentication Policy Change 4713, 4716, 4717 Alterações a políticas de autenticação e trusts
Audit Special Privilege Use 4673, 4674 Uso de privilégios sensíveis (SeDebug, SeTcb)
# Activar auditoria avançada de alterações de privilégios via PowerShell
# Executar num Domain Controller com privilégios de administrador

# Activar subcategorias de auditoria críticas
auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable
auditpol /set /subcategory:"Security Group Management" /success:enable /failure:enable
auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable
auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable
auditpol /set /subcategory:"Authentication Policy Change" /success:enable /failure:enable
auditpol /set /subcategory:"Special Privilege Use" /success:enable /failure:enable
auditpol /set /subcategory:"Kerberos Authentication Service" /success:enable /failure:enable
auditpol /set /subcategory:"Kerberos Service Ticket Operations" /success:enable /failure:enable

# Verificar configuração actual
auditpol /get /category:* | findstr /i "Management\|Directory\|Kerberos\|Privilege"
# Detectar adições a grupos privilegiados nas últimas 24 horas
$startDate = (Get-Date).AddHours(-24)
$privilegedGroups = @("Domain Admins", "Enterprise Admins",
    "Administrators", "Schema Admins", "Account Operators")

foreach ($group in $privilegedGroups) {
    $groupDN = (Get-ADGroup -Identity $group).DistinguishedName

    $events = Get-WinEvent -FilterHashtable @{
        LogName = 'Security'
        Id = @(4728, 4732, 4756)  # Member added to groups
        StartTime = $startDate
    } -ErrorAction SilentlyContinue |
      Where-Object {
        $_.Properties[1].Value -match [regex]::Escape($groupDN)
      }

    if ($events) {
        Write-Host "ALTERAÇÕES NO GRUPO '$group':" -ForegroundColor Yellow
        $events | Select-Object TimeCreated,
          @{N='AdicionadoPor';E={$_.Properties[6].Value}},
          @{N='Membro';E={$_.Properties[2].Value}} |
          Format-Table -AutoSize
    } else {
        Write-Host "Grupo '$group': sem alterações nas últimas 24h" -ForegroundColor Green
    }
}

Recomendação de arquitetura: Encaminhe os logs de segurança de todos os DCs para um SIEM centralizado (Microsoft Sentinel, Splunk ou Elastic Security) usando Windows Event Forwarding (WEF). Isto garante que mesmo que um DC seja comprometido, os logs não são perdidos. Configure alertas em tempo real para os eventos 4728 (membro adicionado a grupo global) e 4756 (membro adicionado a grupo universal).

Detectar Ataques com Defender para Identidade

O Microsoft Defender para Identidade (anteriormente Azure ATP) é a solução da Microsoft para detecção de ataques orientados a identidade no Active Directory. Em 2026, é a ferramenta recomendada para organizações que usam AD on-premises, integrando-se nativamente com o Microsoft Defender XDR e o Sentinel.

O Defender para Identidade detecta automaticamente várias técnicas de escalação de privilégios, incluindo:

  • Reconhecimento de enumerão de utilizadores/grupos (BloodHound, SharpHound, LDAP queries suspeitas)
  • Kerberoasting — pedidos suspeitos de TGS para contas de serviço
  • Overpass-the-Hash — uso de hashes para obter TGTs
  • Golden Ticket — TGTs forjados com a conta KRBTGT
  • Skeleton Key — injecção de password universal em DCs
  • Ataques de shadow admin — utilizadores com permissões equivalentes a administrador sem serem membros de grupos admin
  • Enumeração de sessões — via NetSessionEnum para movimento lateral
  • Abuso de DNS — alterações maliciosas em registos DNS do AD
# Verificar estado dos sensores do Defender para Identidade
# Via Microsoft Graph PowerShell SDK

Connect-MgGraph -Scopes "SecurityEvents.Read.All"

# Listar alertas activos do Defender para Identidade
$alerts = Get-MgSecurityAlert -Filter "category eq 'IdentityDirectoryEvents'" |
  Select-Object Title, Severity, Status, CreatedDateTime,
    @{N='Entidades';E={
      $_.EventMessage | Select-Object -First 5
    }}

$alerts | Format-Table -AutoSize

# Verificar sensores instalados em cada DC
# (via portal do Defender ou API)
$sensors = Get-MgSecurityAlert -Filter "category eq 'IdentityDirectoryEvents'" |
  Select-Object -ExpandProperty Comments

Write-Host "Total de alertas activos: $($alerts.Count)" -ForegroundColor Cyan
# Verificar contas marcadas como "Sensitive" no Defender para Identidade
# Contas marcadas como sensíveis não podem ser usadas para
# movimento lateral (defesa contra pass-the-hash e similar)

# Via PowerShell - marcar contas como sensíveis
# O atributo adminCount=1 indica que a conta está protegida
$sensitiveAccounts = Get-ADUser -LDAPFilter "(adminCount=1)" -Properties adminCount

Write-Host "Contas marcadas como sensíveis (adminCount=1):" -ForegroundColor Cyan
$sensitiveAccounts | Select-Object Name, SAMAccountName, Enabled, adminCount |
  Format-Table -AutoSize

# Marcar uma conta de serviço como sensível manualmente
# (quando não é membro de grupo protegido mas tem privilégios elevados)
Set-ADUser -Identity "svc-backup" `
  -Replace @{adminCount=1} `
  -Server (Get-ADDomain).PDCEmulator

Write-Host "Conta marcada como sensível no Defender para Identidade." -ForegroundColor Green

Integração com Sentinel: Configure o conector do Defender para Identidade no Microsoft Sentinel para correlacionar alertas de identidade com eventos de endpoints e nuvem. As regras de detecção pré-configuradas (analytics rules) para escalação de privilégios estão disponíveis no Sentinel Solution for Active Directory.

LAPS para Gestão de Passwords Locais

O Windows LAPS (Local Administrator Password Solution) é a solução nativa da Microsoft para gestão automática e rotativa de passwords do administrador local em máquinas associadas ao domínio. Em 2026, o Windows LAPS está integrado nativamente no Windows Server 2025 e Windows 11, substituindo o antigo Microsoft LAPS legado (baseado em GPO e cliente separado).

O LAPS é crítico para prevenir escalação de privilégios porque impede o pass-the-hash lateral: se a password do administrador local for igual em múltiplas máquinas (o cenário clássico sem LAPS), um atacante que comprometa uma máquina obtém acesso a todas as outras. Com LAPS, cada máquina tem uma password única, aleatória e rotada automaticamente.

# Verificar estado do Windows LAPS numa máquina
# Executar localmente ou via Invoke-Command

# Verificar configuração LAPS via CSP (Configuration Service Provider)
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\LAPS" -ErrorAction SilentlyContinue

# Verificar a última vez que a password local foi alterada pelo LAPS
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\LAPS\State" -ErrorAction SilentlyContinue |
  Select-Object PasswordAgeDays, PasswordExpirationTime, PostAuthenticationActions

# Estado da password actual (não exibe a password, apenas metadados)
$lapsState = Get-LapsADPassword -Identity $env:COMPUTERNAME -AsPlainText -ErrorAction SilentlyContinue
if ($lapsState) {
    Write-Host "LAPS activo. Password última alteração: $($lapsState.PasswordLastSet)" -ForegroundColor Green
} else {
    Write-Host "LAPS não configurado nesta máquina!" -ForegroundColor Red
}
# Configurar Windows LAPS via GPO no AD
# Política: Computer Configuration > Policies > Admin Templates > System > LAPS

# Parâmetros recomendados (via PowerShell para definir GPO registry settings)
$gpoName = "LAPS-Configuração-Padrao"
$gpo = Get-GPO -Name $gpoName -ErrorAction SilentlyContinue

if (-not $gpo) {
    $gpo = New-GPO -Name $gpoName
    Write-Host "GPO '$gpoName' criado." -ForegroundColor Green
}

# Definições de registo do LAPS
$lapsSettings = @{
    "BackupDirectory" = 1           # 1 = AD, 2 = Entra ID
    "PasswordAgeDays" = 30          # Rotação a cada 30 dias
    "PasswordComplexity" = 4        # Complexidade máxima (letras, números, símbolos)
    "PasswordLength" = 20           # 20 caracteres mínimo
    "PostAuthenticationActions" = 3 # Reset + desconexões (3 = ResetPasswordAndLogon)
    "PostAuthenticationDelay" = 24 # 24 horas após expiração
}

foreach ($setting in $lapsSettings.GetEnumerator()) {
    $regPath = "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\LAPS"
    Set-GPRegistryValue -Name $gpoName -Key $regPath `
      -ValueName $setting.Key -Type DWord -Value $setting.Value
}

# Associar GPO à OU de workstations
New-GPLink -Name $gpoName -Target "OU=Workstations-Tier2,DC=corp,DC=local"

Write-Host "GPO LAPS configurado e associado." -ForegroundColor Green
# Consultar password LAPS de uma máquina específica
# (requer permissão de leitura no atributo msLAPS-Password)

Get-LapsADPassword -Identity "PC-FINANCAS-01" -AsPlainText |
  Select-Object DistinguishedName, Password, PasswordLastSet, PasswordExpiresOn |
  Format-List

# Listar máquinas sem LAPS configurado (sem password armazenada no AD)
$computers = Get-ADComputer -Filter * -Properties msLAPS-Password, msLAPS-PasswordExpirationTime
$noLaps = $computers | Where-Object {
    $null -eq $_."msLAPS-Password" -and $null -eq $_."msLAPS-PasswordExpirationTime"
}

Write-Host "Máquinas sem LAPS configurado: $($noLaps.Count)" -ForegroundColor Yellow
$noLaps | Select-Object Name, DNSHostName, Enabled |
  Format-Table -AutoSize

# Forçar rotação imediata da password LAPS
Reset-LapsADPassword -Identity "PC-FINANCAS-01"
Write-Host "Rotação forçada executada." -ForegroundColor Green

Permissões LAPS: Por omissão, apenas os Domain Admins e Local System podem ler as passwords LAPS. Delegue permissão de leitura apenas a equipas específicas (por exemplo, Helpdesk Tier 2) usando delegação de controlo no AD para o atributo msLAPS-Password. Nunca conceda leitura de LAPS a contas de Tier 1 ou utilizadores comuns.

Linha de Comando PowerShell para Auditoria

Esta secção consolida scripts PowerShell práticos para auditoria contínua de segurança do Active Directory, focados na detecção de cenários de escalação de privilégios. Estes scripts podem ser agendados como tarefas recorrentes ou executados manualmente durante revisões de segurança.

# Script de auditoria completa de escalação de privilégios
# Executar com privilégios de Domain Admin num Domain Controller

Import-Module ActiveDirectory

# 1. Listar contas de serviço com delegação de Kerberos (perigo: Kerberoasting)
$kerberoastable = Get-ADUser -Filter {ServicePrincipalName -ne "$null" -and Enabled -eq $true} `
  -Properties ServicePrincipalName, PasswordLastSet, PasswordNeverExpires |
  Select-Object Name, SAMAccountName, PasswordLastSet,
    PasswordNeverExpires, @{N='SPNCount';E={$_.ServicePrincipalName.Count}}

Write-Host "=== Contas vulneráveis a Kerberoasting ===" -ForegroundColor Yellow
$kerberoastable | Format-Table -AutoSize
Write-Host "Total: $($kerberoastable.Count) contas`n" -ForegroundColor Cyan

# 2. Contas com PasswordNeverExpires (risco de persistência)
$neverExpires = Get-ADUser -Filter {PasswordNeverExpires -eq $true -and Enabled -eq $true} `
  -Properties PasswordNeverExpires, PasswordLastSet |
  Select-Object Name, SAMAccountName, PasswordLastSet, PasswordNeverExpires

Write-Host "=== Contas com Password Never Expires ===" -ForegroundColor Yellow
$neverExpires | Format-Table -AutoSize
Write-Host "Total: $($neverExpires.Count) contas`n" -ForegroundColor Cyan
# 3. Verificar ACLs perigosas em objectos do AD
# Procurar permissões "FullControl" concedidas a utilizadores não-admin

$domain = (Get-ADDomain).DistinguishedName
$dangerousRights = @("GenericAll", "GenericWrite", "WriteDacl", "WriteOwner")

$aclObjects = @("CN=AdminSDHolder,CN=System,$domain",
                 "CN=krbtgt,CN=Users,$domain",
                 "OU=Domain Controllers,$domain")

foreach ($obj in $aclObjects) {
    try {
        $acl = Get-Acl "AD:\$obj" -ErrorAction Stop
        $dangerous = $acl.Access | Where-Object {
            $_.ActiveDirectoryRights -in $dangerousRights -and
            $_.AccessControlType -eq 'Allow' -and
            $_.IdentityReference -notmatch "NT AUTHORITY|BUILTIN|S-1-5"
        }
        if ($dangerous) {
            Write-Host "ACL PERIGOSA em: $obj" -ForegroundColor Red
            $dangerous | Select-Object IdentityReference,
                ActiveDirectoryRights, AccessControlType |
              Format-Table -AutoSize
        } else {
            Write-Host "ACL OK em: $obj" -ForegroundColor Green
        }
    } catch {
        Write-Host "Erro ao ler ACL de: $obj" -ForegroundColor Yellow
    }
}

# 4. Verificar AdminSDHolder e contas protegidas
$sdHolder = Get-ADObject -Identity "CN=AdminSDHolder,CN=System,$domain" -Properties *
Write-Host "=== AdminSDHolder ===" -ForegroundColor Cyan
Write-Host "Última modificação: $($sdHolder.Modified)"

# Verificar se há contas com adminCount=1 que não estão em grupos admin
$protectedAccounts = Get-ADUser -LDAPFilter "(adminCount=1)" -Properties memberOf
$adminGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins",
    "Administrators", "Account Operators", "Backup Operators",
    "Server Operators", "Print Operators")

$shadowAdmins = $protectedAccounts | Where-Object {
    $groups = $_.memberOf | ForEach-Object {
        (Get-ADGroup -Identity $_ -ErrorAction SilentlyContinue).Name
    }
    ($groups | Where-Object { $_ -in $adminGroups }).Count -eq 0
}

Write-Host "=== Shadow Admins (adminCount=1 mas não em grupos admin) ===" -ForegroundColor Red
$shadowAdmins | Select-Object Name, SAMAccountName | Format-Table -AutoSize
# 5. Verificar configuração de delegação de Kerberos
# Delegação não restrita é um risco crítico de escalação

$unconstrained = Get-ADUser -Filter {UserAccountControl -band 524288} -Properties UserAccountControl |
  Select-Object Name, SAMAccountName, UserAccountControl

Write-Host "=== Contas com Delegação NÃO Restrita (Perigo!) ===" -ForegroundColor Red
if ($unconstrained) {
    $unconstrained | Format-Table -AutoSize
} else {
    Write-Host "Nenhuma conta encontrada." -ForegroundColor Green
}

# Verificar delegação não restrita em contas de computador
$unconstrainedComputers = Get-ADComputer -Filter {UserAccountControl -band 524288} `
  -Properties UserAccountControl, DNSHostName |
  Select-Object Name, DNSHostName, UserAccountControl

Write-Host "=== Computadores com Delegação NÃO Restrita ===" -ForegroundColor Yellow
$unconstrainedComputers | Format-Table -AutoSize

# 6. Listar todos os DCs e verificar estado do sistema operativo
$dcs = Get-ADDomainController -Filter * |
  Select-Object HostName, Site, OperatingSystem, OperatingSystemVersion,
    IsGlobalCatalog, IsReadOnly

Write-Host "=== Domain Controllers ===" -ForegroundColor Cyan
$dcs | Format-Table -AutoSize

# Alertar para DCs com SO desactualizado
$oldDCs = $dcs | Where-Object {
    $_.OperatingSystem -notmatch "2022|2025" -and -not $_.IsReadOnly
}
if ($oldDCs) {
    Write-Host "ALERTA: DCs com SO desactualizado detectados!" -ForegroundColor Red
    $oldDCs | Format-Table -AutoSize
}

Automação: Guarde estes scripts num repositório central e execute-os semanalmente via tarefa agendada. Configure o envio dos resultados por email para a equipa de segurança, ou integre-os com o seu SIEM para alertas automatizados quando anomalias são detectadas.

Resolução de Problemas

Durante a implementação de medidas de segurança no Active Directory, podem surgir problemas práticos. Esta secção aborda os mais comuns, com soluções orientadas.

Problema: Após activar SID Filtering, utilizadores legítimos perdem acesso

Isto acontece quando existiam utilizadores migrados que dependiam de sIDHistory para acessos cruzados. A solução é garantir que todos os recursos foram actualizados para usar o novo SID do utilizador antes de activar a filtragem, ou usar a funcionalidade de quarentena gradual.

# Diagnosticar perda de acesso após activação de SID Filtering
# Verificar que SIDs estavam no sIDHistory antes da filtragem

$affectedUser = "joao.silva"
$user = Get-ADUser -Identity $affectedUser -Properties sIDHistory, memberOf

Write-Host "SIDs no sIDHistory de $affectedUser :" -ForegroundColor Yellow
$user.sIDHistory | ForEach-Object {
    $sid = $_
    try {
        $resolved = New-Object System.Security.Principal.SecurityIdentifier($sid)
        $account = $resolved.Translate([System.Security.Principal.NTAccount])
        Write-Host "  $sid -> $($account.Value)" -ForegroundColor Cyan
    } catch {
        Write-Host "  $sid -> (não resolvido - floresta externa)" -ForegroundColor Red
    }
}

# Verificar permissões NTFS em recursos partilhados
$shares = Get-SmbShare | Where-Object { $_.ConstrainedUser -match $affectedUser }
foreach ($share in $shares) {
    $acl = Get-Acl "\\$($env:COMPUTERNAME)\$($share.Name)" -ErrorAction SilentlyContinue
    $access = $acl.Access | Where-Object {
        $_.IdentityReference -match $affectedUser
    }
    if ($access) {
        Write-Host "Permissões em $($share.Name):" -ForegroundColor Green
        $access | Format-Table -AutoSize
    }
}

Problema: Trust de floresta não autentica correctamente

# Diagnosticar problemas de trust entre florestas

# 1. Verificar conectividade DNS entre florestas
$trustPartner = "filial.local"
Resolve-DnsName $trustPartner -Server 8.8.8.8 -ErrorAction SilentlyContinue
Resolve-DnsName -Name "_ldap._tcp.dc._msdcs.$trustPartner" -Type SRV -ErrorAction SilentlyContinue

# 2. Verificar estado do trust
nltest /domain_trusts /v

# 3. Verificar secure channel do trust
nltest /server:DC01 /trustedomain:filial.local /verify

# 4. Verificar firewalls - portas Kerberos e LDAP
Test-NetConnection -ComputerName "dc01.filial.local" -Port 88
Test-NetConnection -ComputerName "dc01.filial.local" -Port 389
Test-NetConnection -ComputerName "dc01.filial.local" -Port 445
Test-NetConnection -ComputerName "dc01.filial.local" -Port 135

# 5. Verificar eventos de erro de Kerberos
Get-WinEvent -LogName 'System' -MaxEvents 50 |
  Where-Object { $_.Id -in @(4, 7, 14, 29, 30, 31, 32, 33, 34) } |
  Select-Object TimeCreated, Id, LevelDisplayName, Message |
  Format-Table -AutoSize

Problema: RODC não replica correctamente

# Diagnosticar problemas de replicação do RODC

# 1. Verificar estado de replicação
repadmin /showrepl RODC-FILIAL-01 /verbose

# 2. Verificar conectividade com o bridgehead server
$bridgehead = "DC01"
Test-NetConnection -ComputerName $bridgehead -Port 135

# 3. Forçar sincronização do RODC com o DC bridgehead
repadmin /syncall RODC-FILIAL-01 /A /d /e

# 4. Verificar erros de replicação recentes
repadmin /showreplsumm 2>&1 |
  Select-Object -First 20

# 5. Verificar se a Password Replication Policy bloqueia replicação
Get-ADDomainControllerPasswordReplicationPolicy -Identity "RODC-FILIAL-01"

# 6. Verificar cache de passwords no RODC (não deve ter contas admin)
Get-ADDomainControllerAccountPasswordReplicationPolicy `
  -Identity "RODC-FILIAL-01" |
  Where-Object { $_.ObjectClass -eq "user" } |
  Select-Object Name, SAMAccountName |
  Format-Table -AutoSize

Problema: LAPS não aplica a password nas workstations

# Diagnosticar problemas de aplicação do LAPS

# 1. Verificar se o GPO do LAPS está a ser aplicado
$computer = "PC-FINANCAS-01"
gpresult /s $computer /r /scope:computer |
  Select-String "LAPS" -Context 2,2

# 2. Verificar se a extensão LAPS do AD está instalada
$lapsschema = Get-ADObject -Filter {Name -eq "ms-LAPS-Password"} -SearchBase (Get-ADRootDSE).SchemaNamingContext -ErrorAction SilentlyContinue
if ($lapsschema) {
    Write-Host "Schema LAPS presente no AD." -ForegroundColor Green
} else {
    Write-Host "Schema LAPS AUSENTE! Importar schema LAPS." -ForegroundColor Red
    Write-Host "Executar: Update-AdSchema -Laps" -ForegroundColor Yellow
}

# 3. Verificar permissões no atributo msLAPS-Password
$computerObj = Get-ADComputer -Identity $computer -Properties msLAPS-Password
$acl = Get-Acl "AD:\$($computerObj.DistinguishedName)"
$lapsAcl = $acl.Access | Where-Object {
    $_.ActiveDirectoryRights -match "ReadProperty" -and
    $_.ObjectType -eq "ced86f3d-5e1e-46b6-a07a-d2ac75d767ce"
}
$lapsAcl | Format-Table -AutoSize

# 4. Forçar actualização de políticas de grupo no cliente
Invoke-Command -ComputerName $computer -ScriptBlock {
    gpupdate /force /target:computer
}

Nota sobre migração de LAPS: Se está a migrar do LAPS legado (GPO + cliente MSI) para o Windows LAPS nativo, a transição deve ser feita de forma faseada. Comece por actualizar o schema do AD, depois actualize os clientes via Windows Update e finalmente actualize o GPO. O LAPS legado e o Windows LAPS podem coexistir temporariamente, mas apenas um deve estar activo por máquina.

Checklist de Segurança AD

Esta checklist consolida todas as medidas abordadas neste artigo num formato prático para auditorias periódicas. Imprima-a, partilhe-a com a sua equipa e execute-a pelo menos trimestralmente.

# Medida de Segurança Prioridade Frequência
1 SID Filtering activo em todos os trusts de floresta Crítica Verificação mensal
2 Autenticação selectiva em trusts de menor confiança Crítica Na criação do trust
3 Limpeza de sIDHistory após migrações Alta Após cada migração
4 Implementar modelo Tier 0/1/2 (PAW para Tier 0) Crítica Projeto contínuo
5 Contas Break Glass em cofre físico com auditoria Crítica Configuração + validação trimestral
6 Rotação de password KRBTGT (2x por ano mínimo) Crítica Semestral (2x em resposta a incidente)
7 RODC em filiais fisicamente inseguras Alta Na implementação da filial
8 Auditoria de alterações de grupos privilegiados Crítica Contínua (alertas em tempo real)
9 Defender para Identidade activo e sensores operacionais Alta Monitorização contínua
10 Windows LAPS activo em todas as workstations e servidores Crítica Verificação semanal
11 Sem delegação não restrita de Kerberos Crítica Verificação mensal
12 Audit script de escalação executado e revisto Alta Semanal
13 Contas de serviço com gMSA (Group Managed Service Accounts) Alta Migração faseada
14 DCs actualizados (Windows Server 2022 ou superior) Alta Verificação mensal de patches
15 Logs de segurança encaminhados para SIEM centralizado Crítica Configuração única + monitorização
16 Backup do AD testado e validado (incluindo restore) Crítica Teste de restore semestral

Recomendação final: A segurança do Active Directory não é um projeto pontual — é um processo contínuo. Em 2026, com a evolução das técnicas de ataque orientadas por identidade, as organizações que não mantêm uma postura de segurança proactiva estão em risco significativo de compromisso. Implemente as medidas desta checklist de forma faseada, começando pelos itens de prioridade Crítica. Para apoio adicional sobre estratégia Zero Trust, consulte o nosso artigo sobre Zero Trust para PMEs em 2026.


Artigos Relacionados

© 2026 kbase.pt — Duarte Spínola. Todos os direitos reservados.

Este artigo é fornecido para fins educacionais. As recomendações devem ser adaptadas ao contexto específico de cada organização e validadas em ambiente de teste antes de aplicação em produção.

Este artigo foi útil?

Duarte Spínola

Deixe um Comentário