> For the complete documentation index, see [llms.txt](https://docs.stoik.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stoik.io/cyber-best-practices/vulnerability-remediation-guides/ad-scan-vulnerability-remediation-guide/stale-objects.md).

# Stale objects

## S-OldNtlm

#### What it means

Windows supports several authentication protocols, from very old and insecure (LM, NTLMv1) to modern and secure (NTLMv2, Kerberos). The older protocols have known vulnerabilities that attackers can exploit to capture and crack passwords on the network.

The **LAN Manager authentication level** controls which protocols are allowed. It should be set to **level 5**, meaning "only accept NTLMv2, refuse all older protocols."

#### What the scan checks

The AD Scan reads Group Policy Objects (GPOs) to verify that the `LmCompatibilityLevel` setting is set to **5**. If no GPO defines this setting, Windows uses a default of **level 3**, which still accepts some weaker protocols.

| Level | What it allows                            | Secure? |
| ----- | ----------------------------------------- | ------- |
| 0-2   | LM and/or NTLMv1                          | No      |
| 3     | NTLMv2 (but doesn't refuse old protocols) | No      |
| **5** | **NTLMv2 only, refuse LM & NTLMv1**       | **Yes** |

#### Why the alert may persist

1. **You changed the registry directly** instead of using a GPO. The AD Scan reads GPO files, not local registry settings. Even if the DC has the correct value in the registry, the alert persists if it wasn't set through Group Policy.
2. **Conflicting GPOs:** One GPO sets level 5, but another GPO overrides it with a lower level.
3. **No GPO at all:** Without any GPO, the default is level 3 (insecure).

#### How to diagnose

```powershell
# Check the effective setting on each 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"
}

# Check which GPOs define this setting
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)"
  }
}
```

#### How to fix

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

1. Open `gpmc.msc`
2. Edit the GPO linked to `OU=Domain Controllers`
3. Navigate to: `Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options`
4. Set **"Network security: LAN Manager authentication level"** to `Send NTLMv2 response only. Refuse LM & NTLM`
5. Set **"Network security: Do not store LAN Manager hash value on next password change"** to `Enabled`
6. Run `gpupdate /force` on all 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

#### What it means

When you authenticate in Active Directory, your password is used to encrypt communication using a specific algorithm. Older algorithms (**DES**, **RC4**) are weak and can be cracked relatively easily. Modern algorithms (**AES-128**, **AES-256**) are much stronger.

AES support was introduced with Windows Server 2008. However, accounts that existed before the upgrade, or accounts with specific configurations, may still be using the old, weaker encryption.

#### What the scan checks

An account is flagged in two situations:

1. **The account's password was set before your domain was upgraded to Server 2008.** Since AES encryption keys are only generated when a password is set on a modern DC, these old passwords only have weak RC4/DES keys.
2. **The account has a Service Principal Name (SPN)** and its encryption settings don't include AES (the `msDS-SupportedEncryptionTypes` attribute is missing AES flags).

#### How to diagnose

```powershell
# Find service accounts without AES support
Get-ADUser -Filter 'ServicePrincipalName -like "*"' `
  -Properties ServicePrincipalName, "msDS-SupportedEncryptionTypes", PasswordLastSet |
  Where-Object { ([int]$_."msDS-SupportedEncryptionTypes" -band 24) -eq 0 } |
  Select-Object SamAccountName,
    @{N="EncryptionTypes"; E={$_."msDS-SupportedEncryptionTypes"}},
    PasswordLastSet

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

#### How to fix

**For accounts with old passwords:** Simply reset the password. This generates new AES keys:

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

**For accounts missing AES encryption settings:** Enable AES in the account's encryption types:

```powershell
# Enable AES for a specific account (24 = AES-128 + AES-256)
Set-ADUser -Identity "svc_account" -Replace @{"msDS-SupportedEncryptionTypes" = 24}

# For a computer account
Set-ADComputer -Identity "server01" -Replace @{"msDS-SupportedEncryptionTypes" = 24}

# Bulk fix for all service accounts missing 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 "Enabled AES for $($_.SamAccountName)"
  }
```

> **Note:** Enabling AES is non-destructive: existing authentication continues to work. However, test with critical services before bulk-applying.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.stoik.io/cyber-best-practices/vulnerability-remediation-guides/ad-scan-vulnerability-remediation-guide/stale-objects.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
