Home Comunidade Eventos YouTube Networks Desafios // produtos Academy News CTI | CVE Contato

03 - Consultas e Linguagens (KQL, SPL, Sigma)

video explicativo
Video explicativoEspaco reservado para o video desta anotação — adicione video: https://youtu.be/... no frontmatter da nota.

Consultas e Linguagens (KQL, SPL, Sigma)

Nota 03 do capítulo 09 (Ferramentas e Plataformas), que formaliza a gramática de consulta e de detecção usada nas plataformas das notas 01 e 02.
Cobre KQL e SPL com exemplos completos e apresenta Sigma como representação neutra que documenta e portabiliza a lógica de caça.
Dialoga com a nota 04 (TIPs), com os controles DAT.4 e TH.8 do capítulo 15 e com o capítulo 18, onde a caça confirmada vira regra Sigma.

1. Contexto e Posicionamento na Biblioteca

As notas 01 e 02 mostraram consultas soltas em Splunk, QRadar, Elastic e nas consoles de EDR; esta nota organiza a gramática por trás delas. Três representações resolvem quase todo o cotidiano do hunter: KQL onde existe o ecossistema Microsoft (Defender e Sentinel), SPL onde existe Splunk e Sigma como formato neutro que documenta, compartilha e portabiliza a lógica de detecção. O AQL do QRadar, apresentado na nota 01, segue a mesma lógica declarativa do SQL e fica de fora para dar profundidade às três representações mais usadas, e o EQL do Elastic aparece na nota 01 como caso particular de correlação sequencial.

A tese da nota é que o hunter escreve lógica uma vez e a traduz com disciplina, em vez de reescrever do zero a cada plataforma. A tradução malfeita é uma das fontes silenciosas de falso negativo: a regra muda de sintaxe e muda de semântica junto, sem que ninguém perceba. Por isso as seções finais tratam da tradução entre linguagens como habilidade técnica própria, com procedimento e teste, e não como tarefa mecânica de substituição de tokens.

2. KQL: Sintaxe, Operadores e Séries Temporais

KQL (Kusto Query Language) é uma linguagem de pipeline tabular: cada linha é uma transformação sobre o resultado da anterior, encadeada pelo pipe. Os operadores de uso diário na caça são where para filtro, project e extend para moldar colunas, summarize para agregação, bin para baldes de tempo, dcount para contagem distinta, join e lookup para enriquecimento, mv-expand para explodir listas e make-series para séries temporais com preenchimento de zeros. O exemplo abaixo expõe password spraying (T1110.003) com janelas de uma hora sobre falhas de logon do Defender:

DeviceLogonEvents
| where Timestamp > ago(14d) and ActionType == "LogonFailed"
| summarize Tentativas = count(), Contas = dcount(AccountName)
    by RemoteIP, bin(Timestamp, 1h)
| where Contas >= 10
| order by Contas desc

O diferencial do KQL para caça é a família de funções de série temporal, que transforma agregação em análise estatística dentro da própria consulta, sem exportar para notebook. O exemplo abaixo detecta horas anômalas de conexões externas por host com decomposição de série, técnica aplicável a beaconing e a mudanças de comportamento:

DeviceNetworkEvents
| where Timestamp > ago(30d) and RemoteIPType == "Public"
| make-series Conexoes = count() default = 0
    on Timestamp in range(ago(30d)..now(), 1h) by DeviceName
| extend (Anomalia, Pontuacao) = series_decompose_anomalies(Conexoes, 3.0)
| mv-expand Timestamp to typeof(datetime), Conexoes to typeof(long), Anomalia, Pontuacao
| where Anomalia != 0
| project DeviceName, Timestamp, Conexoes, Pontuacao

Duas regras de engenharia mantêm consultas KQL saudáveis em produção. Primeira, sempre limitar a janela com ago, porque consulta sem janela varre o período de retenção inteiro e concorre com a operação. Segunda, preferir comparadores insensíveis a caixa (=~, in~) quando o campo vem de telemetria heterogênea, e documentar quando o comparador sensível é intencional, porque essa escolha muda o resultado em silêncio.

3. SPL: Pipelines, stats e transaction

O SPL (Search Processing Language) também é um pipeline, mas organiza a busca em dois estágios com papéis distintos: a busca indexada, que filtra o mais cedo possível para reduzir o volume, e os comandos de transformação, como stats, bin, dedup, eval e transaction. A regra de ouro de desempenho é empurrar o filtro para a busca indexada e deixar para stats apenas o que precisa ser calculado. O exemplo abaixo repete o stack counting de execução via WMI, hipótese contra T1047, no dialeto do Splunk:

index=sysmon EventCode=1 ParentImage="*\\wbem\\wmiprvse.exe"
| stats count AS execucoes, dc(host) AS hosts, values(Image) AS filhos BY CommandLine
| where hosts < 3
| sort - execucoes

O comando transaction agrupa eventos em transações com identificador comum, duração máxima e pausa máxima, e é a ferramenta nativa para cadeias com estado, como rajadas de upload ou sessões de movimento lateral. O custo é alto em memória e tempo, e por isso o uso disciplinado exige maxspan e filtro prévio: o exemplo abaixo agrupa POSTs de upload por origem em janelas de dez minutos e marca as rajadas com cinco eventos ou mais:

index=proxy src_ip=10.20.7.0/24 http_method=POST uri_path="*upload*"
| transaction src_ip maxspan=10m maxpause=2m
| where eventcount >= 5
| table _time, src_ip, eventcount, duration, uri_path

Para janelas longas sobre volume alto, o par tstats e data model acelerado é a resposta do Splunk, como mostrado na nota 01. A disciplina de caça em SPL é a mesma de qualquer pipeline: comentário no início da consulta com a hipótese, filtro temporal sempre presente e preferência por stats sobre transaction quando a agregação simples resolve, porque cada transaction desnecessário rouba capacidade do cluster inteiro.

4. Sigma: A Lógica de Detecção Neutra de Plataforma

Sigma descreve a lógica de detecção em YAML e deixa a sintaxe específica para o conversor, o que a torna o formato de documentação e de portabilidade do catálogo de caças. A estrutura fixa inclui título, identificador UUID, status, descrição, logsource com categoria e produto, bloco detection com seleções nomeadas e condition, além de falsepositives, level e tags do ATT&CK. O exemplo completo abaixo deriva a regra permanente da caça HUNT-2025-014 do capítulo 07, com filtro de ruído do cliente SCCM documentado no baseline:

title: Interpretador de Comandos Filho do Servico WMI
id: 7b8d4a21-3c9e-4f61-b0a2-9e51c3f8d2b4
status: stable
description: >
    Processo filho de interpretador nascido do serviço WMI, padrão de execução
    remota por ferramentas administrativas abusadas. Derivado da caça
    HUNT-2025-014 do capítulo 07.
logsource:
    category: process_creation
    product: windows
detection:
    selecao_pai:
        ParentImage|endswith: '\wbem\wmiprvse.exe'
    selecao_filho:
        Image|endswith:
            - '\powershell.exe'
            - '\cmd.exe'
            - '\mshta.exe'
    filtro_ruido:
        ParentCommandLine|contains: 'SC_ConfigMgr'
    condition: selecao_pai and selecao_filho and not filtro_ruido
falsepositives:
    - administração remota legítima via SCCM e RunBooks aprovados
level: high
tags:
    - attack.execution
    - attack.t1047

A conversão é feita pela ferramenta sigma-cli, que gera consulta pronta para cada backend com pipeline de normalização de campos:

sigma convert -t splunk -p sysmon regras/wmi_spawn_shell.yml
sigma convert -t lucene -p ecs regras/wmi_spawn_shell.yml

O valor operacional do Sigma aparece em três situações: documentar o catálogo de caças em formato revisável por qualquer analista, compartilhar regras com ISACs e com a comunidade sem amarrar a plataforma e migrar de SIEM levando o catálogo junto. O limite também é claro: Sigma descreve lógica de seleção pontual, e as análises estatísticas e sequenciais das seções 2 e 3 continuam dependendo da linguagem da plataforma, ou de um notebook.

5. Quando Usar Cada Uma

A tabela abaixo organiza a decisão por situação de trabalho, e não por preferência de ferramenta. A mesma hipótese frequentemente passa pelas três representações ao longo da vida: nasce como exploração em KQL ou SPL, se confirma como caça documentada e se estabiliza como regra Sigma convertida para o backend de produção.

Situação de trabalho Escolha Justificativa prática
Exploração interativa no Sentinel ou no Defender KQL Funções de série temporal e dcount nativas
Exploração interativa no Splunk SPL stats, tstats e ecossistema de apps maduro
Correlação sequencial por host no Elastic EQL sequence com janela e case-insensitivity
Detecção permanente multiplataforma Sigma Portabilidade, versionamento e revisão
Compartilhamento com ISAC e comunidade Sigma Formato aberto com conversores mantidos
Caça programática sobre data lake SQL e pandas Agregação e estatística fora do SIEM

A regra prática é documentar em Sigma qualquer lógica que valha a pena rodar duas vezes. O catálogo Sigma da organização, versionado em repositório com revisão por pares, é ao mesmo tempo a biblioteca de detecções e o espelho das caças confirmadas, e alimenta diretamente o controle MAP.4 de lacunas de cobertura do capítulo 15.

6. Traduzindo Lógica Entre Linguagens

A tradução entre linguagens é habilidade própria porque os operadores não têm correspondência exata: contains em SPL casa com substring em qualquer posição, endswith em Sigma ancora no fim da string e has em KQL casa com token inteiro dentro do campo. Traduzir por substituição de tokens produz regras que compilam e detectam outra coisa. O procedimento recomendado tem quatro passos: extrair a lógica semântica da consulta original, mapear cada seleção para o operador equivalente no destino, escolher os campos pelo esquema do destino e testar com casos positivos e negativos conhecidos antes de publicar.

O mesmo padrão da regra Sigma da seção 4 fica assim em KQL, com os operadores de fim de string e o filtro de ruído preservados:

DeviceProcessEvents
| where InitiatingProcessFileName =~ "wmiprvse.exe"
    and FileName in~ ("powershell.exe", "cmd.exe", "mshta.exe")
    and InitiatingProcessCommandLine !contains "SC_ConfigMgr"

E assim em SPL, com a seleção ancorada pelo caminho completo do pai:

index=sysmon EventCode=1 ParentImage="*\\wbem\\wmiprvse.exe"
    (Image="*\\powershell.exe" OR Image="*\\cmd.exe" OR Image="*\\mshta.exe")
    NOT ParentCommandLine="*SC_ConfigMgr*"

Duas armadilhas merecem verificação em toda tradução. A primeira é a sensibilidade a caixa, que varia por operador e por plataforma, e que em nomes de executável costuma ser irrelevante, mas em linha de comando às vezes é sinal. A segunda é a normalização de caminho: barra invertida no Windows sobrevive de forma diferente em cada esquema, e o padrão que casa no Sysmon cru pode não casar no campo normalizado do ECS. O teste com caso positivo conhecido, como uma execução registrada deliberadamente, fecha essa lacuna antes que a regra entre em produção cega.

7. Erros Comuns e Pontos de Atenção

  • Traduzir por substituição de tokens; efeito: regra equivalente na sintaxe e diferente na semântica, com falso negativo silencioso; correção: traduzir a lógica semântica e testar com casos positivos e negativos conhecidos.
  • Usar wildcard inicial sem necessidade; efeito: busca que varre o índice inteiro e degrada a plataforma; correção: ancorar o padrão no início do token e reservar wildcard livre para investigação pontual.
  • Escrever Sigma sem logsource coerente; efeito: conversão gera consulta vazia ou consulta sobre fonte que não existe no ambiente; correção: validar categoria e produto contra o inventário de dados antes de converter.
  • Condition ambígua no Sigma; efeito: união indesejada de seleções amplia demais o alarme; correção: nomear cada seleção com função clara e relembrar que seleções sem referência na condition se juntam por AND implícito.
  • Usar transaction sem maxspan; efeito: transação que engole o dia inteiro, custo alto e resultado sem interpretação; correção: delimitar maxspan e maxpause e preferir stats quando possível.
  • Deixar consulta confirmada sem virar Sigma; efeito: conhecimento preso na sintaxe de uma plataforma e perdido na troca de produto; correção: registrar a versão Sigma como fonte canônica e gerar as consultas por conversão.

8. Integração com o Restante da Biblioteca

Esta nota é a camada de linguagem do capítulo 09: as plataformas das notas 01 e 02 fornecem o lugar onde as consultas rodam, e a nota 05 fornece o ambiente onde a estatística além da consulta acontece. As técnicas de stack counting e clustering dos controles TH.8 e TH.9 se expressam exatamente nas consultas aqui exemplificadas, o controle DAT.4 decide quais esquemas normalizam os campos que as regras consomem, e o capítulo 18 consome o catálogo Sigma como matéria-prima do detection engineering. A tradução de lógica entre linguagens também é o que permite que a mesma hipótese rode na console do EDR da nota 02 e no SIEM da nota 01 com comportamento comparável.

Um hábito final fecha a nota com ganho permanente: toda consulta de caça que sobreviver a duas execuções merece versão Sigma no repositório, com testes de caso positivo e negativo anexados. Esse hábito simples converte exploração individual em ativo institucional, reduz a reescrita em cada troca de plataforma e dá ao capítulo 11 uma métrica honesta de catálogo vivo, porque regra sem execução e sem teste é papel morto dentro do repositório.