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

16 - Hunting em Containers e Kubernetes

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

Hunting em Containers e Kubernetes

Nota 16 do capítulo 08 (Técnicas de Hunting por TTPs), levando as técnicas de caça aos ambientes orquestrados e efêmeros.
Mapeia a telemetria disponível (audit logs do Kubernetes, Falco, runtime de node), as TTPs de containers e as consultas por hipótese.
Dialoga com as notas 12 a 15, com o capítulo 26 (ambientes modernos) e com os controles PRT.4, TH.11 e DAT.4 do capítulo 15.

1. Contexto e Posicionamento na Biblioteca

Ambientes orquestrados mudam a economia da caça: pods vivem minutos, nós são gado e imagens são reconstruídas a cada deploy, então forense de disco quase nunca existe no momento da pergunta. A evidência migra para dois planos, o plano de controle, onde o API server registra toda intenção antes da execução, e o plano de runtime, onde syscalls e eventos de container registram a execução real. O ATT&CK formalizou esse domínio com a série T16xx de técnicas de containers, e as plataformas geridas, EKS, GKE e AKS, exportam o audit log do plano de controle para o SIEM como qualquer outra fonte.

O posicionamento na biblioteca segue dois eixos. Com o capítulo 26, esta nota compartilha o tema de ambientes modernos, mas aqui o foco é o método de caça e não a arquitetura. Com o capítulo 15, o PRT.4 define os controles de proteção que reduzem a superfície, e esta nota assume que parte deles pode falhar, porque é aí que a caça entra. A mudança conceitual mais importante para o caçador vindo de endpoint é a identidade: no cluster, o adversário costuma ser uma service account, não uma pessoa, e as hipóteses precisam ler o API server com essa gramática.

2. Telemetria Disponível e Onde Coletar

A fonte central é o audit log do Kubernetes, habilitado no API server por audit policy, que registra cada chamada com verbo, usuário, origem, objeto e resposta. O desenho da policy define o custo e o valor: leituras com nível Metadata, escritas com Request, e subrecursos sensíveis como exec e portforward com RequestResponse, que capturam o corpo da requisição. Os stages RequestReceived e ResponseComplete cobrem o essencial sem duplicar volume. Sem export imediato para fora do cluster, o log vira alvo do próprio incidente, então o DAT.4 do capítulo 15 é pré-requisito, não opção. A tabela abaixo resume as fontes e os campos de caça.

Fonte O que registra Campos de maior valor
K8s audit logs do API server Toda chamada ao plano de controle verb, user.username, sourceIPs, objectRef (resource, subresource, namespace, name), requestObject, responseStatus.code, stage
Plano de controle da nuvem (EKS, GKE, AKS) Operações de cluster e de node Ator, ação, região, recursos modificados
Falco e runtime security Syscalls e eventos de runtime com contexto de container container.id, container.name, image, proc.cmdline, evt.type, user
Runtime de container (containerd, CRI-O) Ciclo de vida de pods e imagens Criação, start, stop, pulls de imagem, OOM
Node (journald, kernel, SSH) Atividade que escapa do namespace sudo, módulos de kernel, sessões SSH, alterações em /etc
Metadata e IAM da nuvem Uso de credenciais de nó e de conta de serviço Chamadas ao metadata, AssumeRole incomum

O Falco roda como daemonset com driver eBPF ou módulo de kernel e converte syscalls em eventos com contexto de container, pod e imagem, com saída para o SIEM. As regras do Falco seguem a disciplina de código do capítulo 18: repositório versionado, desc com justificativa, tags consistentes e revisão de falsos positivos por ciclo. O runtime de container complementa com pulls de imagem fora do registry aprovado, que é sinal direto de T1612, build de imagem no próprio host, e de imagem trojaneada em cadeia de supply chain.

3. TTPs de Containers e Kubernetes

As técnicas da série T16xx têm manifestação observável precisa, e a tabela abaixo concentra as oito que geram caça recorrente. A combinação pod privilegiado com hostPath é o prelúdio padrão do escape para o host; o abuso de token de service account é o passo lateral mais comum em incidentes reais; e o cryptomining é a monetização típica de clusters expostos.

TTP Manifestação típica ATT&CK
kubectl exec não autorizado Shell ou comando dentro de pod de produção por conta fora da janela T1609
Pod privilegiado ou com hostPath securityContext privileged true ou volume hostPath na raiz T1610
Escape para o host Mounts sensíveis, exploit de kernel, cgroup release_agent T1611
Abuso de service account token Token montado usado do pod para listar secrets e pods T1552.007 e T1528
Descoberta do ambiente list e get em pods, secrets e api-resources via API T1613
Build de imagem no host docker build com payload direto no node T1612
Cryptomining CPU sustentada, conexão a pool, deployment com réplicas altas T1496
Uso direto do kubelet API Requisições à porta 10250 contornando o API server T1609

Casos públicos dão escala ao repertório. O CVE-2018-1002105 demonstrou que o próprio API server pode virar proxy de abuso quando o bug permite escalada; kubelets com 10250 aberto e autenticação fraca foram fonte de sequestro de container por anos; e campanhas de cryptomining em clusters mal configurados mostram o ciclo completo, exposição, deployment, mineração e persistência por DaemonSet. O aprendizado para a caça é que o plano de controle entrega a intenção e o runtime entrega o ato, e hipóteses fortes cruzam os dois no mesmo minuto.

4. Hipóteses e Consultas de Exemplo

A tabela abaixo amarra as hipóteses da rotina às fontes e aos sinais, no formato SE e ENTÃO do capítulo 07. Cada linha vira item do catálogo com dono e cadência.

Hipótese Fonte Sinal observável
Exec em produção por conta humana fora da janela de manutenção Audit log verb create em pods/exec com usuário fora da allowlist
Pod privilegiado criado recentemente Audit log requestObject com privileged true ou hostPath montado
Token de service account usado para descoberta Audit log verbs list e get em secrets e pods por SA de workload
Shell em container de produção Falco spawned_process de shell dentro de container
Mineração em andamento Falco e métricas Processo de minerador, conexão a pool, CPU sustentada

O jq abaixo executa a primeira hipótese sobre o audit log exportado, devolvendo usuário, pod, namespace e IP de origem de cada exec. A allowlist entra no próximo estágio do pipeline, porque o hunt iterativo prefere ver tudo e filtrar depois.

jq -c 'select(.verb=="create" and .objectRef.resource=="pods" and .objectRef.subresource=="exec")
      | {ts: .stageTimestamp, usuario: .user.username, pod: .objectRef.name,
         ns: .objectRef.namespace, ip: .sourceIPs[0]}' k8s-audit.json | head -30

A segunda consulta encontra criação de pod privilegiado ou com hostPath, o prelúdio de escape que merece fila própria de triagem.

jq -c 'select(.verb=="create" and .objectRef.resource=="pods")
      | select((.requestObject.spec.containers[]?.securityContext.privileged == true)
               or (any(.requestObject.spec.volumes[]?; .hostPath != null)))
      | {ts: .stageTimestamp, usuario: .user.username, ns: .objectRef.namespace,
         pod: .objectRef.name}' k8s-audit.json

A terceira consulta mede descoberta por service account, ranqueando qual SA lista secrets e pods e em qual namespace, baseline direto para o caso da seção 5.

jq -r 'select(.user.username | startswith("system:serviceaccount:"))
      | select(.verb=="list" or .verb=="get")
      | select(.objectRef.resource=="secrets" or .objectRef.resource=="pods")
      | [.user.username, .verb, .objectRef.resource, .objectRef.namespace] | @tsv' k8s-audit.json |
  sort | uniq -c | sort -rn | head -25

Em ambiente Azure, a mesma hipótese de exec roda sobre a tabela AKSAudit do Sentinel, com o JSON do evento parseado em colunas, como abaixo, lembrando que o conector oferece também a variante AKSAuditAdmin com campos sensíveis.

AKSAudit
| where TimeGenerated > ago(7d)
| extend Evento = parse_json(Log)
| extend Verb = tostring(Evento.verb), Usuario = tostring(Evento.user.username),
         Recurso = tostring(Evento.objectRef.resource), Sub = tostring(Evento.objectRef.subresource),
         Pod = tostring(Evento.objectRef.name)
| where Verb == "create" and Recurso == "pods" and Sub == "exec"
| summarize Execs = count() by Usuario, Pod
| order by Execs desc

A regra Falco abaixo fecha a hipótese de shell no runtime, com exclusão versionada para as imagens de diagnóstico aprovadas, e o padrão de output segue o formato que alimenta o SIEM.

- rule: Shell em Container
  desc: Shell interativo iniciado dentro de container de producao
  condition: >
    spawned_process and container and
    proc.name in (bash, sh, dash, zsh, ash) and
    not container.image.repository startswith "registry.interno/diagnostico"
  output: shell em container (usuario=%user.name pod=%k8s.pod.name imagem=%container.image.repository comando=%proc.cmdline pai=%proc.pname)
  priority: WARNING
  tags: [container, shell, runtime]

5. Caso de Caça: Exec Não Autorizado

O caso da biblioteca parte do baseline de quem pode executar comandos em produção: a service account ci-deploy-bot dos runners de CI, dois administradores humanos e o break-glass documentado. O primeiro passo roda a consulta de exec de 30 dias e confirma que prod/pagamentos não registra exec humano; o segundo passo, na execução da caça, encontra system:serviceaccount:default:build-bot executando comando no pod api-pag-7f9d às 02h14, com sourceIP 203.0.113.9, ASN externo de contratada, enquanto build-bot historicamente só age no CIDR de CI 10.90.0.0/24. A anomalia dupla de identidade e origem já sustenta prioridade alta.

O terceiro passo cruza o runtime no mesmo minuto: Falco registra bash no mesmo pod, seguido de curl ao metadata 169.254.169.254 com resposta listando role do node, e de leitura de /proc/1/environ, padrão de coleta de segredos em variáveis de ambiente. O audit log completa o quadro às 02h19: list de secrets no namespace pagamentos usando o token da própria build-bot, montado no pod porque o chart de deploy habilita automountServiceAccountToken por padrão. O root cause é de configuração: a SA de CI estava vinculada a cluster-admin por conveniência do chart, e o token exposto valeu como identidade total.

A resposta e a conversão fecham o caso. Conteção revogou sessões e token, rotacionou os secrets do namespace e suspendeu a integração da contratada até revisão; erradicação corrigiu RBAC para permissões mínimas, desligou automount onde desnecessário e limitou egress para o metadata com política de rede e hop limit no IMDS. A conversão em detecção criou duas regras permanentes: consulta agendada no SIEM para exec por identidade fora da allowlist, e regra Falco para leitura de environ seguida de acesso ao metadata, ambas no repositório do capítulo 18. O registro do caso anotou a lacuna: até o hunt, nenhuma detecção cobria exec anômalo, o que entra como métrica de cobertura no capítulo 11.

6. Erros Comuns e Pontos de Atenção

  • Caçar sem audit policy desenhada; efeito: volume incontrolável ou lacuna total de escritas; correção: Metadata para leituras, Request para escritas e RequestResponse para exec e portforward.
  • Confundir identidade humana com identidade de workload; efeito: a caça não acha nada porque o adversário age como service account; correção: construir baseline separado por tipo de user.username.
  • Ignorar automount de tokens; efeito: todo pod vira ladrão em potencial da identidade da SA; correção: desligar por padrão, habilitar por exceção e caçar uso anômalo do token.
  • Analisar o node por evento isolado; efeito: escape de container parece processo comum no syslog; correção: correlacionar syscall com contexto de container e com o audit do mesmo minuto.
  • Depender apenas de scanner de imagem; efeito: build feito no host e imagem trojaneada na cadeia ficam invisíveis; correção: caçar T1612 e pulls fora do registry aprovado.
  • Excluir identidades de sistema do hunt; efeito: adversário que opera com identidade de nó ou de kube-proxy some do radar; correção: criar baseline também para system:nodes e cia, com exceções versionadas.
  • Manter o audit log apenas no cluster; efeito: atacante com privilégio apaga a própria trilha; correção: export imediato para SIEM fora do cluster, conforme o DAT.4.

7. Integração com o Restante da Biblioteca

O PRT.4 do capítulo 15 define os controles de proteção de containers que reduzem a superfície, e esta nota cobre a camada de caça que assume falha de controle; os dois juntos fecham o ciclo defesa e verificação. O TH.11 dá continuidade quando o achado pula para o node, tratado como endpoint tradicional, e o DAT.4 garante que o audit log sobreviva ao incidente. Com o capítulo 26, a fronteira é de método: lá está a arquitetura de ambientes modernos, aqui está o catálogo de hipóteses. A conversão das caças em regras Falco e consultas agendadas pertence ao capítulo 18, e a cobertura da série T16xx alimenta o mapa de lacunas do grupo MAP do capítulo 15.

A nota encerra com um princípio de priorização que organiza o backlog de caça em cluster: o API server é o sensor ideal porque vê intenção antes da execução, então caçadas que movem a detecção para o plano de controle, mudança de RBAC, criação de pod com spec suspeito, uso de SA fora do padrão, custam menos e acionam mais cedo que caçadas apenas de runtime. Runtime permanece indispensável porque prova o ato, mas o volume do backlog deve ser preenchido primeiro pelo plano de controle, e o runtime entra onde a intenção do API server não alcança, escape de container e abuso direto de kubelet.