Datadog SECL es un lenguaje de dominio específico personalizado que se utiliza para crear expresiones y políticas del Agent dentro de Datadog Workload Protection. SECL permite a los equipos de seguridad definir reglas de detección de amenazas en tiempo real especificando condiciones, operadores y patrones que los agentes de seguridad pueden hacer un seguimiento en servidores, contenedores, aplicaciones e infraestructura en la nube.

Cómo encajan las reglas SECL

Piense en SECL como un filtro local: se ejecuta dentro del Agent en cada servidor, observando los eventos del kernel y del SO. Cuando un evento coincide con su expresión SECL, el Agent genera una detección.

Las reglas de detección de amenazas de Datadog actúan como lógica de backend: combinan una o más reglas del Agent (usando @agent.rule_id), agregan umbrales, suprimen el ruido y deciden cómo se enrutan las alertas.

En resumen, la regla del Agent encuentra el comportamiento sin procesar y la regla de detección lo convierte en historias de ataques de extremo a extremo.

Esta guía describe cómo crear expresiones de reglas manualmente, pero Workload Protection también proporciona el asistente Creador de reglas asistido para guiarlo en la creación de las reglas del Agent y de detección juntas. Consulte Crear las reglas personalizadas del Agent y de detección juntas.

Sintaxis de expresiones SECL

El formato estándar de una expresión SECL es:

<event-type>.<event-attribute> <operator> <value> [<operator> <event-type>.<event-attribute>] ...

Usando este formato, un ejemplo de regla para un sistema Linux se ve así:

open.file.path == "/etc/shadow" && process.file.path not in ["/usr/sbin/vipw"]

Operadores

Los operadores SECL se utilizan para combinar atributos de eventos en una expresión completa. Los siguientes operadores están disponibles:

Operador SECLDefiniciónVersión del Agent
==Igual7.27
!=No es igual7.27
>Mayor que7.27
>=Mayor o igual7.27
<Menor7.27
<=Menor o igual7.27
! o notNo7.27
^NOT binario7.27
in [elem1, ...]El elemento está contenido en la lista7.27
not in [elem1, ...]El elemento no está contenido en la lista7.27
=~Coincidencia de cadena7.27
!~Sin coincidencia de cadena7.27
&AND binario7.27
|OR binario7.27
&& o andAND lógico7.27
|| o orOR lógico7.27
in CIDREl elemento está en el rango IP7.37
not in CIDREl elemento no está en el rango IP7.37
allin CIDRTodos los elementos están en el rango IP7.37
in [CIDR1, ...]El elemento está en los rangos IP7.37
not in [CIDR1, ...]El elemento no está en los rangos IP7.37
allin [CIDR1, ...]Todos los elementos están en los rangos IP7.37

Patrones y expresiones regulares

Se pueden usar patrones o expresiones regulares en las expresiones SECL. Se pueden usar con los operadores in, not in, =~ y !~.

FormatoEjemploCampos admitidosVersión del Agent
~"pattern"~"httpd.*"Todo7.27
r"regexp"r"rc[0-9]+"Todo excepto .path7.27

Los patrones en los campos .path se usan como Glob. * coincide con archivos y carpetas al mismo nivel. **, introducido en 7.34, se puede usar al final de una ruta para coincidir con todos los archivos y subcarpetas.

Duraciones

Puede usar SECL para escribir reglas basadas en duraciones, las cuales se activan ante eventos que ocurren durante un periodo de tiempo específico. Por ejemplo, activar ante un evento donde se accede a un archivo secreto después de que haya transcurrido más de cierta cantidad de tiempo desde que se creó un proceso. Dicha regla podría escribirse de la siguiente manera:

open.file.path == "/etc/secret" && process.file.name == "java" && process.created_at > 5s

Las duraciones son números con un sufijo de unidad. Los sufijos admitidos son “s”, “m”, “h”.

Sintaxis específica de la plataforma

Las expresiones SECL admiten varias plataformas. Puede usar la documentación a continuación para ver qué atributos y ayudantes están disponibles para cada una.

Consejos para la creación de reglas

  • Establezca siempre el sistema operativo (SO).
  • Ancle en la ascendencia para reducir el ruido. Utilice process.ancestors.file.name.
  • Utilice duraciones (por ejemplo, > 5s, 10m, 2h) para apuntar a ventanas de ejecución estrechas.
  • Utilice la coincidencia exacta (==) siempre que sea posible, ya que resulta en el menor ruido.
  • La pertenencia a una lista (in [...]) es mejor para listas de permitidos o conjuntos controlados de valores.
  • Utilice una coincidencia glob (~"/path/*") para familias de rutas, ya que es más segura y rápida que regex.
  • Utilice regex (=~) solo cuando no se puedan usar globs/listas. Mantenga la expresión regex lo más estrecha posible. Como regla general, comience con == o in [...]. Recurra a regex solo como último recurso.
  • Utilice la negación (not in [...], !~) para definir excepciones explícitamente (por ejemplo, herramientas confiables).
  • Utilice operadores CIDR (in CIDR, not in CIDR) para límites de red.
  • Nombre las reglas según el comportamiento, con un formato que siga Qué + Quién + Contexto.
  • Etiquete generosamente: team, app, env, MITRE, severity.

Evite errores comunes

PatrónExplicación
open.file.path == "/etc/passwd", exec.comm != ""Demasiado amplio. Coincide con muchos casos de uso válidos.
container.id != ""Útil solo si se limita con un campo más específico.

Biblioteca de ejemplo

Puede encontrar ejemplos más detallados en la política predeterminada que se incluye lista para usar con el agente. Consulte Política predeterminada de Workload Protection.

En los archivos de política del Agent, cada regla incluye un id y un expression. También puede agregar actions opcionales. Consulte Variables y acciones para obtener más información.

Linux

Acceso a archivos confidenciales (lista de permitidos de herramientas seguras)

rules:
  - id: access_sensitive_files
    expression: >-
      open.file.path in ["/etc/shadow", "/etc/sudoers"] &&
      process.file.path not in ["/usr/sbin/vipw", "/usr/sbin/visudo"]
    filters:
      - os == "linux"

NGINX o PHP generando bash

rules:
  - id: nginx_php_spawn_bash
    expression: >-
      exec.file.path == "/usr/bin/bash" &&
      (
        process.ancestors.file.name == "nginx" ||
        process.ancestors.file.name =~ "php*"
      )
    filters:
      - os == "linux"

Acceso sospechoso a IMDS desde un contenedor

rules:
  - id: suspicious_imds_access
    expression: >-
      connect &&
      network.destination.ip in ["169.254.169.254"] &&
      container.id != ""
    filters:
      - os == "linux"

Carga de módulo del kernel fuera de la ventana de mantenimiento

rules:
  - id: kernel_module_load
    expression: >-
      load_module &&
      process.user != "root" &&
      process.ancestors.file.name not in ["modprobe", "insmod"]
    filters:
      - os == "linux"

Lectura de archivo confidencial poco después del inicio

rules:
  - id: sensitive_file_read_after_start
    expression: >-
      open.file.path == "/etc/secret" &&
      process.file.name == "java" &&
      process.created_at > 5s
    filters:
      - os == "linux"

Salida a IP no corporativas (lista CIDR de permitidos)

rules:
  - id: outbound_non_corporate_ips
    expression: >-
      connect &&
      network.destination.ip not in [10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12]
    filters:
      - os == "linux"

Windows

Persistencia en el registro a través de una clave de ejecución

rules:
  - id: registry_run_key_persistence
    expression: >-
      set_key_value &&
      open_key.registry.key_path =~ "*\\Software\\Microsoft\\Windows\\CurrentVersion\\Run*"
    filters:
      - os == "windows"

Binario sin firmar iniciando PowerShell

rules:
  - id: unsigned_binary_powershell
    expression: >-
      exec.file.path =~ "*\\WindowsPowerShell\\v1.0\\powershell.exe" &&
      process.parent.file.path !~ "*\\Program Files*" &&
      process.user_sid != "S-1-5-18"
    filters:
      - os == "windows"

Multiplataforma

Indicadores de criptomineros

rules:
  - id: crypto_miner_indicators
    expression: >-
      exec.args_flags in ["cpu-priority", "donate-level", ~"randomx-1gb-pages"] ||
      exec.args in [~"*stratum+tcp*", ~"*nicehash*", ~"*yespower*"]