Esta es la Part 6 de la serie AD DFIR Lab. Configuramos toda la auditoría antes de ejecutar los ataques — si no lo hacemos ahora, los ataques no dejarán rastro.
Por qué auditar antes de atacar
Un lab DFIR sin auditoría es como investigar un crimen sin cámaras de seguridad. Los ataques ocurren, pero cuando llegas a investigar no queda nada. Por eso Phase 8 va antes de Phase 9 (attacks): primero instrumentamos, después atacamos, y entonces los artefactos están ahí para analizarlos.
Lo que vamos a capturar:
Windows:
- Sysmon con
sysmon-modularde olafhartong (2704 líneas de reglas) - Windows Advanced Audit Policy vía
auditpol(no GPO) - PowerShell logging: Script Block (4104), Module (4103), Transcription
- Command line en 4688
- Logs operacionales: WinRM, WMI-Activity, TaskScheduler
Linux:
- auditd con 50 reglas DFIR (exec, auth, sudo, ssh, sssd, systemd, cron, priv esc)
- journald persistente en
/var/log/journal/
Windows: Sysmon con sysmon-modular
El Sysmon que trae GOAD es de 2021 (v13) y usa la config SwiftOnSecurity. Nosotros usamos la última versión de Sysmon (v15+) con sysmon-modular de Olaf Hartong, que tiene mejor cobertura para técnicas MITRE ATT&CK modernas.
# En el host Proxmox
cd /root/lab/audit
wget https://download.sysinternals.com/files/Sysmon.zip
wget https://raw.githubusercontent.com/olafhartong/sysmon-modular/master/sysmonconfig.xml
# 2704 líneas de reglas con mapping a MITRE ATT&CK
Y el playbook Ansible instala Sysmon en las 6 Windows VMs:
- name: Copy Sysmon.zip to Windows VM
ansible.windows.win_copy:
src: /root/lab/audit/Sysmon.zip
dest: 'C:\sysmon\Sysmon.zip'
- name: Unzip Sysmon
community.windows.win_unzip:
src: 'C:\sysmon\Sysmon.zip'
dest: 'C:\sysmon'
- name: Copy sysmon-modular config
ansible.windows.win_copy:
src: /root/lab/audit/sysmonconfig.xml
dest: 'C:\sysmon\sysmonconfig.xml'
- name: Install Sysmon (first time)
ansible.windows.win_command: 'C:\sysmon\Sysmon64.exe -accepteula -i C:\sysmon\sysmonconfig.xml'
when: sysmon_svc.exists is not defined or not sysmon_svc.exists
- name: Update Sysmon config (if already installed)
ansible.windows.win_command: 'C:\sysmon\Sysmon64.exe -c C:\sysmon\sysmonconfig.xml'
when: sysmon_svc.exists is defined and sysmon_svc.exists
La lógica está bien pensada: si es una instalación nueva, usa -i; si ya estaba instalado, usa -c para actualizar la config sin reinstalar.
Eventos Sysmon clave que captura la config modular
| ID | Evento | Para qué |
|---|---|---|
| 1 | ProcessCreate | Con command line — base de todo el análisis |
| 3 | NetworkConnect | Conexiones salientes |
| 7 | ImageLoaded | DLLs cargadas (detección de DLL sideloading) |
| 8 | CreateRemoteThread | Inyección de procesos |
| 10 | ProcessAccess | Apertura de handles a otros procesos (mimikatz → lsass.exe) |
| 11 | FileCreate | Creación de archivos en paths sospechosos |
| 13 | RegistryValueSet | Modificación del registro (persistencia) |
| 22 | DnsQuery | Resolución DNS — gold para detectar C2 |
Después de los ataques, tendremos miles de estos eventos en Microsoft-Windows-Sysmon/Operational.evtx.
Windows Advanced Audit Policy
Sysmon es genial pero no capta todo. El Security.evtx es quien tiene los eventos de Kerberos (4768, 4769), logons (4624, 4625), y DCSync (4662). Hay que activarlo explícitamente con auditpol:
- name: Enable Account Logon auditing (4768-4776 Kerberos)
ansible.windows.win_shell: |
auditpol /set /subcategory:"Credential Validation" /success:enable /failure:enable
auditpol /set /subcategory:"Kerberos Authentication Service" /success:enable /failure:enable
auditpol /set /subcategory:"Kerberos Service Ticket Operations" /success:enable /failure:enable
- name: Enable DS Access (4662 — DCSync detection)
ansible.windows.win_shell: |
auditpol /set /subcategory:"Directory Service Access" /success:enable /failure:enable
auditpol /set /subcategory:"Directory Service Changes" /success:enable /failure:enable
auditpol /set /subcategory:"Directory Service Replication" /success:enable /failure:enable
Categorías activadas (Success + Failure):
| Categoría | Eventos importantes |
|---|---|
| Account Logon | 4768 (TGT request), 4769 (TGS request), 4771, 4776 |
| Logon/Logoff | 4624 (success), 4625 (failure), 4634, 4647, 4648, 4672 (special) |
| Object Access | 5140/5145 (file share), 4656 (handle), 4663 (access) |
| DS Access | 4662 (DCSync detection) |
| Detailed Tracking | 4688 (process creation), 4689 (termination) |
| Privilege Use | 4673, 4674 |
| Account Management | 4720-4738 (user changes), 4726 (delete) |
| Policy Change | 4719, 4907 |
Command line en 4688
Por defecto el Event 4688 solo registra el nombre del ejecutable, no los argumentos. Para DFIR esto es inútil — necesitas ver qué parámetros usó el atacante. Se activa con una clave de registro:
- name: Enable command line in 4688
ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Audit
name: ProcessCreationIncludeCmdLine_Enabled
data: 1
type: dword
Sin esto, verías powershell.exe pero no powershell.exe -enc SQBFAHgA.... Con esto, capturas el payload completo.
PowerShell logging
Los atacantes usan PowerShell para todo. Sin logging de PowerShell, pierdes la mitad de los artefactos de un incidente moderno. Tres niveles:
# Script Block Logging — Event 4104 (el más importante)
- ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
name: EnableScriptBlockLogging
data: 1
type: dword
# Module Logging — Event 4103 (todos los módulos)
- ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging
name: EnableModuleLogging
data: 1
type: dword
- ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging\ModuleNames
name: '*'
data: '*'
type: string
# Transcription — archivos de texto con todo lo escrito
- ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription
name: EnableTranscripting
data: 1
type: dword
- ansible.windows.win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription
name: OutputDirectory
data: 'C:\PSTranscripts'
type: string
Con esto:
- Event 4104: cualquier bloque de script que PowerShell ejecuta (incluso si está obfuscado con Base64, se decodifica antes del log)
- Event 4103: cada comando individual de cada módulo
- Transcription: archivos de texto en
C:\PSTranscriptscon toda la sesión
Dimensionamiento de logs (importante para disco limitado)
El servidor Hetzner tiene 2×512 GB NVMe en RAID1, con ~310 GB libres en el pool ZFS tras crear todas las VMs. Los logs pueden crecer rápido si no los limitamos.
Cálculo conservador (per-VM y total):
| Log | Por VM | Total 6 Windows |
|---|---|---|
| Security | 512 MB | 3 GB |
| Sysmon | 512 MB | 3 GB |
| PowerShell Operational | 256 MB | 1.5 GB |
| WinRM Operational | 128 MB | 768 MB |
| WMI-Activity | 128 MB | 768 MB |
| TaskScheduler | 128 MB | 768 MB |
| Subtotal Windows | ~1.6 GB | ~10 GB |
| auditd Linux | - | 600 MB |
| journald | - | 500 MB |
| TOTAL | ~11 GB |
Con 310 GB libres en ZFS, el ratio de seguridad es ~28x. Cómodo.
# Tamaños aplicados con wevtutil
- ansible.windows.win_shell: wevtutil sl Security /ms:536870912
- ansible.windows.win_shell: wevtutil sl Microsoft-Windows-Sysmon/Operational /ms:536870912
- ansible.windows.win_shell: wevtutil sl Microsoft-Windows-PowerShell/Operational /ms:268435456
Gotcha: los tamaños iniciales que puse (1GB cada uno) eran excesivos para un lab en servidor compartido. La primera iteración llegaba a ~24 GB de logs potenciales. Revisando los ratios de disco antes de lanzar los ataques me di cuenta y bajé los valores. Siempre calcula el peor caso antes de activar auditoría completa en un entorno con disco limitado.
Linux: auditd con reglas DFIR
Para Ubuntu (LNX01), usamos auditd con reglas enfocadas a DFIR, no cumplimiento:
## ======= AUTHENTICATION =======
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k identity
-w /etc/sudoers.d/ -p wa -k identity
## ======= PROCESS EXECUTION =======
-a always,exit -F arch=b64 -S execve -k exec
-a always,exit -F arch=b32 -S execve -k exec
## ======= SUDO (uid != euid = escalated) =======
-a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k sudo_exec
## ======= SSH =======
-w /etc/ssh/sshd_config -p wa -k sshd
-w /root/.ssh/ -p wa -k root_ssh
## ======= PRIVILEGE ESCALATION =======
-w /bin/su -p x -k priv_esc
-w /usr/bin/sudo -p x -k priv_esc
-w /usr/bin/pkexec -p x -k priv_esc
## ======= KERNEL MODULES =======
-a always,exit -F arch=b64 -S init_module -S delete_module -k modules
## ======= SSSD / KERBEROS =======
-w /etc/sssd/ -p wa -k sssd
-w /etc/krb5.conf -p wa -k kerberos
-w /etc/krb5.keytab -p wa -k kerberos
## ======= CRON / SYSTEMD =======
-w /etc/cron.d/ -p wa -k cron
-w /etc/crontab -p wa -k cron
-w /var/spool/cron/ -p wa -k cron
-w /etc/systemd/ -p wa -k systemd
50 reglas en total, con keys para filtrado rápido:
# Buscar ejecuciones privilegiadas
sudo ausearch -k sudo_exec --start recent
# Buscar modificaciones a /etc/passwd
sudo ausearch -k identity
# Buscar intentos de autenticación SSSD
sudo ausearch -k sssd
Tamaño auditd
Configurado para 600MB total (200MB × 3 archivos) con rotación automática:
max_log_file = 200
num_logs = 3
max_log_file_action = ROTATE
Y journald persistente (sobrevive reboots), limitado a 500 MB:
[Journal]
SystemMaxUse=500M
MaxRetentionSec=30day
Storage=persistent
Verificación post-deployment
# Sysmon corriendo en Windows
ansible -i goad/inventory dc01 -m win_shell -a '(Get-Service sysmon64).Status'
# Running
# Cantidad de eventos Sysmon capturados ya
ansible -i goad/inventory dc01 -m win_shell -a '(Get-WinEvent -ListLog Microsoft-Windows-Sysmon/Operational).RecordCount'
# 1660
# Audit policy activa
ansible -i goad/inventory dc01 -m win_shell -a 'auditpol /get /category:* | Select-String "Success and Failure"'
# System Integrity Success and Failure
# Logon Success and Failure
# Process Creation Success and Failure
# ...
# auditd en Linux
ssh ubuntu@192.168.10.32 'sudo auditctl -l | wc -l'
# 50
Las 7 máquinas del dominio están instrumentadas. Cuando lancemos los ataques en Phase 9, cada técnica dejará huellas en los EVTX/logs que podremos analizar después con herramientas como masstin.
Siguiente: Part 7 — Fire and Blood: Attack Scenarios and Forensic Analysis (próximamente)
Anterior: Part 5 — The Smallfolk: Users, Groups and Vulnerabilities
$ comments