# AD-scan: handleiding voor het verhelpen van kwetsbaarheden

Elke sectie over een kwetsbaarheid bevat:

* **Wat het betekent:** een uitleg van het risico in eenvoudige taal
* **Wat de scan controleert:** de specifieke voorwaarden die de waarschuwing activeren
* **Waarom de waarschuwing kan blijven bestaan:** veelvoorkomende gedeeltelijke oplossingen die niet voldoende zijn
* **Hoe te diagnosticeren:** PowerShell-opdrachten om getroffen objecten te identificeren
* **Hoe op te lossen:** stapsgewijze oplossing

> **Vereisten:** Alle PowerShell-opdrachten vereisen de `ActiveDirectory` module en moeten worden uitgevoerd als Domain Admin op een Domain Controller.
>
> ```powershell
> Import-Module ActiveDirectory
> ```

## A-LAPS-Not-Installed

#### Wat het betekent

Elke Windows-computer heeft een **ingebouwd lokaal Administrator-account**. Standaard heeft dit account vaak op alle machines hetzelfde wachtwoord, of een wachtwoord dat nooit verandert. Als een aanvaller één machine compromitteert, kan die dat wachtwoord opnieuw gebruiken om toegang te krijgen tot alle andere machines.

**LAPS** (Local Administrator Password Solution) lost dit op door automatisch op elke computer een uniek, willekeurig gegenereerd wachtwoord in te stellen en dit veilig op te slaan in Active Directory. Alleen geautoriseerde beheerders kunnen het ophalen.

#### Wat de scan controleert

De AD Scan zoekt naar aanwijzingen dat LAPS is ingesteld in uw Active Directory. Concreet controleert het of de benodigde LAPS-gegevensvelden aanwezig zijn in uw AD-configuratie. Als dat niet zo is, betekent dat dat LAPS nooit is geïnstalleerd.

#### Waarom de waarschuwing kan blijven bestaan

* **LAPS alleen via Intune beheerd:** Als u Microsoft Intune gebruikt om LAPS-wachtwoorden in de cloud te beheren (zonder de on-premises AD te configureren), kan de AD Scan dit niet detecteren. De scan bekijkt alleen uw lokale Active Directory.
* **LAPS gedeeltelijk geïnstalleerd:** De LAPS-instelling kan zijn gestart maar niet voltooid.

#### Hoe te diagnosticeren

```powershell
# Controleer of LAPS is ingesteld in uw Active Directory
Get-ADObject -SearchBase (Get-ADRootDSE).SchemaNamingContext `
  -Filter "name -like 'ms-Mcs-AdmPwd' -or name -eq 'ms-LAPS-Password'" |
  Select-Object Name, whenCreated
```

Als dit geen resultaten oplevert, is LAPS niet geïnstalleerd.

#### Hoe op te lossen

**Voor Windows Server 2019 en later (aanbevolen):** Moderne LAPS is ingebouwd in Windows. Schakel het in via Group Policy:

1. Open `gpmc.msc` (Group Policy Management)
2. Bewerk of maak een GPO die is gekoppeld aan uw computer-OU's
3. Navigeer naar: `Computer Configuration > Administrative Templates > System > LAPS`
4. Configureer de LAPS-instellingen (inschakelen, wachtwoordcomplexiteit instellen, enz.)

**Voor oudere omgevingen:** Download Legacy LAPS van Microsoft en voer de schema-uitbreiding uit:

```powershell
Update-LapsADSchema
```

> **Opmerking:** Als u lokale beheerderswachtwoorden beheert via een ander hulpmiddel (CyberArk, Intune-only LAPS, enz.), neem dan contact op met Stoïk support om dit vast te leggen als een geaccepteerde uitzondering.

## A-LAPS-Joined-Computers

#### Wat het betekent

Wanneer iemand een computer toevoegt ("joint") aan het Active Directory-domein, wordt die persoon de **maker** van het computerobject in AD. Standaard krijgt de maker speciale machtigingen op dat object.

Het probleem is: wanneer LAPS is geïnstalleerd, wordt het lokale beheerderswachtwoord opgeslagen op datzelfde computerobject. Als de maker nog steeds de juiste machtigingen heeft, kan die **het LAPS-wachtwoord lezen**, zelfs als die geen beheerder is. Dit betekent dat een gewone gebruiker die ooit een pc aan het domein heeft toegevoegd, het lokale beheerderswachtwoord van die machine kan ophalen.

#### Wat de scan controleert

Voor elke ingeschakelde computer waarop LAPS is uitgerold, controleert de AD Scan **twee dingen**:

1. **Is de persoon die de computer heeft toegevoegd nog steeds de "eigenaar" van het computerobject?** Eigenaars kunnen zichzelf elke machtiging geven, inclusief het lezen van het LAPS-wachtwoord.
2. **Heeft de maker nog steeds expliciete machtigingen** op het computerobject, zoals `Alle uitgebreide rechten` (waarmee het LAPS-wachtwoord kan worden gelezen), `WriteDacl` (waarmee machtigingen kunnen worden gewijzigd), `WriteOwner` (waarmee het eigenaarschap kan worden teruggenomen), of `GenericWrite`?

De waarschuwing wordt geactiveerd als **een van beide** voorwaarden waar is.

#### Waarom de waarschuwing kan blijven bestaan

Dit is de meest voorkomende bron van verwarring: **het wijzigen van de eigenaar is slechts de helft van de oplossing.**

Veel beheerders wijzigen de eigenaar naar "Domain Admins" en verwachten dat de waarschuwing verdwijnt. Maar de AD Scan controleert ook op resterende machtigingen (ACEs, of Access Control Entries genoemd) die aan de oorspronkelijke maker zijn verleend. Deze machtigingen blijven bestaan, zelfs nadat de eigenaar is gewijzigd, en moeten apart worden verwijderd.

#### Hoe te diagnosticeren

```powershell
# Lijst computers waarbij de maker nog steeds risicovolle machtigingen heeft
Get-ADComputer -Filter "Enabled -eq `$true" `
  -Properties "mS-DS-CreatorSID", "nTSecurityDescriptor" |
  Where-Object { $_."mS-DS-CreatorSID" -ne $null } |
  ForEach-Object {
    $comp = $_
    $acl = $comp.nTSecurityDescriptor
    $creatorSid = $comp."mS-DS-CreatorSID"
    $owner = $acl.GetOwner([System.Security.Principal.SecurityIdentifier])

    $isOwner = ($owner.Value -eq $creatorSid.Value)

    $riskyAces = $acl.Access | Where-Object {
      -not $_.IsInherited -and
      $_.IdentityReference.Value -eq $creatorSid.Value -and
      ($_.ActiveDirectoryRights -match 'WriteDacl|WriteOwner|GenericWrite|ExtendedRight')
    }

    if ($isOwner -or $riskyAces) {
      [PSCustomObject]@{
        Computer       = $comp.Name
        CreatorIsOwner = $isOwner
        RiskyRights    = ($riskyAces | ForEach-Object { $_.ActiveDirectoryRights }) -join ", "
      }
    }
  } | Format-Table -AutoSize
```

#### Hoe op te lossen

U moet **beide** van deze acties uitvoeren voor elke getroffen computer:

1. **Wijzig de eigenaar** naar Domain Admins
2. **Verwijder de expliciete machtigingen van de maker**

Het volgende script doet beide automatisch:

```powershell
#Requires -Modules ActiveDirectory

$affectedComputers = Get-ADComputer -Filter "Enabled -eq `$true" `
  -Properties "mS-DS-CreatorSID", "nTSecurityDescriptor" |
  Where-Object { $_."mS-DS-CreatorSID" -ne $null }

foreach ($comp in $affectedComputers) {
  $path = "AD:$($comp.DistinguishedName)"
  $acl = Get-Acl -Path $path
  $creatorSid = $comp."mS-DS-CreatorSID"
  $modified = $false

  # Stap 1: wijzig eigenaar naar Domain Admins
  $domainAdmins = New-Object System.Security.Principal.NTAccount("$env:USERDOMAIN", "Domain Admins")
  $acl.SetOwner($domainAdmins)
  $modified = $true

  # Stap 2: verwijder expliciete machtigingen verleend aan de maker (en verweesde SID's)
  $toRemove = @($acl.Access | Where-Object {
    -not $_.IsInherited -and
    ($_.IdentityReference.Value -eq $creatorSid.Value -or
     $_.IdentityReference.Value -match '^S-1-5-21-')  # Verweesde SID's (verwijderde accounts)
  })

  foreach ($ace in $toRemove) {
    $acl.RemoveAccessRuleSpecific($ace)
    Write-Host "$($comp.Name): Verwijderd [$($ace.ActiveDirectoryRights)] voor $($ace.IdentityReference)"
  }

  if ($modified) {
    Set-Acl -Path $path -AclObject $acl
    Write-Host "$($comp.Name): Gerepareerd" -ForegroundColor Green
  }
}
```

> **Tip:** Voer eerst de diagnostische opdracht uit om de lijst met getroffen computers te bekijken voordat u de oplossing toepast.

## A-NoServicePolicy

#### Wat het betekent

**Serviceaccounts** zijn accounts die door toepassingen en services worden gebruikt (bijv. SQL Server, back-upagents) om zich te authenticeren in Active Directory. In tegenstelling tot gewone gebruikersaccounts zijn serviceaccounts doelwitten van hoge waarde: ze hebben vaak verhoogde machtigingen en hun wachtwoorden worden zelden gewijzigd.

Een **Fine-Grained Password Policy (PSO)** is een speciale wachtwoordregel die u op specifieke groepen accounts kunt toepassen. De AD Scan verwacht dat uw serviceaccounts worden gedekt door een PSO die wachtwoorden van ten minste **20 tekens**vereist, waardoor ze veel moeilijker te kraken zijn.

#### Wat de scan controleert

De AD Scan zoekt naar ten minste één wachtwoordbeleid (GPO of PSO) dat een minimale wachtwoordlengte afdwingt van **20 tekens of meer**.

#### Waarom de waarschuwing kan blijven bestaan

1. **Het scanaccount heeft geen toestemming om de PSO te lezen.** Wachtwoordbeleidsregels worden opgeslagen in een beschermd deel van AD dat standaard alleen door Domain Admins kan worden gelezen. Als de scan wordt uitgevoerd met een account met minder rechten, kan het de PSO eenvoudigweg niet zien, ook al bestaat deze.
2. **De PSO bestaat, maar de minimale lengte ligt onder 20** (bijv. 12 of 15 tekens).
3. **De PSO bestaat, maar is niet toegewezen aan een groep of gebruiker.**

#### Hoe te diagnosticeren

```powershell
# Lijst alle Fine-Grained Password Policies en hun instellingen
Get-ADFineGrainedPasswordPolicy -Filter * |
  Select-Object Name, MinPasswordLength, @{N="AppliedTo"; E={$_.AppliesTo -join ", "}}, Precedence
```

Als dit niets oplevert, bestaat er geen PSO of heeft het account dat de opdracht uitvoert geen rechten om deze te zien. Probeer het uit te voeren met een Domain Admin-account.

#### Hoe op te lossen

**Als de PSO bestaat maar de scan deze niet kan zien:** Voer de AD Scan uit met een Domain Admin-account.

**Als er geen PSO bestaat:** Maak er een aan en wijs die toe aan uw serviceaccounts:

```powershell
# Maak een wachtwoordbeleid voor serviceaccounts
New-ADFineGrainedPasswordPolicy -Name "Service Accounts - Strong Password" `
  -Precedence 10 `
  -MinPasswordLength 20 `
  -MaxPasswordAge "90.00:00:00" `
  -MinPasswordAge "1.00:00:00" `
  -PasswordHistoryCount 24 `
  -ComplexityEnabled $true `
  -ReversibleEncryptionEnabled $false `
  -LockoutDuration "00:30:00" `
  -LockoutObservationWindow "00:30:00" `
  -LockoutThreshold 5

# Wijs het toe aan een beveiligingsgroep met uw serviceaccounts
Add-ADFineGrainedPasswordPolicySubject `
  -Identity "Service Accounts - Strong Password" `
  -Subjects "SG_ServiceAccounts"
```

> **Opmerking:** Het aanmaken van een PSO dwingt niet onmiddellijk wachtwoordwijzigingen af. Bestaande wachtwoorden blijven werken totdat ze verlopen of handmatig opnieuw worden ingesteld. Vanaf dat moment geldt de nieuwe minimumlengte van 20 tekens.

## A-AuditDC

#### Wat het betekent

**Auditbeleid** bepalen welke gebeurtenissen op uw Domain Controllers worden gelogd. Zonder goede auditing kunnen aanvallen zoals diefstal van inloggegevens, ongeautoriseerde groepswijzigingen of misbruik van replicatie (DCSync) plaatsvinden zonder een spoor in de logs achter te laten.

De AD Scan verifieert dat uw Domain Controllers zijn geconfigureerd om de belangrijkste beveiligingsgebeurtenissen te loggen.

#### Wat de scan controleert

De scan zoekt naar **13 specifieke audit-subcategorieën** die via Group Policy op alle Domain Controllers moeten zijn ingeschakeld:

| Categorie                          | Wat het logt                                                      |
| ---------------------------------- | ----------------------------------------------------------------- |
| Kerberos Authentication Service    | Inlogpogingen via Kerberos                                        |
| Kerberos Service Ticket Operations | Verzoeken om servicetickets (detecteert Kerberoasting)            |
| Computer Account Management        | Computer-joins/wijzigingen in AD                                  |
| Security Group Management          | Wijzigingen in groepslidmaatschap                                 |
| User Account Management            | Aanmaken, verwijderen en resetten van wachtwoorden van gebruikers |
| DPAPI Activity                     | Gebruik van Data Protection API (toegang tot inloggegevens)       |
| Process Creation                   | Nieuw gestarte processen (detecteert kwaadaardige tools)          |
| Logon / Logoff                     | Interactieve en externe aanmeldingen                              |
| Special Logon                      | Aanmeldingen met verhoogde rechten                                |
| Authentication Policy Change       | Wijzigingen in authenticatie-instellingen                         |
| Sensitive Privilege Use            | Gebruik van gevoelige machtigingen                                |
| Security System Extension          | Wijzigingen in het beveiligingssubysteem                          |

#### Waarom de waarschuwing kan blijven bestaan

1. **Instellingen toegepast via `auditpol` rechtstreeks op de DC** worden niet gedetecteerd. De AD Scan leest Group Policy-bestanden, niet de lokale configuratie van de DC. U moet een GPO gebruiken.
2. **Conflicterende GPO's:** Eén GPO schakelt de instelling in, maar een andere GPO met hogere prioriteit schakelt deze uit.
3. **GPO niet gekoppeld aan de OU Domain Controllers:** De GPO bestaat maar is gekoppeld aan een andere OU.

#### Hoe te diagnosticeren

```powershell
# Controleer het effectieve auditbeleid op een Domain Controller
auditpol /get /category:*
```

Als de lokale instellingen correct lijken maar de waarschuwing blijft bestaan, controleer dan of de instellingen uit een GPO komen (niet uit een lokale overschrijving):

```powershell
# Controleer welke GPO's zijn gekoppeld aan de OU Domain Controllers
Get-GPInheritance -Target "OU=Domain Controllers,$($(Get-ADDomain).DistinguishedName)"
```

#### Hoe op te lossen

1. Open `gpmc.msc` (Group Policy Management Console)
2. Maak een GPO aan of bewerk een GPO die is gekoppeld aan `OU=Domain Controllers`
3. Navigeer naar: `Computer Configuration > Policies > Windows Settings > Security Settings > Advanced Audit Policy Configuration > Audit Policies`
4. Schakel **Succes en fout** in voor alle hierboven vermelde subcategorieën
5. Voer `gpupdate /force` uit op alle Domain Controllers

Controleer de oplossing:

```powershell
auditpol /get /category:"Account Logon"
auditpol /get /category:"Account Management"
auditpol /get /category:"Logon/Logoff"
```

## A-BadSuccessor

#### Wat het betekent

Windows Server 2025 introduceerde een nieuw type serviceaccount genaamd **dMSA** (Delegated Managed Service Account). Er werd een beveiligingsfout ontdekt waarbij een gewone gebruiker met bepaalde machtigingen op een Active Directory-map (een Organizational Unit, of OU genoemd) een dMSA kon aanmaken en die kon gebruiken om volledige beheerderstoegang tot het domein te krijgen.

Deze aanval is alleen mogelijk wanneer:

* U hebt ten minste één **Windows Server 2025** Domain Controller
* Een **KDS Root Key** bestaat (vereist voor beheerde serviceaccounts)
* een niet-beheerdersgebruiker het recht heeft om objecten in een OU aan te maken

#### Wat de scan controleert

De AD Scan zoekt naar niet-geprivilegieerde gebruikers of groepen die machtigingen hebben om dMSA-objecten aan te maken of te beheren in een OU, zoals `CreateChild`, `GenericAll`, `WriteDacl`, of `WriteOwner`.

#### Waarom de waarschuwing kan blijven bestaan

* De oplossing moet worden toegepast op **elke** betrokken OU, niet slechts één.
* Machtigingen die zijn geërfd van bovenliggende OU's blijven van toepassing op onderliggende OU's.
* Aangepaste beheergroepen worden mogelijk niet door de scan als "geprivilegieerd" herkend.

#### Hoe te diagnosticeren

```powershell
# Controleer de vereisten
Get-KdsRootKey  # Er moet een KDS Root Key bestaan om de aanval mogelijk te maken

Get-ADDomainController -Filter * |
  Where-Object { $_.OperatingSystem -like "*2025*" } |
  Select-Object Name, OperatingSystem  # Minstens één Win2025-DC

# Zoek OU's met risicovolle delegaties
Get-ADOrganizationalUnit -Filter * -Properties nTSecurityDescriptor |
  ForEach-Object {
    $ou = $_
    $ou.nTSecurityDescriptor.Access |
      Where-Object {
        -not $_.IsInherited -and
        $_.ActiveDirectoryRights -match 'GenericAll|CreateChild|WriteDacl|WriteOwner'
      } | ForEach-Object {
        [PSCustomObject]@{
          OU        = $ou.Name
          Principal = $_.IdentityReference
          Rights    = $_.ActiveDirectoryRights
        }
      }
  } | Format-Table -AutoSize
```

#### Hoe op te lossen

Verwijder voor elke gemarkeerde OU de risicovolle machtigingen van niet-beheerdersgebruikers:

```powershell
$ouDN = "OU=Servers,DC=yourdomain,DC=com"  # Vervang door uw OU
$path = "AD:$ouDN"
$acl = Get-Acl -Path $path

# Verwijder risicovolle rechten voor een specifieke groep
$identity = New-Object System.Security.Principal.NTAccount("YOURDOMAIN", "HelpDeskTeam")
$toRemove = $acl.Access | Where-Object {
  $_.IdentityReference -eq $identity -and
  $_.ActiveDirectoryRights -match 'CreateChild|GenericAll'
}

foreach ($ace in $toRemove) {
  $acl.RemoveAccessRuleSpecific($ace)
}
Set-Acl -Path $path -AclObject $acl
```

## A-AdminSDHolder

#### Wat het betekent

Wanneer een gebruiker wordt toegevoegd aan een geprivilegieerde groep in Active Directory (zoals Domain Admins), markeert het systeem zijn account automatisch met een vlag genaamd `adminCount = 1`. Deze vlag maakt deel uit van een ingebouwd beschermingsmechanisme.

Het probleem is: **wanneer u die gebruiker uit de beheerdersgroep verwijdert, wordt de vlag NIET automatisch verwijderd.** Deze blijft voor altijd bestaan, tenzij u die expliciet verwijdert.

De AD Scan markeert accounts die deze resterende `adminCount` markering hebben, maar geen echte beheerders meer zijn. Dit kan duiden op:

* Een gebruiker die tijdelijk beheerder was gemaakt en waarvan de opschoning onvolledig was
* Een mogelijk beveiligingsrisico: deze accounts kunnen nog steeds verhoogde machtigingen hebben in bepaalde gebieden

#### Wat de scan controleert

De scan vindt ingeschakelde gebruikersaccounts waarbij `adminCount = 1` maar het account momenteel geen lid is van een geprivilegieerde groep.

#### Hoe te diagnosticeren

```powershell
# Maak een lijst van alle huidige geprivilegieerde gebruikers
$privilegedMembers = @()
@("Domain Admins", "Enterprise Admins", "Schema Admins", "Administrators",
  "Account Operators", "Server Operators", "Backup Operators", "Print Operators"
) | ForEach-Object {
  try { $privilegedMembers += (Get-ADGroupMember $_ -Recursive).DistinguishedName } catch {}
}

# Zoek accounts met de resterende adminCount-vlag
Get-ADUser -LDAPFilter "(&(admincount=1)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" `
  -Properties adminCount |
  Where-Object { $_.DistinguishedName -notin $privilegedMembers } |
  Select-Object SamAccountName, Name
```

#### Hoe op te lossen

Nadat u hebt bevestigd dat deze accounts geen beheerders meer zouden moeten zijn, wist u de vlag:

```powershell
# Wis adminCount voor één gebruiker
Set-ADUser -Identity "username" -Clear adminCount

# Of wis het voor alle niet-geprivilegieerde gebruikers in één keer
Get-ADUser -LDAPFilter "(&(admincount=1)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" |
  Where-Object { $_.DistinguishedName -notin $privilegedMembers } |
  ForEach-Object {
    Set-ADUser -Identity $_ -Clear adminCount
    Write-Host "adminCount gewist voor $($_.SamAccountName)"
  }
```

## P-Kerberoasting

#### Wat het betekent

In Active Directory zijn sommige accounts geregistreerd om services uit te voeren, zoals een SQL Server of een webapplicatie. Deze accounts hebben een **Service Principal Name (SPN)**, wat in wezen een label is dat zegt: "dit account draait een netwerkservice."

Het veiligheidsrisico is: **elke geverifieerde gebruiker** in het domein kan een Kerberos-ticket aanvragen voor elk account met een SPN. Dat ticket is versleuteld met het wachtwoord van het account, en de aanvaller kan vervolgens proberen het offline te kraken, zonder enig alarm te activeren.

Dit wordt een **Kerberoasting** aanval genoemd. Het is vooral gevaarlijk wanneer het account met de SPN ook een **Domain Admin** is, omdat het kraken van dat wachtwoord volledige controle over het domein betekent.

#### Wat de scan controleert

De AD Scan markeert accounts die aan **alle drie** de voorwaarden voldoen:

1. Het account is lid van een **bevoorrechte groep** (Domain Admins, Enterprise Admins, enz.)
2. Het account heeft een **Service Principal Name (SPN)**
3. Het wachtwoord van het account is **niet meer gewijzigd in meer dan 40 dagen** (waardoor aanvallers meer tijd hebben om het te kraken)

#### Waarom de waarschuwing kan blijven bestaan

Je moet **alle drie** de voorwaarden aanpakken. Veelvoorkomende onvolledige oplossingen:

* **Wachtwoord gewijzigd maar de SPN behouden:** De waarschuwing verdwijnt tijdelijk, maar keert na 40 dagen terug.
* **SPN verwijderd, maar het account zit nog steeds in Domain Admins:** De waarschuwing verdwijnt, maar het onderliggende risico blijft bestaan.

#### Hoe te diagnosticeren

```powershell
$privilegedGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins", "Administrators")
$threshold = (Get-Date).AddDays(-40)

foreach ($group in $privilegedGroups) {
  Get-ADGroupMember -Identity $group -Recursive |
    Where-Object { $_.objectClass -eq "user" } |
    ForEach-Object { Get-ADUser $_ -Properties ServicePrincipalName, PasswordLastSet } |
    Where-Object { $_.ServicePrincipalName.Count -gt 0 -and $_.PasswordLastSet -lt $threshold } |
    Select-Object SamAccountName,
      @{N="Wachtwoordleeftijd (dagen)"; E={[math]::Round(((Get-Date) - $_.PasswordLastSet).TotalDays)}},
      @{N="SPN's"; E={$_.ServicePrincipalName -join "; "}}
}
```

#### Hoe op te lossen

**Beste optie: verwijder het account uit bevoorrechte groepen.** Serviceaccounts hoeven zelden Domain Admins te zijn. Maak een toegewijd, niet-bevoorrecht account aan met alleen de machtigingen die de service echt nodig heeft:

```powershell
Remove-ADGroupMember -Identity "Domain Admins" -Members "svc_account" -Confirm:$false
```

**Als je het niet uit de admin-groep kunt verwijderen:** Reset in elk geval regelmatig het wachtwoord (elke 30 dagen of minder):

```powershell
Set-ADAccountPassword -Identity "svc_account" `
  -NewPassword (ConvertTo-SecureString "YourNewStr0ngP@ssw0rd!" -AsPlainText -Force) -Reset
```

**Beste oplossing op lange termijn:** Converteer naar een **Group Managed Service Account (gMSA)**, dat zijn wachtwoord automatisch elke 30 dagen roteert:

```powershell
New-ADServiceAccount -Name "gMSA_SQLService" `
  -DNSHostName "gmsa_sqlservice.yourdomain.com" `
  -PrincipalsAllowedToRetrieveManagedPassword "SQLServersGroup"
```

## P-AdminLogin

#### Wat het betekent

Elk Active Directory-domein heeft een **ingebouwd Administrator-account** dat automatisch wordt aangemaakt wanneer het domein wordt ingesteld. Dit account heeft volledige controle over het hele domein en kan niet worden geblokkeerd.

Vanwege zijn macht en voorspelbaarheid (aanvallers weten dat het altijd bestaat) moet het worden gereserveerd voor **alleen noodgevallen**, zoals herstel na een ramp. Voor dagelijkse administratie moeten persoonlijke admin-accounts worden gebruikt (bijv., `adm_john`), zodat acties aan individuen kunnen worden gekoppeld.

#### Wat de scan controleert

De AD Scan controleert of het ingebouwde Administrator-account in de **laatste 35 dagen**bij een Domain Controller heeft ingelogd. Als dat zo is, wordt de waarschuwing geactiveerd, wat aangeeft dat het account wordt gebruikt voor routinetaken in plaats van voor noodgevallen.

#### Waarom de waarschuwing kan blijven bestaan

* **Het hernoemen van het account helpt niet.** De scan identificeert de ingebouwde Administrator aan de hand van zijn interne identificatie (RID-500), niet aan de hand van zijn naam.
* **Het wijzigen van het wachtwoord helpt niet.** De scan controleert inlogactiviteit, niet de leeftijd van het wachtwoord.
* **Geautomatiseerde scripts of geplande taken** die draaien onder de ingebouwde Administrator zullen de waarschuwing blijven activeren.
* **Je hoeft alleen maar te wachten.** Nadat je het account niet meer gebruikt, verdwijnt de waarschuwing automatisch na 35 dagen.

#### Hoe te diagnosticeren

```powershell
# Controleer wanneer de ingebouwde Administrator voor het laatst op elke DC heeft ingelogd
$domainSID = (Get-ADDomain).DomainSID
$adminSID = "$domainSID-500"

Get-ADDomainController -Filter * | ForEach-Object {
  $dc = $_
  $admin = Get-ADUser -Identity $adminSID -Server $dc.HostName -Properties LastLogon
  $lastLogon = [DateTime]::FromFileTime($admin.LastLogon)
  $daysAgo = [math]::Round(((Get-Date) - $lastLogon).TotalDays, 1)

  [PSCustomObject]@{
    DC        = $dc.HostName
    LastLogon = $lastLogon
    DaysAgo   = $daysAgo
    Status    = if ($daysAgo -le 35) { "WAARSCHUWING - Onlangs gebruikt" } else { "OK" }
  }
} | Format-Table -AutoSize
```

Controleer ook op geplande taken die mogelijk de ingebouwde Administrator gebruiken:

```powershell
Get-ADDomainController -Filter * | ForEach-Object {
  Invoke-Command -ComputerName $_.HostName -ScriptBlock {
    Get-ScheduledTask | Where-Object {
      $_.Principal.UserId -match "Administrator"
    } | Select-Object TaskName, @{N="RunAs"; E={$_.Principal.UserId}}
  }
}
```

#### Hoe op te lossen

1. **Maak persoonlijke admin-accounts** voor elke beheerder (bijv., `adm_john`, `adm_jane`)
2. **Werk alle geplande taken bij** zodat een toegewezen serviceaccount wordt gebruikt in plaats van de ingebouwde Administrator
3. **Stop met inloggen** met de ingebouwde Administrator voor routinetaken
4. De waarschuwing wordt automatisch verwijderd **35 dagen** na de laatste aanmelding

## P-AdminNum

#### Wat het betekent

Hoe meer accounts met administratorrechten er in je domein zijn, hoe groter het aanvalsoppervlak. Elk admin-account is een mogelijk toegangspunt voor een aanvaller. Veel organisaties bouwen in de loop van de tijd te veel admin-accounts op: tijdelijke toegang die nooit is ingetrokken, serviceaccounts die uit gemak aan Domain Admins zijn toegevoegd, enz.

#### Wat de scan controleert

De AD Scan telt het totale aantal **unieke gebruikers** over alle bevoorrechte groepen heen (Domain Admins, Enterprise Admins, Administrators, Account Operators, Server Operators, Backup Operators, enz.). Als dezelfde gebruiker in meerdere groepen zit, wordt die slechts één keer geteld.

De waarschuwing wordt geactiveerd als:

* Meer dan **10%** van de actieve gebruikers bevoorrecht zijn, OF
* Meer dan **50** bevoorrechte accounts bestaan

> Deze controle wordt overgeslagen voor kleine organisaties met minder dan 100 actieve gebruikers.

#### Hoe te diagnosticeren

```powershell
$privilegedGroups = @(
  "Domain Admins", "Enterprise Admins", "Schema Admins", "Administrators",
  "Account Operators", "Server Operators", "Backup Operators", "Print Operators"
)

$uniqueMembers = @{}
foreach ($group in $privilegedGroups) {
  try {
    Get-ADGroupMember -Identity $group -Recursive |
      Where-Object { $_.objectClass -eq "user" } |
      ForEach-Object { $uniqueMembers[$_.DistinguishedName] = $_.SamAccountName }
  } catch {}
}

$activeUsers = (Get-ADUser -Filter "Enabled -eq `$true" | Measure-Object).Count
$pct = [math]::Round(($uniqueMembers.Count / $activeUsers) * 100, 1)

Write-Host "Bevoorrechte accounts: $($uniqueMembers.Count)"
Write-Host "Actieve gebruikers: $activeUsers"
Write-Host "Verhouding: $pct% (waarschuwing als >10% of >50 accounts)"
Write-Host ""
$uniqueMembers.Values | Sort-Object | ForEach-Object { Write-Host "  - $_" }
```

#### Hoe op te lossen

Bekijk de lijst en verwijder accounts die echt geen admin-toegang nodig hebben:

```powershell
Remove-ADGroupMember -Identity "Domain Admins" -Members "username" -Confirm:$false
```

Best practices:

* Gebruik **aparte admin-accounts** (`adm_john`) die verschillen van dagelijkse gebruikersaccounts
* **Verwijder serviceaccounts** uit admin-groepen en geef ze alleen de specifieke machtigingen die ze nodig hebben
* **Controleer regelmatig** het lidmaatschap van bevoorrechte groepen

## P-ProtectedUsers

#### Wat het betekent

De **Protected Users** groep is een speciale beveiligingsgroep die is geïntroduceerd in Windows Server 2012 R2. Leden van deze groep krijgen extra bescherming:

* Ze kunnen **alleen verifiëren met Kerberos** (het veiligere protocol), niet met het oudere NTLM-protocol
* Hun **referenties worden niet in de cache opgeslagen** op machines waarop ze inloggen: een aanvaller die een werkstation compromitteert, kan hun referenties niet uit het geheugen stelen
* **Delegatie is uitgeschakeld:** hun account kan niet worden geïmiteerd door services

Deze bescherming is cruciaal voor administrator-accounts, die in de meeste aanvallen het primaire doelwit zijn.

#### Wat de scan controleert

De AD Scan controleert of alle **ingeschakelde admin-accounts** (leden van Domain Admins, Enterprise Admins, enz.) ook lid zijn van de **Protected Users** groep.

#### Waarom de waarschuwing kan blijven bestaan

* **Gebruikers die via geneste groepen zijn toegevoegd** worden mogelijk niet gedetecteerd. Voeg gebruikers **rechtstreeks** toe aan de Protected Users-groep.
* **Replicatievertragingen** tussen Domain Controllers kunnen tijdelijke inconsistenties veroorzaken.
* **Managed Service Accounts (gMSA)** worden van deze controle uitgesloten: ze hoeven niet in Protected Users te staan.

#### Hoe te diagnosticeren

```powershell
$protectedUsers = (Get-ADGroupMember -Identity "Protected Users").DistinguishedName
$privilegedGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins", "Administrators")

$notProtected = foreach ($group in $privilegedGroups) {
  Get-ADGroupMember -Identity $group -Recursive |
    Where-Object { $_.objectClass -eq "user" } |
    ForEach-Object { Get-ADUser $_ -Properties Enabled } |
    Where-Object { $_.Enabled -and $_.DistinguishedName -notin $protectedUsers }
}

$notProtected | Select-Object -Unique SamAccountName, Name | Format-Table -AutoSize
```

#### Hoe op te lossen

```powershell
Add-ADGroupMember -Identity "Protected Users" -Members "adm_john", "adm_jane"
```

> **Belangrijk:** Het toevoegen van accounts aan Protected Users dwingt **Kerberos-only-verificatie**af. Sommige oudere applicaties die NTLM vereisen, kunnen voor deze accounts stoppen met werken. **Test eerst met één account** voordat je alle beheerders toevoegt.
>
> Beste praktijk: admin-accounts moeten worden gebruikt **alleen voor beheertaken** (niet voor e-mail, internetten of het draaien van zakelijke applicaties), dus NTLM-compatibiliteit is zelden een probleem.

## S-OldNtlm

#### Wat het betekent

Windows ondersteunt verschillende verificatieprotocollen, van heel oud en onveilig (LM, NTLMv1) tot modern en veilig (NTLMv2, Kerberos). De oudere protocollen hebben bekende kwetsbaarheden die aanvallers kunnen misbruiken om wachtwoorden op het netwerk vast te leggen en te kraken.

De **LAN Manager-verificatieniveau** bepaalt welke protocollen zijn toegestaan. Het moet worden ingesteld op **niveau 5**, wat betekent: "alleen NTLMv2 accepteren, alle oudere protocollen weigeren."

#### Wat de scan controleert

De AD Scan leest Group Policy Objects (GPO's) om te verifiëren dat de `LmCompatibilityLevel` instelling is ingesteld op **5**. Als geen enkele GPO deze instelling definieert, gebruikt Windows standaard **niveau 3**, wat nog steeds enkele zwakkere protocollen accepteert.

| Niveau | Wat het toestaat                            | Beveiligd? |
| ------ | ------------------------------------------- | ---------- |
| 0-2    | LM en/of NTLMv1                             | Nee        |
| 3      | NTLMv2 (maar weigert oude protocollen niet) | Nee        |
| **5**  | **Alleen NTLMv2, LM & NTLMv1 weigeren**     | **Ja**     |

#### Waarom de waarschuwing kan blijven bestaan

1. **Je hebt rechtstreeks het register gewijzigd** in plaats van een GPO te gebruiken. De AD Scan leest GPO-bestanden, niet lokale registerinstellingen. Zelfs als de DC de juiste waarde in het register heeft, blijft de waarschuwing bestaan als deze niet via Groepsbeleid is ingesteld.
2. **Conflicterende GPO's:** Eén GPO stelt niveau 5 in, maar een andere GPO overschrijft dit met een lager niveau.
3. **Helemaal geen GPO:** Zonder enige GPO is de standaard niveau 3 (onveilig).

#### Hoe te diagnosticeren

```powershell
# Controleer de effectieve instelling op elke DC
Get-ADDomainController -Filter * | ForEach-Object {
  $level = Invoke-Command -ComputerName $_.HostName -ScriptBlock {
    (Get-ItemProperty "HKLM:\System\CurrentControlSet\Control\Lsa" `
      -Name LmCompatibilityLevel -ErrorAction SilentlyContinue).LmCompatibilityLevel
  }
  Write-Host "$($_.HostName): LmCompatibilityLevel = $level"
}

# Controleer welke GPO's deze instelling definiëren
Import-Module GroupPolicy
Get-GPO -All | ForEach-Object {
  [xml]$r = Get-GPOReport -Guid $_.Id -ReportType Xml
  if ($r.InnerXml -match "LmCompatibilityLevel") {
    Write-Host "GPO: $($_.DisplayName)"
  }
}
```

#### Hoe op te lossen

**Via Group Policy Management Console (aanbevolen):**

1. Open `gpmc.msc`
2. Bewerk de GPO die is gekoppeld aan `OU=Domain Controllers`
3. Navigeer naar: `Computerconfiguratie > Beleid > Windows-instellingen > Beveiligingsinstellingen > Lokaal beleid > Beveiligingsopties`
4. Stel in **"Netwerkbeveiliging: LAN Manager-verificatieniveau"** op `Alleen NTLMv2-reactie verzenden. LM & NTLM weigeren`
5. Stel in **"Netwerkbeveiliging: sla de LAN Manager-hashwaarde niet op bij de volgende wachtwoordwijziging"** op `Ingeschakeld`
6. Voer `gpupdate /force` uit op alle Domain Controllers

**Via PowerShell:**

```powershell
$gpoName = "DC - Enforce NTLMv2"
$gpo = Get-GPO -Name $gpoName -ErrorAction SilentlyContinue
if (-not $gpo) { $gpo = New-GPO -Name $gpoName }

Set-GPRegistryValue -Name $gpoName `
  -Key "HKLM\System\CurrentControlSet\Control\Lsa" `
  -ValueName "LmCompatibilityLevel" -Type DWord -Value 5

Set-GPRegistryValue -Name $gpoName `
  -Key "HKLM\System\CurrentControlSet\Control\Lsa" `
  -ValueName "NoLMHash" -Type DWord -Value 1

New-GPLink -Name $gpoName `
  -Target "OU=Domain Controllers,$($(Get-ADDomain).DistinguishedName)" `
  -LinkEnabled Yes
```

## S-AesNotEnabled

#### Wat het betekent

Wanneer u zich verifieert in Active Directory, wordt uw wachtwoord gebruikt om communicatie te versleutelen met behulp van een specifiek algoritme. Oudere algoritmen (**DES**, **RC4**) zijn zwak en kunnen relatief eenvoudig worden gekraakt. Moderne algoritmen (**AES-128**, **AES-256**) zijn veel sterker.

AES-ondersteuning werd geïntroduceerd met Windows Server 2008. Accounts die vóór de upgrade bestonden, of accounts met specifieke configuraties, kunnen echter nog steeds de oude, zwakkere versleuteling gebruiken.

#### Wat de scan controleert

Een account wordt in twee situaties gemarkeerd:

1. **Het wachtwoord van het account werd ingesteld voordat uw domein werd geüpgraded naar Server 2008.** Omdat AES-versleutelingssleutels alleen worden gegenereerd wanneer een wachtwoord wordt ingesteld op een moderne DC, hebben deze oude wachtwoorden alleen zwakke RC4/DES-sleutels.
2. **Het account heeft een Service Principal Name (SPN)** en de versleutelingsinstellingen bevatten geen AES (het `msDS-SupportedEncryptionTypes` attribuut mist AES-vlaggen).

#### Hoe te diagnosticeren

```powershell
# Zoek serviceaccounts zonder AES-ondersteuning
Get-ADUser -Filter 'ServicePrincipalName -like "*"' `
  -Properties ServicePrincipalName, "msDS-SupportedEncryptionTypes", PasswordLastSet |
  Where-Object { ([int]$_."msDS-SupportedEncryptionTypes" -band 24) -eq 0 } |
  Select-Object SamAccountName,
    @{N="Versleutelingstypen"; E={$_."msDS-SupportedEncryptionTypes"}},
    PasswordLastSet

# Hetzelfde voor computeraccounts
Get-ADComputer -Filter 'ServicePrincipalName -like "*"' `
  -Properties "msDS-SupportedEncryptionTypes" |
  Where-Object { ([int]$_."msDS-SupportedEncryptionTypes" -band 24) -eq 0 } |
  Select-Object Name, @{N="Versleutelingstypen"; E={$_."msDS-SupportedEncryptionTypes"}}
```

#### Hoe op te lossen

**Voor accounts met oude wachtwoorden:** Reset gewoon het wachtwoord. Dit genereert nieuwe AES-sleutels:

```powershell
Set-ADAccountPassword -Identity "svc_account" `
  -NewPassword (ConvertTo-SecureString "YourNewStr0ngP@ssw0rd!" -AsPlainText -Force) -Reset
```

**Voor accounts zonder AES-versleutelingsinstellingen:** Schakel AES in bij de versleutelingstypen van het account:

```powershell
# Schakel AES in voor een specifiek account (24 = AES-128 + AES-256)
Set-ADUser -Identity "svc_account" -Replace @{"msDS-SupportedEncryptionTypes" = 24}

# Voor een computeraccount
Set-ADComputer -Identity "server01" -Replace @{"msDS-SupportedEncryptionTypes" = 24}

# Bulkfix voor alle serviceaccounts zonder AES
Get-ADUser -Filter 'ServicePrincipalName -like "*"' `
  -Properties "msDS-SupportedEncryptionTypes" |
  Where-Object { ([int]$_."msDS-SupportedEncryptionTypes" -band 24) -eq 0 } |
  ForEach-Object {
    Set-ADUser $_ -Replace @{"msDS-SupportedEncryptionTypes" = 24}
    Write-Host "AES ingeschakeld voor $($_.SamAccountName)"
  }
```

> **Opmerking:** AES inschakelen is niet-destructief: bestaande verificatie blijft werken. Test echter met kritieke services voordat je dit in bulk toepast.

## A-NoGPOLLMNR

#### Wat het betekent

**LLMNR** (Link-Local Multicast Name Resolution) is een protocol dat Windows gebruikt om andere computers op het netwerk te vinden wanneer DNS het antwoord niet heeft. Het werkt door een vraag uit te zenden naar alle nabije machines: "Weet iemand waar `servername` is?"

Het probleem is: een aanvaller op hetzelfde netwerk kan **op deze uitzendingen reageren en doen alsof hij de doelserver is**, waardoor het slachtoffer zijn referenties naar de aanvaller stuurt. Dit wordt een **LLMNR-poisoning** aanval genoemd en is een van de meest gebruikte technieken tijdens aanvallen op interne netwerken.

LLMNR is een verouderd protocol dat moderne netwerken niet nodig hebben (DNS doet alles). Het moet via Groepsbeleid worden uitgeschakeld.

#### Wat de scan controleert

De AD Scan zoekt naar een **ingeschakelde en gekoppelde GPO** die LLMNR uitschakelt door de registerwaarde `EnableMulticast` in te stellen op `0`.

#### Waarom de waarschuwing kan blijven bestaan

1. **GPO bestaat maar is niet gekoppeld** aan een OU.
2. **GPO is uitgeschakeld**, zelfs als deze gekoppeld is.
3. **LLMNR is handmatig uitgeschakeld** (via register of `netsh`) maar niet via Groepsbeleid. De AD Scan leest GPO-bestanden, niet lokale machine-instellingen.

#### Hoe te diagnosticeren

```powershell
Import-Module GroupPolicy
Get-GPO -All | ForEach-Object {
  [xml]$r = Get-GPOReport -Guid $_.Id -ReportType Xml
  if ($r.InnerXml -match "EnableMulticast") {
    Write-Host "GPO '$($_.DisplayName)' - Status: $($_.GpoStatus) - Bevat LLMNR-instelling"
  }
}
```

#### Hoe op te lossen

```powershell
$gpoName = "Schakel LLMNR uit"
$gpo = Get-GPO -Name $gpoName -ErrorAction SilentlyContinue
if (-not $gpo) { $gpo = New-GPO -Name $gpoName }

Set-GPRegistryValue -Name $gpoName `
  -Key "HKLM\Software\Policies\Microsoft\Windows NT\DNSClient" `
  -ValueName "EnableMulticast" -Type DWord -Value 0

# Koppel aan de domeinroot zodat het op alle computers van toepassing is
New-GPLink -Name $gpoName `
  -Target (Get-ADDomain).DistinguishedName `
  -LinkEnabled Yes
```

Na het koppelen van de GPO, voer uit `gpupdate /force` op machines of wacht op de volgende vernieuwingscyclus van Groepsbeleid (meestal 90 minuten).

## Veelgestelde vragen

#### De waarschuwing wordt nog steeds weergegeven nadat ik de oplossing heb toegepast. Waarom?

De AD-scan wordt niet periodiek uitgevoerd. Nadat u een oplossing hebt toegepast, moet u **het script opnieuw uitvoeren** zodat de waarschuwing verdwijnt. Als de waarschuwing na een nieuwe scan blijft bestaan, was de oplossing waarschijnlijk slechts gedeeltelijk. Raadpleeg de sectie "Waarom de waarschuwing kan blijven bestaan" van de betreffende kwetsbaarheid. Zorg ervoor dat u de details van de kwetsbaarheid in uw rapport leest; die bevatten vaak details over de getroffen assets.

#### Heb ik Domain Admin-rechten nodig om de scan uit te voeren?

Sommige kwetsbaarheden (bijv. A-NoServicePolicy) vereisen verhoogde machtigingen om bepaalde AD-objecten te lezen. De scan uitvoeren met een **Domain Admin-account** zorgt ervoor dat alle objecten zichtbaar zijn en voorkomt fout-positieve waarschuwingen die worden veroorzaakt door onvoldoende machtigingen. Als dat niet mogelijk is, kunt u het script nog steeds uitvoeren als een gewone domeingebruiker, al kunnen sommige kwetsbaarheden verschijnen door een gebrek aan zichtbaarheid op AD-objecten.

#### Ik heb één kwetsbaarheid opgelost, maar er verscheen een nieuwe. Is dat normaal?

Ja. Sommige oplossingen kunnen andere problemen aan het licht brengen. Bijvoorbeeld: het installeren van LAPS (het oplossen van A-LAPS-Not-Installed) kan A-LAPS-Joined-Computers activeren als computerobjecten onjuiste machtigingen hebben. Dit is te verwachten: behandel elke waarschuwing op volgorde van ernst.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.stoik.io/help/help-nl/preventietools/what-is-the-active-directory-scan/ad-scan-vulnerability-remediation-guide.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
