> 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/es/guias-de-remediacion-de-vulnerabilidades/ad-scan-vulnerability-remediation-guide/anomalies.md).

# Anomalías

## A-LAPS-No-Instalado

#### Qué significa

Cada equipo Windows tiene una **cuenta de Administrador local integrada**. De forma predeterminada, esta cuenta suele tener la misma contraseña en todas las máquinas, o una contraseña que nunca cambia. Si un atacante compromete una máquina, puede reutilizar esa contraseña para acceder a todas las demás.

**LAPS** (Solución de contraseña de administrador local) resuelve esto estableciendo automáticamente una contraseña única, generada aleatoriamente, en cada equipo y almacenándola de forma segura en Active Directory. Solo los administradores autorizados pueden recuperarla.

#### Qué comprueba el análisis

El análisis de AD busca evidencias de que LAPS se ha configurado en tu Active Directory. En concreto, comprueba si los campos de datos necesarios de LAPS existen en tu configuración de AD. Si no existen, significa que LAPS nunca se instaló.

#### Por qué la alerta puede persistir

* **LAPS administrado solo mediante Intune:** Si usas Microsoft Intune para administrar las contraseñas de LAPS en la nube (sin configurar el AD المحلي local), el análisis de AD no puede detectarlo. El análisis solo examina tu Active Directory local.
* **LAPS se instaló parcialmente:** La configuración de LAPS puede haberse iniciado, pero no completado.

#### Cómo diagnosticar

```powershell
# Comprueba si LAPS está configurado en tu Active Directory
Get-ADObject -SearchBase (Get-ADRootDSE).SchemaNamingContext `
  -Filter "name -like 'ms-Mcs-AdmPwd' -or name -eq 'ms-LAPS-Password'" |
  Select-Object Name, whenCreated
```

Si esto no devuelve resultados, LAPS no está instalado.

#### Cómo solucionarlo

**Para Windows Server 2019 y posteriores (recomendado):** LAPS moderno viene integrado en Windows. Habilítalo mediante Directiva de grupo:

1. Abre `gpmc.msc` (Administración de directivas de grupo)
2. Edita o crea una GPO vinculada a tus OU de equipos
3. Navega hasta: `Configuración del equipo > Plantillas administrativas > Sistema > LAPS`
4. Configura los ajustes de LAPS (habilitar, establecer complejidad de contraseña, etc.)

**Para entornos más antiguos:** Descarga Legacy LAPS de Microsoft y ejecuta la extensión del esquema:

```powershell
Update-LapsADSchema
```

> **Nota:** Si administras las contraseñas de administrador local mediante otra herramienta (CyberArk, LAPS solo con Intune, etc.), contacta con el soporte de Stoïk para documentarlo como una excepción aceptada.

## A-LAPS-Equipos-Unidos

#### Qué significa

Cuando alguien agrega ("une") un equipo al dominio de Active Directory, esa persona se convierte en el **creador** del objeto de equipo en AD. De forma predeterminada, el creador obtiene permisos especiales sobre ese objeto.

El problema es que, cuando LAPS está instalado, la contraseña de administrador local se almacena en ese mismo objeto de equipo. Si el creador aún conserva los permisos correctos, puede **leer la contraseña de LAPS**, incluso si no es administrador. Esto significa que un usuario normal que alguna vez unió un PC al dominio podría recuperar la contraseña de administrador local de esa máquina.

#### Qué comprueba el análisis

Para cada equipo habilitado con LAPS desplegado, el análisis de AD comprueba **dos cosas**:

1. **¿La persona que unió el equipo sigue siendo el "propietario" del objeto de equipo?** Los propietarios pueden concederse a sí mismos cualquier permiso, incluido leer la contraseña de LAPS.
2. **¿El creador aún tiene permisos explícitos** sobre el objeto de equipo, como `Todos los derechos extendidos` (lo que permite leer la contraseña de LAPS), `WriteDacl` (lo que permite modificar permisos), `WriteOwner` (lo que permite recuperar la propiedad), o `GenericWrite`?

La alerta se activa si **cualquiera** de las condiciones es verdadera.

#### Por qué la alerta puede persistir

Esta es la fuente de confusión más común: **cambiar el propietario es solo la mitad de la solución.**

Muchos administradores cambian el propietario a "Domain Admins" y esperan que la alerta desaparezca. Pero el análisis de AD también comprueba si quedan permisos residuales (llamados ACE, o entradas de control de acceso) que se concedieron al creador original. Estos permisos permanecen incluso después de cambiar el propietario y deben eliminarse por separado.

#### Cómo diagnosticar

```powershell
# Enumera los equipos donde el creador aún tiene permisos de riesgo
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]@{
        Equipo       = $comp.Name
        CreatorIsOwner = $isOwner
        RiskyRights    = ($riskyAces | ForEach-Object { $_.ActiveDirectoryRights }) -join ", "
      }
    }
  } | Format-Table -AutoSize
```

#### Cómo solucionarlo

Necesitas hacer **ambas cosas** para cada equipo afectado:

1. **Cambiar el propietario** a Domain Admins
2. **Eliminar los permisos explícitos del creador**

El siguiente script hace ambas cosas automáticamente:

```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

  # Paso 1: cambiar el propietario a Domain Admins
  $domainAdmins = New-Object System.Security.Principal.NTAccount("$env:USERDOMAIN", "Domain Admins")
  $acl.SetOwner($domainAdmins)
  $modified = $true

  # Paso 2: eliminar los permisos explícitos concedidos al creador (y los SID huérfanos)
  $toRemove = @($acl.Access | Where-Object {
    -not $_.IsInherited -and
    ($_.IdentityReference.Value -eq $creatorSid.Value -or
     $_.IdentityReference.Value -match '^S-1-5-21-')  # SID huérfanos (cuentas eliminadas)
  })

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

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

> **Consejo:** Ejecuta primero el comando de diagnóstico para revisar la lista de equipos afectados antes de aplicar la corrección.

## A-NoServicePolicy

#### Qué significa

**Las cuentas de servicio** son cuentas utilizadas por aplicaciones y servicios (p. ej., SQL Server, agentes de copia de seguridad) para autenticarse en Active Directory. A diferencia de las cuentas de usuario normales, las cuentas de servicio son objetivos de alto valor: a menudo tienen permisos elevados y sus contraseñas rara vez se cambian.

Una **política de contraseñas de granularidad fina (PSO)** es una regla especial de contraseñas que puedes aplicar a grupos específicos de cuentas. El análisis de AD espera que tus cuentas de servicio estén cubiertas por una PSO que exija contraseñas de al menos **20 caracteres**, lo que las hace mucho más difíciles de descifrar.

#### Qué comprueba el análisis

El análisis de AD busca al menos una política de contraseñas (GPO o PSO) que imponga una longitud mínima de contraseña de **20 caracteres o más**.

#### Por qué la alerta puede persistir

1. **La cuenta de análisis no tiene permiso para leer la PSO.** Las políticas de contraseñas se almacenan en una zona protegida de AD que, de forma predeterminada, solo pueden leer los Domain Admins. Si el análisis se ejecuta con una cuenta con menos privilegios, simplemente no puede ver la PSO, aunque exista.
2. **La PSO existe, pero la longitud mínima está por debajo de 20** (por ejemplo, 12 o 15 caracteres).
3. **La PSO existe, pero no está asignada a ningún grupo o usuario.**

#### Cómo diagnosticar

```powershell
# Enumera todas las políticas de contraseñas de granularidad fina y sus ajustes
Get-ADFineGrainedPasswordPolicy -Filter * |
  Select-Object Name, MinPasswordLength, @{N="AppliedTo"; E={$_.AppliesTo -join ", "}}, Precedence
```

Si esto no devuelve nada, o bien no existe ninguna PSO o la cuenta que ejecuta el comando no tiene permisos para verla. Prueba a ejecutarlo con una cuenta de Domain Admin.

#### Cómo solucionarlo

**Si la PSO existe pero el análisis no puede verla:** Ejecuta el análisis de AD con una cuenta de Domain Admin.

**Si no existe ninguna PSO:** Crea una y asígnala a tus cuentas de servicio:

```powershell
# Crear una política de contraseñas para cuentas de servicio
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

# Asignarla a un grupo de seguridad que contenga tus cuentas de servicio
Add-ADFineGrainedPasswordPolicySubject `
  -Identity "Service Accounts - Strong Password" `
  -Subjects "SG_ServiceAccounts"
```

> **Nota:** Crear una PSO no fuerza inmediatamente los cambios de contraseña. Las contraseñas existentes seguirán funcionando hasta que expiren o se restablezcan manualmente. En ese momento se aplicará el nuevo mínimo de 20 caracteres.

## A-AuditDC

#### Qué significa

**Las políticas de auditoría** determinan qué eventos se registran en tus Controladores de dominio. Sin una auditoría adecuada, ataques como el robo de credenciales, los cambios no autorizados de grupos o el abuso de replicación (DCSync) pueden producirse sin dejar rastro en los registros.

El análisis de AD verifica que tus Controladores de dominio estén configurados para registrar los eventos de seguridad más importantes.

#### Qué comprueba el análisis

El análisis busca **13 subcategorías de auditoría específicas** que deberían estar habilitadas mediante Directiva de grupo en todos los Controladores de dominio:

| Categoría                                   | Qué registra                                                        |
| ------------------------------------------- | ------------------------------------------------------------------- |
| Servicio de autenticación Kerberos          | Intentos de inicio de sesión mediante Kerberos                      |
| Operaciones de tickets de servicio Kerberos | Solicitudes de tickets de servicio (detecta Kerberoasting)          |
| Administración de cuentas de equipo         | Uniones/cambios de equipos en AD                                    |
| Administración de grupos de seguridad       | Cambios en la membresía de grupos                                   |
| Administración de cuentas de usuario        | Creación, eliminación y restablecimiento de contraseñas de usuarios |
| Actividad de DPAPI                          | Uso de la API de protección de datos (acceso a credenciales)        |
| Creación de procesos                        | Nuevos procesos iniciados (detecta herramientas maliciosas)         |
| Inicio/Cierre de sesión                     | Inicios de sesión interactivos y remotos                            |
| Inicio de sesión especial                   | Inicios de sesión con privilegios elevados                          |
| Cambio de política de autenticación         | Cambios en la configuración de autenticación                        |
| Uso de privilegios sensibles                | Uso de permisos sensibles                                           |
| Extensión del sistema de seguridad          | Cambios en el subsistema de seguridad                               |

#### Por qué la alerta puede persistir

1. **Ajustes aplicados mediante `auditpol` directamente en el DC** no se detectan. El análisis de AD lee archivos de Directiva de grupo, no la configuración local del DC. Debes usar una GPO.
2. **GPO en conflicto:** Una GPO habilita el ajuste, pero otra GPO con mayor prioridad lo deshabilita.
3. **GPO no vinculada a la OU de Controladores de dominio:** La GPO existe, pero está vinculada a otra OU.

#### Cómo diagnosticar

```powershell
# Comprueba la política de auditoría efectiva en un Controlador de dominio
auditpol /get /category:*
```

Si la configuración local parece correcta pero la alerta persiste, comprueba que los ajustes provengan de una GPO (no de una anulación local):

```powershell
# Verifica qué GPO están vinculadas a la OU de Controladores de dominio
Get-GPInheritance -Target "OU=Domain Controllers,$($(Get-ADDomain).DistinguishedName)"
```

#### Cómo solucionarlo

1. Abre `gpmc.msc` (Consola de administración de directivas de grupo)
2. Crea o edita una GPO vinculada a `OU=Domain Controllers`
3. Navega hasta: `Configuración del equipo > Directivas > Configuración de Windows > Configuración de seguridad > Configuración avanzada de la directiva de auditoría > Directivas de auditoría`
4. Habilita **Éxito y error** para todas las subcategorías enumeradas arriba
5. Ejecuta `gpupdate /force` en todos los Controladores de dominio

Verifica la corrección:

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

## A-BadSuccessor

#### Qué significa

Windows Server 2025 introdujo un nuevo tipo de cuenta de servicio llamado **dMSA** (Delegated Managed Service Account). Se descubrió un fallo de seguridad por el que un usuario normal con ciertos permisos sobre una carpeta de Active Directory (llamada Unidad Organizativa, o OU) podía crear una dMSA y usarla para obtener acceso total de administrador al dominio.

Este ataque solo es posible cuando:

* Tienes al menos un **Windows Server 2025** Controlador de dominio
* Una **KDS Root Key** existe (requerida para las cuentas de servicio administradas)
* Un usuario sin privilegios tiene derecho a crear objetos en una OU

#### Qué comprueba el análisis

El análisis de AD busca usuarios o grupos sin privilegios que tengan permisos para crear o controlar objetos dMSA en cualquier OU, como `CreateChild`, `GenericAll`, `WriteDacl`, o `WriteOwner`.

#### Por qué la alerta puede persistir

* La corrección debe aplicarse en **cada** OU afectada, no solo en una.
* Los permisos heredados de las OU padre siguen aplicándose a las OU secundarias.
* Es posible que el análisis no reconozca como "privados" grupos de administración personalizados.

#### Cómo diagnosticar

```powershell
# Comprueba los prerrequisitos
Get-KdsRootKey  # La KDS Root Key debe existir para que el ataque sea posible

Get-ADDomainController -Filter * |
  Where-Object { $_.OperatingSystem -like "*2025*" } |
  Select-Object Name, OperatingSystem  # Al menos un DC Win2025

# Busca OU con delegaciones de riesgo
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
```

#### Cómo solucionarlo

Para cada OU marcada, elimina los permisos de riesgo de los usuarios sin privilegios:

```powershell
$ouDN = "OU=Servers,DC=yourdomain,DC=com"  # Sustituye por tu OU
$path = "AD:$ouDN"
$acl = Get-Acl -Path $path

# Elimina los permisos de riesgo para un grupo específico
$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

#### Qué significa

Cuando se agrega un usuario a un grupo privilegiado en Active Directory (como Domain Admins), el sistema marca automáticamente su cuenta con una bandera llamada `adminCount = 1`. Esta marca forma parte de un mecanismo de protección integrado.

El problema es que: **cuando eliminas a ese usuario del grupo de administradores, la marca NO se borra automáticamente.** Permanece para siempre, salvo que la elimines explícitamente.

El análisis de AD detecta cuentas que conservan este `adminCount` residual, pero que ya no son administradores reales. Esto puede indicar:

* Un usuario que fue administrador temporalmente y la limpieza no se completó
* Un posible problema de seguridad: estas cuentas aún pueden tener permisos elevados en ciertas áreas

#### Qué comprueba el análisis

El análisis encuentra cuentas de usuario habilitadas en las que `adminCount = 1` pero la cuenta no es actualmente miembro de ningún grupo privilegiado.

#### Cómo diagnosticar

```powershell
# Construye una lista de todos los usuarios privilegiados actuales
$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 {}
}

# Busca cuentas con la marca adminCount residual
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
```

#### Cómo solucionarlo

Después de confirmar que estas cuentas ya no deben ser administradores, borra la marca:

```powershell
# Borra adminCount para un solo usuario
Set-ADUser -Identity "username" -Clear adminCount

# O bórralo para todos los usuarios no privilegiados a la vez
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 "Se eliminó adminCount para $($_.SamAccountName)"
  }
```

## A-NoGPOLLMNR

#### Qué significa

**LLMNR** (Resolución de nombres por multidifusión local) es un protocolo que Windows usa para encontrar otros equipos en la red cuando DNS no tiene la respuesta. Funciona difundiendo una pregunta a todas las máquinas cercanas: "¿Alguien sabe dónde `servername` está?"

El problema es que un atacante en la misma red puede **responder a estas difusiones haciéndose pasar por el servidor objetivo**, engañando a la víctima para que envíe sus credenciales al atacante. Esto se llama **envenenamiento de LLMNR** y es una de las técnicas más comunes utilizadas durante ataques a redes internas.

LLMNR es un protocolo heredado que las redes modernas no necesitan (DNS lo resuelve todo). Debe deshabilitarse mediante Directiva de grupo.

#### Qué comprueba el análisis

El análisis de AD busca una **GPO habilitada y vinculada** que deshabilite LLMNR configurando la `EnableMulticast` valor del registro a `0`.

#### Por qué la alerta puede persistir

1. **La GPO existe pero no está vinculada** a ninguna OU.
2. **La GPO está deshabilitada**, incluso si está vinculada.
3. **LLMNR se deshabilitó manualmente** (mediante el registro o `netsh`) pero no a través de la Directiva de grupo. El escaneo de AD lee archivos GPO, no la configuración local de la máquina.

#### Cómo diagnosticar

```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)' - Estado: $($_.GpoStatus) - Contiene la configuración de LLMNR"
  }
}
```

#### Cómo solucionarlo

```powershell
$gpoName = "Disable LLMNR"
$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

# Vincular a la raíz del dominio para que se aplique a todos los equipos
New-GPLink -Name $gpoName `
  -Target (Get-ADDomain).DistinguishedName `
  -LinkEnabled Yes
```

Después de vincular la GPO, ejecute `gpupdate /force` en las máquinas o espere al siguiente ciclo de actualización de la Directiva de grupo (normalmente 90 minutos).


---

# 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/es/guias-de-remediacion-de-vulnerabilidades/ad-scan-vulnerability-remediation-guide/anomalies.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.
