§1Visão geral e princípios básicos
RoamSwitch Server Edition é um conjunto de segurança de rede autônoma residente e sem cabeça e proteção de integridade desenvolvido especificamente para infraestruturas de servidores Linux em provedores de nuvem (AWS, GCP, Azure, VPS bare-metal) e data centers locais.
Ao contrário das edições de estação de trabalho cliente focadas na mobilidade e adaptação do perímetro Wi-Fi, a Server Edition é baseada em cinco princípios intransigentes: Inbound Default Drop, Critical Path File Integrity Monitoring (FIM), Preemptive Kernel LPE & Privilege Escalation Hardening, eBPF Runtime Threat Telemetry, e Isolamento autônomo de host air-gap com alertas de emergência pré-separação.
O princípio Zero Telemetry — nenhuma biblioteca de comunicação externa no próprio daemon — é aplicado no nível do código (por padrão, a única coisa que sai do anfitrião é a receção de dados assinados (os dados de CVE do kernel, as regras web e, em servidores Ubuntu, os dados de CVE de pacotes do Ubuntu usados pela verificação de CVE dos pacotes do sistema; manifesto verificado todos os dias, os dados de CVE em si cerca de uma vez a cada 30 dias), que também pode ser desativada, e toda outra exceção é algo que o operador ativa explicitamente; veja os princípios de projeto do §1), e os segredos (tokens de bot e configuração) são protegidos com permissões 0600.
1.1 Comparação: Edição Cliente vs. Edição Servidor
| Dimensão | Edição cliente (desktop/móvel) | Edição Server (Headless/Infraestrutura) |
|---|---|---|
| Implantação | Laptops, estações de trabalho móveis para desenvolvedores | VMs em nuvem, nós bare-metal, hosts de contêiner |
| Comportamento da rede | Comutação dinâmica de perfil baseada em Wi-Fi SSID / Gateway MAC | Descarte padrão de entrada estática. Somente portas explicitamente permitidas são expostas |
| Interface do usuário | GTK3 Desktop GUI + indicador de bandeja | CUI puro sem cabeça. Comandos CLI + assistente interativo de configuração + interface de terminal (roamswitch-server-tui) |
| Notificações de incidentes | Notificações na área de trabalho (libnotify) | Push direto para Telegram Bot, LINE Messaging API e Webhooks (Slack/Discord) |
| Defesas Primárias | Falsificação de ARP de Wi-Fi público, BadUSB, criptografia de documentos ransomware | Queda de reconhecimento externo, detecção de adulteração de FIM, fugas de contêiner, kernel LPE (CVE-2026-53362) |
1.2 Princípios Arquitetônicos Fundamentais
- Zero Telemetry: por padrão, nada sobre o usuário ou o ambiente é enviado para fora. O próprio daemon não tem nenhuma biblioteca de comunicação HTTP/TLS; somente para as notificações e os encaminhamentos que o operador configurou ele executa, como subprocessos, o
curldo sistema (Telegram / LINE / webhook; segredos como tokens e URLs são passados em uma configuração pela entrada padrão, nunca na linha de comando) e oopenssl(encaminhamento de syslog por TLS). A única comunicação externa ativada por padrão, além das atualizações do gerenciador de pacotes, é a seguinte. (1) Enquantocve_kernel_map_updates_enabled(true por padrão) estiver ativado, oroamswitch-updaterrecebe de forma anônima do lafine.net dados assinados. São os dados de CVE do kernel para a auditoria de isolamento de contêineres, as regras de deteção da camada de aplicações web (regras web) e, em servidores Ubuntu, os dados de CVE de pacotes do Ubuntu usados pela verificação de CVE dos pacotes do sistema. O manifesto assinado e a sua assinatura são verificados todos os dias (dois GET); os dados de CVE do kernel e os de pacotes do Ubuntu só são obtidos quando passaram cerca de 30 dias desde a última atualização (um servidor que ainda não tem os dados do Ubuntu obtém-nos na verificação diária seguinte), e as regras web só quando o manifesto tem uma versão mais recente. É um simples HTTPS GET sem query string nem cookies, cujo único cabeçalho que nomeia o software é umUser-Agent: RoamSwitch-Updaterfixo; só são aceitos dados cuja assinatura Ed25519 seja válida, e nada sobre este host é enviado. O operador pode desativá-la comroamswitch server config set cve_kernel_map_updates_enabled false, pelo assistente de configuração ou pela TUI do servidor; um false explícito em umserver.confexistente é mantido como está, e a auditoria continua a funcionar com a linha de base incorporada quando a atualização está desativada; já a verificação de CVE dos pacotes do sistema num servidor Ubuntu indica então «sem dados de CVE locais» e não devolve nenhum resultado. Toda outra exceção é ativada explicitamente pelo operador. (2) O encaminhamento de eventos (forward_enabled, false por padrão) envia apenas aos destinos syslog / arquivo JSON Lines / webhook assinado que o operador configurou. (3) Somente senpm_audit_signatures_enabled(false por padrão) estiver ativado e o operador executarroamswitch audit-npm-signatures <DIR> --confirm, o próprionpmcontata registry.npmjs.org. (4) Somente sesensor_pairing_enabled(false por padrão) estiver ativado ele se conecta, e apenas ao endereço do Sensor informado pelo operador (o Sensor é um produto separado, não coberto por Zero Telemetry). (5) O Fleet (camada Business) é apenas código do lado do dispositivo: um dispositivo não registrado não envia nada nem resolve nenhum nome; o serviço de gerenciamento não está implantado nem lançado e, por concepção, não existe canal de comando remoto. (6) A integração com LLM da ferramenta independente incluídaaccessscope(diagnóstico de segurança de logs de acesso) está desativada por padrão. Somente se for ativada (na linha de comando, quando se indica--llm) podem ser enviados a um serviço externo, por meio do comando de LLM escolhido pelo operador, um resumo do diagnóstico, linhas de log como evidência e informações sobre o ambiente (na funcionalidade de busca de logs). O daemon (roamswitch-server) não participa dessa comunicação, o AccessScope pode executar a sua análise por LLM também como root (o LLM corre então com os privilégios de root; recomenda-se um utilizador sem privilégios), e está fora do escopo do Zero Telemetry. A ferramenta separada incluídapersonalsoc(verificação de registos e defesas) funciona da mesma forma: apenas quando se indica--llm, um resumo do diagnóstico pode ser enviado a um serviço externo através do comando LLM escolhido pelo operador (fora do âmbito de Zero Telemetry). O comandopathscopenão chama nenhum LLM. (7) Somente seclamav_enabled(false por padrão) for ativado, o daemon executafreshclampara receber as assinaturas do ClamAV (uma vez, quando ainda não existe um banco de dados de assinaturas e, enquantoclamav_scan_dirsestiver definido, a cadaclamav_freshclam_interval_secs, 7200 segundos por padrão). - Inbound Default Drop: novas conexões TCP de entrada para qualquer porta que não seja uma porta permitida são descartadas pelo
nftables, sem sequer devolver um RST. Uma varredura de portas enxerga apenas as portas permitidas (loopback, conexões estabelecidas, ICMP e ICMPv6 são aceitos). - Fail-Closed e autorrecuperação: as regras de bloqueio por padrão e de isolamento permanecem no kernel e, por isso, são mantidas mesmo que o daemon pare ou reinicie (
Restart=always). A proteção das portas publicadas do Docker é reverificada a cada 60 segundos, e a lista de bloqueio de egress e o bloqueio de varredura de portas, a cada 300 segundos, reinstalando as regras que desapareceram. As regras de isolamento do estado DEGRADED são conferidas na avaliação a cada 15 segundos e reinstaladas se estiverem ausentes. Se o próprio conjunto de regras de bloqueio por padrão for apagado por um agente externo, ele não é reaplicado automaticamente; confirme pelo diagnóstico “Inbound default deny” (roamswitch server status). - Proteção por permissões 0600: o arquivo de configuração
/etc/roamswitch/server.confrecebe automaticamente as permissões 0600 ao ser criado e atualizado. Segredos como tokens e URLs de webhook também são passados aocurlem uma configuração pela entrada padrão e nunca são colocados na linha de comando (que outros usuários podem ver por meio de/proc/<pid>/cmdline).
§2Cenário de ameaças e modelo adversário
Os servidores modernos voltados para a Internet enfrentam varreduras automatizadas implacáveis, vetores de quebra de contêineres e escalonamentos de privilégios de kernel de dia zero.
- Reconhecimento automatizado e exposição de banco de dados: scanners em toda a Internet que localizam portas de banco de dados internas expostas involuntariamente (MySQL 3306, Redis 6379, Postgres 5432).
- Violação de caminho crítico e inserção de backdoor: Intrusos estabelecem persistência modificando binários de autenticação principais (
/bin/login,/usr/bin/sudo,/etc/pam.d/*,/etc/shadow). - Escalonamento de privilégios de kernel (CVE-2026-53362 Frag Gap): Atacantes sem privilégios transformam namespaces de usuários em armas (
unshare -U -r) para acionar corrupção de memória do kernel e escalar para root. - Container Socket Breakout: Contêineres configurados incorretamente com sinalizadores
/var/run/docker.sockou--privilegedmontados executando ações raiz no sistema operacional host. - Snooping de memória de processo: invasores anexando
ptraceou lendo/proc/$pid/memem processos para extrair chaves privadas ou credenciais.
§3Arquitetura do Sistema
RoamSwitch Server Edition opera como binários Rust nativos projetados para memória mínima e zero sobrecarga de CPU.
┌─────────────────────────────────────────────────────────────┐
│ Espaço de usuário e administrador │
│ │
│ roamswitch (CLI) roamswitch-mcp (AI Agent) │
│ · server status (34 itens) · ferramentas de auditoria │
│ · server config / setup · stdio JSON-RPC │
│ · fim verify / update │
│ │ │ │
└───────┼───────────────────────────────────┼─────────────────┘
│ (comandos CLI e config) │ (stdio)
┌───────▼───────────────────────────────────▼─────────────────┐
│ Base do sistema (systemd + privilégio root) │
│ │
│ roamswitch-server-daemon │
│ ├── CriticalPathFim (varredura SHA-256 em 2º plano) │
│ ├── módulo de integração eBPF/Falco │
│ ├── Notifier (alertas Telegram / LINE / Webhook) │
│ └── Air-Gap Controller (regras de emergência nftables) │
│ │
│ Configuração: /etc/roamswitch/server.conf (permissão 0600)│
│ BD de integridade: /var/lib/roamswitch/fim.db │
└─────────────────────────────────────────────────────────────┘
§4Mecanismos Básicos de Defesa
4.1 Segurança de limite (queda padrão de entrada)
O nftables aplica policy drop à chain input da tabela inet roamswitch_server. Somente novas conexões TCP de entrada para as portas indicadas pelo administrador (ssh_ports, allowed_ports) são permitidas, e o tráfego para portas não permitidas expira por timeout (é descartado). Loopback, conexões estabelecidas, ICMP e ICMPv6 são permitidos.
Mesmo que um Air-Gap (isolamento de emergência) seja acionado, os caminhos de administração — as portas SSH de manutenção (ssh_ports) e os IPs de origem de manutenção registrados (whitelist_ips), tanto conexões novas quanto estabelecidas — são mantidos no conjunto de regras, evitando que a recuperação remota se torne impossível (preserve_ssh_on_isolation, true por padrão). Qualquer outra conexão estabelecida (por exemplo, um C2 ou reverse shell já aberto pelo invasor) é cortada pelas cadeias default-drop. Se não for indicada nenhuma origem de administração (whitelist_ips e os endereços permitidos do guard.yaml estão vazios), as portas SSH de manutenção continuam a aceitar novas ligações de qualquer origem durante o isolamento, e o servidor emite um aviso no arranque. Com preserve_ssh_on_isolation=false, o isolamento corta também o SSH. A edição de servidor até à 1.10.4 tinha um defeito. As regras de isolamento descartavam as respostas SSH, pelo que o SSH do operador não funcionava durante o isolamento. Foi corrigido na 1.10.5.
4.2 Monitoramento de integridade de arquivos de caminho crítico (FIM)
Monitora a integridade por hash SHA-256 dos arquivos mais críticos para a inicialização, a autenticação, a rede e a administração do sistema. O escopo inclui 23 caminhos fixos (/etc/shadow, /etc/passwd, /etc/sudoers, /etc/ssh/sshd_config, /bin/login, /usr/bin/sudo, /usr/sbin/sshd, /usr/lib/systemd/systemd etc.); os arquivos diretamente em 12 diretórios (/etc/pam.d, /etc/sudoers.d, /etc/ssh/sshd_config.d, /etc/cron.d e /etc/cron.{hourly,daily,weekly,monthly}, /etc/systemd/system, /etc/ld.so.conf.d, /etc/profile.d, /root/.ssh), onde também se detecta o surgimento de novos arquivos (known_hosts e known_hosts.old em /root/.ssh ficam de fora, pois são reescritos a cada conexão SSH); os binários do próprio RoamSwitch; o authorized_keys de cada usuário que pode fazer login; e /etc/ld.so.preload, que não deve existir (seu surgimento é detectado). Após atualizações legítimas de pacotes, a linha de base saudável é atualizada automaticamente: em sistemas baseados em Debian, pelo hook /etc/apt/apt.conf.d/99roamswitch-fim (apt upgrade etc.); em sistemas baseados em RHEL e no openSUSE, por uma unidade systemd.path que observa /var/lib/rpm (roamswitch-fim-update.path). Ambos executam roamswitch fim update.
Identificação da via de intrusão (quem fez a alteração e através de que início de sessão SSH)
As notificações sobre um ficheiro alterado (FIM de caminhos críticos e FIM de ficheiros de bloqueio) passam a indicar o processo que fez a alteração (conta, executável, comando) e o início de sessão SSH a que pertence (IP e porta de origem, hora do início de sessão, método de autenticação e impressão digital da chave pública). Vem ativado por predefinição (fim_intrusion_context_enabled). No momento em que um evento é lido, o daemon tira um instantâneo de /proc/<pid> do processo que escreve (executável, utilizador, loginuid, sessionid, cgroup, cadeia de pais), porque um processo como tee ou sed desaparece um milissegundo depois. Um processo que já tinha terminado é completado pelo gravador de execuções (se estiver ativado). A associação a um início de sessão usa primeiro a tabela de sessões da guarda SSH e, na falta dela, as linhas Accepted do logind e do journald. Funciona mesmo com a guarda SSH desativada. Não é enviado nada para o exterior.
Só se confia nos valores que o kernel comunica: o executável vem de /proc/<pid>/exe (e não de argv[0]), o início de sessão de loginuid (definido uma única vez no início de sessão e herdado através de sudo e su) e do session-N.scope do cgroup, e o resto da cadeia de pais. Os valores que um processo pode alterar por si, como comm, a linha de comandos e o ambiente, são mostrados mas nunca usados para decidir; um processo que apenas se chama sshd não é tomado por um início de sessão SSH. Uma notificação distingue três respostas: encontrado (origem, hora, método, chave); «Não foi encontrado nenhum início de sessão SSH» (a verificação mostrou um serviço do systemd, um contentor, uma sessão de início local ou um processo sem sessão de início); e «Não foi possível determinar o caminho de acesso» (o processo já não existia e não consta do gravador de execuções, o logind não respondeu, a alteração foi encontrada pela verificação periódica e o processo é desconhecido, etc.). O que não pôde ser verificado nunca é apresentado como «não é um início de sessão». A notificação sai mesmo que a consulta falhe.
/etc/ssh/sshd_config: modified
Processo: root (iniciou sessão como admin) / /usr/bin/tee / comando: tee /etc/ssh/sshd_config (pid 4121)
Início de sessão SSH: a sessão que admin abriu a partir de 203.0.113.25:51544 às 2026-10-17 03:12:08 (autenticação: publickey, chave SHA256:AbCdEf0123456789)
/etc/sudoers: modified
Não foi possível determinar o caminho de acesso (a alteração foi encontrada pela verificação periódica, por isso não se sabe que processo a fez)
Passam também a ser detetadas as edições que colocam um ficheiro novo sob o mesmo nome: install, sed -i e cp seguido de mv no mesmo diretório. A marca por ficheiro fica no inode, pelo que este tipo de edição antes não gerava nenhum evento. Agora o daemon marca também os diretórios que contêm ficheiros vigiados e, quando um ficheiro com outro nome é fechado no mesmo diretório, volta a consultar o nome alguns milissegundos depois. Limite: um ficheiro escrito noutro diretório e movido com mv só é encontrado pela verificação periódica (fim_check_interval_secs). Nesse caso o processo que escreveu não é conhecido, e a notificação di-lo.
As medições foram feitas numa VM com Ubuntu 24.04 com a origem do operador num espaço de nomes de rede (netns) à parte. Com sudo tee, com um processo desligado com nohup (o seu IP de origem continuou a ser identificado depois de o operador terminar a sessão, com a nota «Essa sessão já terminou»), com uma cadeia sudo -i e com um cat de vida muito curta, a notificação mostrou o IP, o utilizador e o método de autenticação. Um início de sessão local deu «Não foi encontrado nenhum início de sessão SSH». Um processo que disfarçou o nome com exec -a "sshd: …" não foi tomado por SSH.
Além da notificação, o achado fica guardado na cronologia de incidentes (tipo fim) e em /var/lib/roamswitch/fim_intrusions.json (apenas root, os últimos 100). A ferramenta MCP verify_fim devolve-o num campo adicionado, recentIntrusionContext (apenas quando executada como root). O veredicto sobre se um ficheiro foi adulterado não muda. Limites: com o gravador de execuções desativado e um processo escritor que vive apenas um instante, o executável é desconhecido, e são mostrados o executável e a linha de comandos do processo pai. As notificações da vigilância de persistência (persistence_watch) não trazem informação de processo e por isso não recebem via de intrusão. A via mostra o processo que fez a alteração e o seu início de sessão, e nada mais: a porta de entrada em si (a vulnerabilidade explorada ou a forma como uma chave foi roubada) não é mostrada. Para desativar, defina fim_intrusion_context_enabled=false.
4.3 Endurecimento de Kernel e Contêiner
Frag Gap (CVE-2026-53362) Mitigação: impõe user.max_user_namespaces = 0 via sysctl, neutralizando vetores LPE. Yama LSM Protection impõe kernel.yama.ptrace_scope = 2, evitando inspeção de memória não autorizada. As cargas de trabalho de contêiner são auditadas quanto à exposição docker.sock. Na edição de servidor, esta proibição de espaços de nomes sem privilégios está ativada por predefinição (harden_userns_enabled). Impede o Podman rootless e semelhantes; defina-a como false se depender deles.
As portas publicadas do Docker (-p) contornam, como se sabe, o firewall padrão do host. Por isso, com protect_docker_ports=true (padrão), é descartado o tráfego vindo da interface externa cuja porta de destino antes do DNAT não esteja entre as portas permitidas (ssh_ports, allowed_ports) (o tráfego de retorno, o loopback e o tráfego entre contêineres não são afetados). No backend iptables / iptables-nft, as regras vão na cadeia DOCKER-USER (IPv4, e também via ip6tables quando o IPv6 do Docker está ativado); no backend nftables nativo do Docker (Docker 29 e posteriores, configuração sem DOCKER-USER), em uma tabela própria inet roamswitch_docker_guard (hook forward, prioridade -10), e esse único conjunto de regras cobre IPv4 e IPv6. O daemon reverifica periodicamente e reinstala as regras que desaparecem. Além disso, um guarda sempre ativo detecta em tempo real, por meio de docker events, o início de um contêiner --privileged ou a montagem de /var/run/docker.sock e o notifica imediatamente como risco de escape de contêiner (sem configuração; somente notificação, sem bloqueio automático). Em hosts que lidam com arquivos destinados a terceiros, como relés de e-mail ou pastas compartilhadas, o File Scan Guard, ativável opcionalmente (YARA integrado + ClamAV opcional), oferece varredura periódica e quarentena automática.
Container Exec Guard (container_exec_guard_enabled, true por padrão). Define o fanotify FAN_OPEN_EXEC (classe de notificação) na raiz overlay2 de cada contêiner Docker em execução e inspeciona o conteúdo de cada arquivo executado com as regras YARA embutidas, notificando em caso de correspondência. Como se inscreve em docker events e depois lista os contêineres em execução com docker ps, os contêineres que já estavam em execução quando o daemon iniciou também são cobertos. O conteúdo do arquivo executado é lido do descritor de arquivo entregue pelo fanotify, portanto pode ser inspecionado mesmo que o arquivo se apague logo após a execução. Apenas notifica e não interrompe nem nega a execução (a edição Server não tem nenhum fanotify de classe de permissão). O Docker 29 removeu o campo Status, já obsoleto, das mensagens de docker events, então até a 1.11.0 a inscrição falhava logo e a proteção ficava se reconectando a cada 5 segundos sem nunca conseguir uma inscrição. Desde a 1.11.1 ela usa Action, que tem o mesmo valor também em versões mais antigas do Docker. Quando a inscrição continua falhando, o intervalo de reconexão dobra de 5 segundos até 5 minutos, e o aviso para a mesma causa é registrado apenas na primeira vez.
4.4 Telemetria de ameaças em tempo de execução eBPF e ajuste anti-inchaço
Utiliza sondas eBPF modernas (CO-RE/BTF) para interceptar escalada de privilégios e tentativas de quebra de contêiner em milissegundos. Para eliminar os pontos problemáticos padrão do Falco — inchaço de log, esgotamento de disco e sobrecarga de CPU — o RoamSwitch padroniza um perfil otimizado (/etc/falco/config.d/99-roamswitch-optimized.yaml):
- Filtragem de gravidade (
priority: warning): Suprime a telemetria operacional ruidosa (Informações/Avisos) em 95%, revelando incidentes de segurança estritamente acionáveis. - Kernel-Level Pre-Drop (
drop_failed_exit: true): Descarta saídas de syscall com falha diretamente no teste do kernel, reduzindo as alternâncias de contexto da CPU em mais de 50%. - Otimização de espaço de memória (
cpus_for_each_buffer: 2): compacta buffers de anel de 8 MB para 2 MB, limitando estritamente o uso de memória a 30–50 MB. - Direct UNIX Domain Socket IPC: integração imediata por um socket em memória (
/run/roamswitch/events.sock), sem passar por E/S de disco. - Automated Log Cap (
/etc/logrotate.d/roamswitch-falco): a rotação diária commaxsize 50Me 7 gerações compactadas evita o crescimento excessivo dos logs do Falco.
Precisão e rapidez do isolamento eBPF (sem o deixar só nas mãos das regras do Falco)
A precisão e a rapidez do isolamento eBPF dependem das regras do sensor (Falco ou Tetragon). De facto, as regras padrão do Falco 0.45.0 (29 no total) não incluem nenhuma que detete um reverse shell no anfitrião: as regras de reverse shell são só para contentores, e algumas são descartadas pela condição priority: warning do RoamSwitch. O RoamSwitch não parte do princípio de que as regras são boas; compensa de três maneiras: mede quanto demora o isolamento, verifica regularmente que o caminho dos alertas está vivo e deteta por si os reverse shells.
Medição da latência do isolamento: por cada incidente eBPF o daemon regista o tempo desde a deteção do Falco até ler o alerta (detect_to_receive_ms), desde que o lê até a resposta terminar (receive_to_action_ms, medido depois de a chamada de isolamento regressar; no Air-Gap do anfitrião, até o conjunto de regras ser carregado) e a soma dos dois (detect_to_action_ms). Os valores surgem como campos adicionados em ebpf_incidents.json e na ferramenta MCP get_ebpf_incidents. A notificação de um processo isolado inclui uma linha «da deteção à resposta: N ms». Medido numa VM com Ubuntu 24.04 (Falco 0.45.0, modern eBPF): de 1 a 2 ms da deteção à receção, de 41 a 62 ms da receção ao isolamento do processo mais SIGKILL (42 a 64 ms no total) e 109 ms no total para o Air-Gap do anfitrião (dentro do objetivo de 150 ms). Os valores são dessa VM. O Tetragon marca a hora na receção, pelo que não tem detect_to_receive_ms.
Heartbeat (ebpf_heartbeat_interval_secs; 600 segundos por predefinição, 0 desativa-o, caso contrário de 60 a 86400): o pacote inclui uma regra do Falco própria do RoamSwitch, 96-roamswitch-heartbeat.yaml. Em cada intervalo o daemon abre um caminho descartável que só o root pode usar (um nome aleatório em /run/roamswitch/heartbeat/) e mede quanto tempo o alerta dessa regra demora a regressar pela saída do Falco. Uma única ida e volta mostra de uma vez que a regra está carregada, que o Falco está a funcionar e que o caminho de saída está vivo. Só quando duas verificações seguidas não regressam (a segunda um minuto depois da primeira) avisa: «as regras não estão carregadas ou a saída não está a chegar», no máximo uma vez em 24 horas. Uma linha de heartbeat é descartada sem chegar ao isolamento, à notificação, à lista de permitidos nem ao registo de incidentes. Não é enviado nada para o exterior. As idas e voltas medidas foram de 2 a 6 ms; ao retirar a regra o aviso chegou ao fim de cerca de 164 segundos e, ao restaurá-la, o estado voltou ao normal em cerca de 75 segundos.
O estado fica em /var/lib/roamswitch/ebpf_heartbeat.json e é lido pelo campo heartbeat da ferramenta MCP get_ebpf_incidents e pelo diagnóstico K-04 (agente de execução eBPF; o número de itens de diagnóstico continua a ser 34). Mesmo que o Falco esteja a funcionar, o K-04 reprova se o heartbeat não regressar. Limites: verifica-se uma única ida e volta de uma só regra (as chamadas de sistema da família open); não se consegue saber se outra regra está avariada por si. O que se avaria entre duas verificações (10 minutos por predefinição) só se vê na seguinte. Não é feito para o Tetragon. Num anfitrião em que o Falco não está em execução ou falta o ficheiro da regra, não se verifica nada nem se avisa de nada (disso trata a notificação existente de «guarda parada»). O Falco escreve uma linha de aviso no syslog por cada verificação (144 linhas por dia com o valor predefinido).
Deteção de reverse shell (própria do RoamSwitch)
Sem depender das regras do Falco, o RoamSwitch lê por si /proc de 2 em 2 segundos e procura uma shell ou um interpretador (sh, bash, python, perl, ruby, php, node e semelhantes) cuja entrada e saída padrão sejam uma única ligação TCP que este anfitrião abriu para um endereço externo. São abrangidos bash -i >& /dev/tcp/…, python, perl, nc -e e socat exec:. Só se comunica o que é visto duas vezes seguidas, uma vez por processo. Por predefinição só contam os endereços externos públicos; os privados (RFC 1918, CGNAT, link-local) só contam com reverse_shell_watch_include_private=true, porque o ProxyCommand do ssh, os contentores e o desenvolvimento local os tornam comuns e legítimos. O loopback nunca é vigiado. As ligações que o anfitrião aceitou (por inetd ou socat TCP-LISTEN) também não são abrangidas. Medido numa VM com Ubuntu 24.04, bash /dev/tcp, python, perl, nc -e e socat exec: foram detetados cada um cerca de 2,4 segundos após a ligação. Não são detetados ssh, ssh com ProxyCommand, git sobre ssh nem um cliente nc.
Uma deteção segue o mesmo caminho de um alerta do Falco (lista de permitidos, arrefecimento das notificações, ações por gravidade do guard.yaml, registo de incidentes) como um evento eBPF Critical chamado RoamSwitch Reverse Shell. Por predefinição isola o processo e termina-o (kill). Um reverse shell pertencente ao root não pode ser isolado por processo; tal como em qualquer evento Critical, segue-se então para o Air-Gap de todo o anfitrião. Há duas saídas se houver receio de que um programa legítimo seja assinalado por engano: reverse_shell_watch_notify_only=true (um Warning só com notificação; nada é isolado nem terminado; false por predefinição) e uma entrada na lista de permitidos, sudo roamswitch server allowlist add "RoamSwitch Reverse Shell" <nome do processo>. As três chaves de configuração são reverse_shell_watch_enabled (true por predefinição), reverse_shell_watch_include_private (false) e reverse_shell_watch_notify_only (false).
Limites: o filtro faz-se por nome (nome do processo e do executável), pelo que um binário caseiro com um nome diferente do de uma shell ou de um interpretador que ligue a sua entrada e saída padrão a um socket não é encontrado. As ligações por loopback (como o retorno de ssh -R) e as de menos de 2 segundos não são vistas, nem os processos que não sejam visíveis a partir do espaço de processos do anfitrião. Esta deteção existe apenas na Server Edition; o Mac e o cliente Linux não a têm.
4.5 Isolamento de Emergência do Entreferro com Alertas Pré-Separação
Imediatamente antes de cortar as interfaces de rede em caso de violação crítica, o daemon envia alertas de emergência de forma síncrona para Telegram, LINE e Webhooks. Os alertas acrescentam automaticamente o servidor Hostname e Primary IP Address.
🚨 [RoamSwitch IMMINENT AIR-GAP] CRITICAL: IMMINENT AIR-GAP HOST ISOLATION (cve_2026_53362_lpe)
🚨 CRITICAL SECURITY INCIDENT DETECTED: cve_2026_53362_lpe
Host: production-node-01 (IP: 192.168.1.10)
Process: exploit_payload (PID: 4921)
ACTION: Initiating host Air-Gap network isolation (SSH preservation active).
WARNING: Outbound internet connectivity will be cut immediately after this message.
Timestamp: 2026-09-06 18:00:00
⚠️ Network connectivity will be severed immediately.As condições de liberação dependem da confiança do acionador. Os acionadores de baixa confiança (por exemplo, um evento eBPF de nível Error ou inferior) são totalmente restaurados após um temporizador curto (server_safeguards.safety_timer_secs em guard.yaml, 300 segundos por padrão). Os acionadores de alta confiança (eBPF Critical/Emergency/Alert, escalonamento para isolamento do host por uma regra que se repete, adulteração de um canário etc.) nunca restauram em silêncio. Após o temporizador curto a causa é reverificada (o PID congelado ainda está vivo, a regra disparou de novo etc.) e o isolamento só é liberado, com notificação, quando a eliminação da causa é verificada. Se não for possível verificar e não houver ACK ao atingir o limite (isolation_hard_cap_secs, 3600 segundos por padrão; 0 = sem limite), ele passa a DEGRADED. O DEGRADED mantém o caminho de administração (portas SSH de manutenção e IPs de origem de manutenção, conexões novas e estabelecidas), permite novo tráfego de saída apenas para os IPs de origem de manutenção e nunca reabre por temporizador. A liberação ocorre somente por uma reverificação que comprove o fim da causa, por roamswitch server ack (um ACK durante o DEGRADED significa liberação) ou por roamswitch emergency-restore. Um isolamento confirmado com ACK no estado FULL é considerado assumido pelo operador: não é restaurado pelo temporizador, não é liberado automaticamente nem quando a eliminação da causa é verificada, não passa a DEGRADED e permanece até ser liberado por emergency-restore. Cada transição é gravada na linha do tempo de incidentes e notificada.
Registrador de execuções de processos & encaminhamento de eventos
Um registrador estritamente local que grava exec por meio do conector de processos do netlink funciona ativado por padrão (compartilhado com a edição Client). Ele guarda o caminho do executável, os argumentos da linha de comando (com comprimento limitado e caracteres de controle escapados), a linhagem de processos pais, o uid, o ID do contêiner, o SHA-256 do executável etc. em /var/lib/roamswitch/exec_log como JSON Lines com cadeia de hashes (0600; 200 MB / 14 dias por padrão). A cadeia de hashes torna a adulteração detectável, mas não evitável (um invasor que obtenha root pode reescrever toda a cadeia). As regras de correlação somente de notificação EXR-001 a EXR-010 (shell iniciado por um serviço web, execução a partir de /tmp ou memfd, encadeamento de ferramentas de ataque etc.) nunca isolam sozinhas. Somente se um operador ativar explicitamente exec_rules_isolation_optin (false por padrão) uma regra de alta gravidade é tratada como acionador de alta confiança do isolamento do host.
O encaminhamento de eventos (forward_enabled, false por padrão) envia apenas aos destinos que o operador configurou: syslog (RFC 5424 ou CEF, sobre UDP / TCP / TLS), um arquivo JSON Lines ou um webhook assinado com HMAC-SHA256. O syslog TLS passa pelo openssl s_client do sistema e o webhook pelo curl do sistema (segredos são passados em uma configuração pela entrada padrão, nunca na linha de comando); o daemon não tem nenhum crate TLS/HTTP. O que é enviado se limita aos campos nome do host, ID do evento, carimbo de data e hora, origem, gravidade, regra, ação, PID, nome do processo e resumo — para os eventos de detecção que aparecem na linha do tempo de incidentes e no histórico de notificações (eBPF, transições do estado de isolamento, FIM, canários etc.) e para as notificações das regras de execução — mais os hashes de selagem de segmentos do log de execuções. O log bruto de execuções não é incluído.
Deteção de tunelização DNS / exfiltração
Ao ativar dns_tunnel_detect_enabled (padrão: true), as consultas DNS de saída deste próprio host (apenas porta 53 UDP/TCP) são inspecionadas por meio de um consumidor NFQUEUE dedicado. Uma consulta é contabilizada como de «formato suspeito» (o padrão característico de ferramentas de tunelização DNS como iodine ou dnscat2) quando o seu rótulo tem mais de 40 bytes E a sua entropia de Shannon é superior a 3,8, ou quando o tipo de registro (qtype) é TXT/NULL (as consultas TXT para clamav.net, usadas pelas atualizações de assinaturas do ClamAV, não são contadas); uma notificação só é enviada quando ocorrem 10 ou mais consultas desse tipo em uma janela deslizante de 60 segundos (as notificações repetidas para o mesmo domínio esperam 300 segundos e, enquanto a rajada continua, 600 e 1200 segundos, até um intervalo máximo de 1800 segundos). Apenas o tráfego DNS (porta 53 UDP/TCP) é inspecionado; nenhum outro tráfego é examinado. A funcionalidade apenas notifica e nunca bloqueia automaticamente. A regra nft subjacente tem a flag bypass, de modo que as consultas DNS continuam a passar sem serem afetadas mesmo que a thread de detecção esteja parada ou sem resposta; a resolução de nomes nunca é interrompida por uma falha desta funcionalidade. Uma alteração desta configuração só tem efeito após um roamswitch server restart (sem recarga a quente).
Limitação conhecida: nomes de host longos separados por hifens (por exemplo, prod-us-east-1-web-server-node-0042) e atividades legítimas particularmente realistas em um servidor, como um servidor de e-mail que verifica registros TXT de SPF/DKIM de muitos domínios remetentes diferentes em um curto período, provocavam falsos positivos, conforme confirmado por medição, porque as rajadas TXT/NULL eram contabilizadas com um único contador global que não distinguia o domínio de destino. Ambos foram corrigidos em 23/09/2026. A correção consiste em uma lista de permissões de entropia configurável e na separação do contador de rajadas por domínio apex (uma aproximação simples com base nos dois últimos rótulos do QNAME, e não uma implementação estrita da Public Suffix List). A lista de permissões já inclui, por padrão, 16 sufixos de grandes CDNs/nuvens e PaaS (cloudfront.net, akamaiedge.net, akamaized.net, edgekey.net, edgesuite.net, fastly.net, azureedge.net, googleusercontent.com, amazonaws.com, r2.dev, workers.dev, vercel.app, netlify.app, supabase.co, firebaseapp.com, web.app), e os operadores podem adicionar os domínios internos da própria organização por meio de ServerConfig.dns_tunnel_entropy_allowlist (uma chave separada por vírgulas em server.conf, também editável pela TUI). A lista de permissões dispensa apenas a verificação combinada de comprimento do rótulo e entropia; a detecção pelo tipo de registro TXT/NULL (qtype) aplica-se sempre, independentemente da lista de permissões, o que impede um atacante de disfarçar um túnel sob um domínio permitido (a única exceção é o TXT para clamav.net, usado pelas atualizações de assinaturas do ClamAV, que não é contado porque um terceiro não pode criar subdomínios sob esse domínio). O contador de rajadas passou a ser separado por domínio apex, o que elimina os falsos positivos causados por um único contador global que ignorava o domínio de destino (a lógica de janela deslizante de 60 segundos e o limite de 10 consultas não foram alterados por esta correção; o intervalo de renotificação foi depois alterado para crescer de 300 segundos até no máximo 1800 segundos enquanto a rajada continua). O tráfego malicioso real de ferramentas como iodine ou dnscat2 apenas alterna rótulos e qtype sob um único domínio controlado pelo atacante, de modo que restringir a contagem ao domínio apex não reduz a eficácia da detecção.
Deteção e bloqueio de força bruta SSH (ssh_guard)
Uma defesa contra força bruta própria do RoamSwitch, ativa com ssh_guard_enabled (true por predefinição). Segue o registo do sshd a partir do journald com journalctl -f (só sem journald segue auth.log ou secure), conta as falhas por endereço de origem e, para uma origem que atinge o limiar (por predefinição 6 em 600 segundos), descarta apenas as novas ligações (ct state new) às portas SSH na tabela inet roamswitch_sshguard. No momento do bloqueio, são também cortadas as ligações que essa origem já tinha abertas para o SSH (as entradas do conntrack são apagadas e uma regra descarta os pacotes do sentido de resposta). Só é bloqueada uma origem sem sessão autenticada, sem início de sessão por chave pública registado e sem isenção, e isto é verificado de novo mesmo antes de cortar; uma sessão autenticada e uma origem isenta nunca são cortadas. Um bloqueio começa em 1 hora, quadruplica a cada reincidência e tem um limite de 7 dias; o fim do prazo é tratado pelo timeout do nftables. Não inicia o Air-Gap e não envia nada para o exterior (apenas executa localmente comandos como journalctl, nft e loginctl). Quando o fail2ban (com uma jail sshd ativa) ou o CrowdSec (com um firewall bouncer em execução) já protege o sshd, cede-lhe o bloqueio e limita-se a detetar e notificar.
As linhas do registo contêm uma cadeia que o atacante escolhe (o nome de utilizador). Por isso o endereço de origem é lido apenas do fim da linha, em from <IP> port <N>, e um endereço de origem falso posto no nome de utilizador não faz com que um terceiro seja bloqueado. Do journald só são lidas as linhas cujas credenciais do remetente (_UID, _COMM) são as de um sshd de root, e as escritas com logger -t sshd são ignoradas. Seguir um ficheiro (auth.log) não é a predefinição, porque o ficheiro não tem nenhum campo que garanta o remetente e qualquer utilizador local autorizado a usar o syslog pode forjar linhas. Para não deixar os operadores à porta, nunca são bloqueados o gateway, o DNS, o próprio anfitrião, o loopback, whitelist_ips, ssh_guard_allow, a origem de uma sessão SSH autenticada, qualquer endereço que tenha iniciado sessão com chave pública nos últimos 30 dias e um Sensor emparelhado. Os endereços privados não estão isentos. Uma falha de chave pública (Failed publickey) não é contada.
Medido (uma VM Ubuntu 24.04 com journald e systemd reais): do 6.º falhanço ao bloqueio passaram cerca de 0,2 segundos (0,17 a 0,24 segundos). O endereço de origem do operador não foi bloqueado, e uma tentativa com um endereço de origem falso no nome de utilizador não fez com que um terceiro fosse bloqueado. Um hydra real (4 em paralelo) foi travado após 6 falhas. Também foram verificados o restauro de um bloqueio com o tempo restante depois de o servidor reiniciar, o levantamento de um bloqueio e a passagem a apenas detetar e notificar enquanto o fail2ban protege o sshd. Estes valores provêm deste ambiente de VM. Medido com o corte de ligações acrescentado: as falhas que ainda passavam depois de um bloqueio eram de 16 a 24 antes e de 0 a 4 depois. Apagar apenas as entradas do conntrack não cortava as ligações; só funcionou depois de acrescentar uma regra que descarta o sentido de resposta.
Regras da camada de aplicação web (web shells e código injetado)
A edição Servidor não tinha nenhuma análise acionada pela escrita, apenas a análise periódica de clamav_scan_dirs. Agora vigia as raízes de documentos encontradas na configuração do servidor web (Apache, nginx, Caddy) com fanotify só de notificação (FAN_CLASS_NOTIF, que nunca pode bloquear outro processo) e verifica os ficheiros PHP, JavaScript, JSP e ASP logo que são escritos e fechados, com as regras da camada de aplicação web (web shells, código ofuscado injetado, PHP escondido em imagens, abuso de .htaccess). Uma análise periódica de 6 em 6 horas cobre os eventos perdidos e os ficheiros anteriores ao arranque. As regras têm três camadas (integradas, instaladas pelo atualizador diário após a verificação da assinatura e os seus ficheiros em /etc/roamswitch/rules.d/*.json); as 18 regras não contêm qualquer assinatura extraída de uma amostra real e descrevem apenas técnicas documentadas publicamente.
Na edição Servidor, a quarentena automática limita-se a critical por predefinição. Um resultado high apenas notifica e aciona o hook posterior à deteção; o ficheiro de um site em produção não é tocado. As notificações (Telegram, LINE, webhook) estão em 10 idiomas e indicam a regra e se o ficheiro foi posto em quarentena ou deixado. A obtenção das regras vai incluída na mesma obtenção única do atualizador diário e não acrescenta nenhum destino. Com cve_kernel_map_updates_enabled desativado não há qualquer contacto de rede e usam-se as regras integradas. Com um fanotify real, uma web shell escrita foi posta em quarentena em menos de 2 segundos e um ficheiro inofensivo foi deixado.
Após uma deteção, um executável colocado em /etc/roamswitch/hooks/post-detection recebe os resultados em JSON na entrada padrão (só é executado um ficheiro pertencente a root, não escrevível e num diretório seguro; sem shell, ambiente mínimo e paragem aos 30 segundos). A resposta opcional sobre contas (desativada por predefinição) revoga a shell de início de sessão do dono de um ficheiro posto em quarentena. Não faz nada com root, contas abaixo de account_min_uid (1000 por predefinição), utilizadores com sessão iniciada nem o utilizador do daemon; a shell anterior é registada e roamswitch web-rules unlock-account repõe-na. Falsos positivos medidos: 0 no núcleo do WordPress (2409 ficheiros), no phpMyAdmin (3356 ficheiros) e em dependências npm (14 743 ficheiros). Limites: só são lidos os primeiros 256 KB (ao escrever/executar) e 4 MB (análise), nomes fragmentados como 'ev'.'al' não são seguidos e, por falta de amostras reais, não se incluem assinaturas de malware concreto.
Honeytokens (iscos de credenciais)
Na inicialização do daemon, o RoamSwitch implanta de forma idempotente arquivos de credenciais falsas em caminhos reais conhecidos que atacantes e ferramentas automatizadas de roubo de credenciais realmente vasculham (/root/.aws/credentials, /root/.ssh/id_rsa, /root/.docker/config.json, /root/.pypirc e /root/.env.backup, sob /root porque o daemon é executado como root), cada um contendo um marcador ROAMSWITCH_HONEYTOKEN (ativado por padrão; honeytokens_enabled o desativa e honeytokens_home muda onde os iscos são colocados). Um arquivo real já existente em qualquer um desses caminhos nunca é sobrescrito (a implantação sempre verifica antes se o arquivo existe). O acesso real a um honeytoken também pode desencadear, dentro de um limite máximo, a implantação em cascata de iscos adicionais relacionados (um perfil AWS adicional, um config de SSH, um kubeconfig etc.). Os pacotes distribuídos até a 1.10.4 não incluíam roamswitch-honeytokens, necessário para esta funcionalidade, de modo que ela não era executada nas instalações feitas a partir dos pacotes. Ele é incluído desde a 1.10.5, e o problema de o sandbox do systemd bloquear as gravações em /root na edição Server também foi corrigido na 1.10.5. Desde a 1.11.1, os comandos docker executados pelo próprio RoamSwitch são iniciados com um diretório dedicado vazio como DOCKER_CONFIG, portanto não acionam o isco /root/.docker/config.json. A leitura por qualquer outro programa continua a ser detectada como antes.
Um processo de monitoramento em segundo plano (roamswitch-honeytokens) usa fanotify de classe de notificação (que não bloqueia nada) para monitorar a leitura e a abertura de cada isco. O evento traz o PID de quem acessa, de modo que o executável de origem é identificado na hora (em ambientes sem fanotify, passa a usar inotify e fuser). Como nenhum processo legítimo tem motivo para ler esses arquivos, qualquer acesso, exceto o dos binários do próprio RoamSwitch e o de clientes OpenSSH (ssh, scp, sftp, ssh-add, ssh-agent etc.; ssh-keygen não está incluído) nos iscos de SSH, é tratado como um sinal forte de reconhecimento pós-comprometimento por um intruso (MITRE ATT&CK T1552, Unsecured Credentials), e uma notificação é enviada. Um acesso cujo executável de origem não pode ser identificado também não é liberado, e sim tratado como detecção. A funcionalidade apenas notifica; não congela nem bloqueia o processo que acessa, nem toma qualquer outra medida adicional.
Limitação conhecida: o corpo do isco /root/.ssh/id_rsa contém texto legível e continua a ser um formato inválido como corpo em base64 de uma chave privada OpenSSH real. No entanto, a maioria dos scanners de segredos assinala arquivos apenas pela correspondência de expressão regular com o cabeçalho -----BEGIN ... PRIVATE KEY-----, de modo que consideramos limitado o impacto real na taxa de detecção. Além disso, em ambientes em que o fanotify não está disponível e se passa a usar o inotify, a identificação do processo que acessa o arquivo (por meio de uma chamada a fuser) pode não conseguir obter o PID nem o nome de processos extremamente efêmeros, que terminam logo após a leitura; nesse caso, o processo é apenas tratado como desconhecido, o que não afeta a detecção do próprio acesso (o evento é disparado e notificado normalmente).
Pacotes de provas (recolha forense automática)
A captura de provas é iniciada nestes casos. Um evento do sensor de ameaças em tempo de execução baseado em eBPF resulta em um isolamento de rede por processo (per-process) bem-sucedido; esse isolamento falha e é escalado para um Air-Gap em todo o host; ou é executado um Air-Gap em todo o host. Ela também é iniciada no caminho do canário de ransomware, quando uma adulteração é detectada, o processo é congelado e o host é isolado. Em um corte em todo o host, a captura é iniciada antes do corte e nunca o atrasa. Até a 1.10.4, ela só era executada após um isolamento por processo bem-sucedido; a 1.10.5 ampliou esses casos. Se nenhum PID alvo for conhecido, o snapshot de /proc não é coletado. O roamswitch-incident-capture é iniciado e salva um pacote de provas em <diretório de estado>/incident-evidence/<carimbo de data/hora>-<id curto>/. O que é capturado: uma captura de pacotes limitada a 30 segundos por meio do tshark na interface da rota padrão (registrada apenas como ignorada caso o tshark não esteja instalado) e um snapshot /proc/<pid> do processo alvo (status, cmdline, maps, um environ com os valores que parecem segredos substituídos por [REDACTED], uma lista dos destinos dos descritores de arquivo abertos (o conteúdo não é capturado) e a cadeia de processos ancestrais). A falha na captura de um único artefato não interrompe o pacote inteiro; ela é registrada e o restante da captura prossegue. Os pacotes distribuídos até a 1.10.4 não incluíam roamswitch-incident-capture, necessário para esta funcionalidade, de modo que ela não era executada nas instalações feitas a partir dos pacotes. Ele é incluído desde a 1.10.5.
Os resultados são reunidos em manifest.json, que registra o hash SHA-256 de todos os artefatos do pacote (para permitir detectar adulterações posteriores). Os pacotes nunca são excluídos automaticamente; os pacotes antigos só são removidos quando um operador executa explicitamente sudo roamswitch-incident-capture prune [--keep-days N] (retenção padrão: 30 dias). Também está disponível, a qualquer momento, o comando sudo roamswitch-incident-capture snapshot [--pid PID] [--reason TEXT] [--json] para uma captura manual.
As provas recolhidas não são verificadas no momento da captura. Para confirmar posteriormente se houve adulteração, execute sudo roamswitch-incident-capture verify <diretório do pacote> [--json]. O comando recalcula o hash de cada ficheiro atualmente presente no pacote e compara-o com os valores registados em manifest.json, reportando cada discrepância individualmente como modificado, em falta ou não registado (um ficheiro presente que o manifesto nunca registou).
Limitação conhecida: esta verificação compara o SHA-256 de manifest.json com registros mantidos fora do pacote, em dois locais: uma cadeia de registros fora do pacote (evidence_anchor.log, em que cada linha se encadeia à anterior e recebe o atributo de somente acréscimo) e o log do sistema (tag roamswitch-evidence). Reescrever manifest.json após a captura faz o verify falhar; alterar ou remover uma linha do registro também, porque a cadeia se rompe. Isso não impede um atacante com root que consiga reescrever tanto a cadeia quanto o destino para onde o log do sistema é encaminhado; recomenda-se encaminhar o log do sistema para outra máquina. A assinatura não está implementada. Um pacote sem esse registro (capturado por uma versão anterior) é indicado como «sem registro», ou seja, não tem confirmação externa.
§5Conjunto de diagnóstico de segurança de 34 verificações
A Server Edition executa 34 auditorias especializadas de integridade de segurança:
| # | Categoria | Verifique o título | Padrão e Lógica |
|---|---|---|---|
| 1 | Autenticação e acesso | Login raiz SSH e autenticação de senha | Verifica PermitRootLogin no. Se a autenticação por senha também estiver desativada, informa acesso somente por chave pública; mesmo com ela ativada, é aprovado desde que o login de root esteja proibido |
| 2 | Autenticação e acesso | Contas com senha vazia | Garante que nenhum usuário tenha hash de senha em branco em /etc/shadow |
| 3 | Autenticação e acesso | Sudoers Privilégio Higiene | Verifica se /etc/sudoers e /etc/sudoers.d não contêm NOPASSWD: ALL, que concede todos os privilégios sem senha |
| 4 | Rede | Negação padrão de entrada | Auditorias nftables para política de recebimento de entrada padrão |
| 5 | Kernel e integridade | Namespaces de usuários sem privilégios (Frag Gap) | Garante user.max_user_namespaces=0 (ou kernel.unprivileged_userns_clone=0), bloqueando a via de ataque de LPE |
| 6 | Kernel e integridade | Suporte eBPF BTF | Valida informações do tipo BTF do kernel via /sys/kernel/btf/vmlinux |
| 7 | Kernel e integridade | eBPF LSM ativo | Verifica se há bpf no parâmetro de inicialização lsm= do kernel |
| 8 | Rede | Barreira XDP no arranque | Cobre com uma barreira XDP de negação por predefinição a janela de arranque anterior à instalação da tabela nftables do Link Guard (experimental, apenas por ativação voluntária, não carregada por predefinição). Verifica a presença da ligação fixada; não estar carregada não é uma falha |
| 9 | Kernel e integridade | Agente de segurança de tempo de execução eBPF | Verifica se um agente como o Falco ou o Tetragon está em execução. Enquanto o Falco corre, verifica também se o alerta da regra própria do RoamSwitch regressa (o heartbeat) e reprova se não regressar (indicando os ficheiros do Falco do RoamSwitch em falta) |
| 10 | Kernel e integridade | Cronologia unificada de incidentes | Verifica se a cronologia que unifica os incidentes do Link Guard, Canary, eBPF Guard e Resource Guard consegue registar (eventos existentes ou armazenamento com permissão de escrita) e mostra o último tempo de contenção |
| 11 | Recipiente | Auditoria de montagem de soquete Docker | Detecta montagens de contêiner de /var/run/docker.sock |
| 12 | Recipiente | Contêineres privilegiados do Docker | Auditorias para cargas de trabalho de contêiner --privileged de alto risco |
| 13 | Recipiente | Isolamento do runtime de contentores (runc/gVisor/Kata) | Verifica o runtime de contentores predefinido. Um runtime baseado em runc (partilha o kernel do anfitrião) não passa; gVisor (runsc) ou Kata Containers (isolamento com uma VM por contentor) passa. Não aplicável se o Docker/containerd não for detetado |
| 14 | Recipiente | Proteção contra o contorno da firewall pelo Docker (DOCKER-USER) | Verifica se as regras do RoamSwitch estão realmente presentes na cadeia DOCKER-USER (sempre avaliada primeiro) ou na sua tabela nftables dedicada de proteção do Docker, para que as portas publicadas dos contentores não contornem a negação por predefinição da firewall através das regras do próprio Docker. Só é avaliado se protect_docker_ports estiver ativo em server.conf |
| 15 | Kernel e integridade | Teste real de deteção do ClamAV (EICAR) | Dois minutos após o arranque e depois a cada 6 horas, o daemon analisa um ficheiro de teste EICAR inofensivo a partir do seu próprio ambiente (por exemplo, dentro de uma sandbox do systemd) para confirmar que o ClamAV o deteta realmente. Só é avaliado se clamav_enabled estiver ativo em server.conf |
| 16 | Kernel e integridade | fanotify: eventos perdidos (excesso da fila) | Verifica se o kernel descartou eventos de monitorização de FIM e de execução de contentores devido a um excesso na fila de eventos do fanotify. As escritas e execuções de ficheiros durante um excesso escapam à monitorização em tempo real; se acontecer com frequência, aumente fs.fanotify.max_queued_events |
| 17 | Kernel e integridade | Exposição a CVE conhecidas do kernel | Compara a versão do kernel em execução com o mapa local de CVE conhecidas (linha de base integrada ou atualização com assinatura verificada). A verificação em si não faz qualquer comunicação externa; as atualizações do mapa são obtidas de acordo com cve_kernel_map_updates_enabled (true por predefinição, pode ser desativada). Um resultado que não possa ser determinado é reportado como inconclusivo, e não como uma falha |
| 18 | Integridade | Integridade de arquivo de caminho crítico (FIM) | Verificação de integridade SHA-256 de 23 arquivos críticos fixos, de todos os arquivos diretamente em 12 diretórios e mais |
| 19 | Kernel e integridade | Proteção de Processo Yama | Verifica se kernel.yama.ptrace_scope é 2 ou 3, impedindo a espionagem de memória |
| 20 | Rede | Encaminhamento de IP desativado | Verifica net.ipv4.ip_forward = 0 |
| 21 | Rede | Proteção de cookies TCP SYN | Verifica net.ipv4.tcp_syncookies = 1 |
| 22 | Rede | Filtragem de caminho reverso (rp_filter) | Verifica se net.ipv4.conf.all.rp_filter é 1 (estrito) ou 2 (flexível, para configurações multihomed), descartando pacotes falsificados |
| 23 | Kernel e integridade | Restrição de dump principal | Evita vazamentos de memória do processo via fs.suid_dumpable = 0 |
| 24 | Operações | Atualizações automáticas de segurança | Verifica a configuração de aplicação automática de patches por unattended-upgrades (Debian / Ubuntu), dnf-automatic (RHEL / Fedora) e similares |
| 25 | Operações | Sincronização de horário NTP | Verifica a sincronização via chrony ou systemd-timesyncd |
| 26 | Operações | Proteção de força bruta SSH | Passa enquanto a guarda SSH do próprio RoamSwitch (ssh_guard) estiver em execução e a bloquear, ou verifica a monitorização ativa através do fail2ban ou do crowdsec |
| 27 | Kernel e integridade | eBPF sem privilégios desativado | Verifica se kernel.unprivileged_bpf_disabled é 1 ou 2, prevenindo Spectre/LPE |
| 28 | Rede | Redirecionamentos ICMP ignorados | Evita envenenamento de rota via accept_redirects = 0 |
| 29 | Rede | Transmissões de eco ICMP ignoradas | Mitiga ataques DoS do amplificador Smurf |
| 30 | Kernel e integridade | Endurecimento de memória compartilhada | Verifica se /dev/shm está montado com pelo menos uma das opções nodev, nosuid ou noexec |
| 31 | Autenticação e acesso | Protocolos legados inseguros ausentes | Verifica que não há serviços em texto claro em escuta (telnetd, rshd, tftpd, …) nem clientes em texto claro (telnet, rsh, tftp, …) instalados (serviços e clientes são informados separadamente). |
| 32 | Kernel e integridade | Despejos principais do processo SUID restritos | Evita vazamentos de credenciais em falhas binárias SUID |
| 33 | Kernel e integridade | Programas auxiliares (iscos e recolha de provas) instalados | O daemon inicia pelo nome o programa de iscos de credenciais (honeytokens) e o de pacotes de provas, e não faz nada, em silêncio, se faltar algum. Esta verificação confirma que ambos estão instalados. |
| 34 | Rede | Ficheiros sensíveis expostos no servidor web | Identifica as raízes de documentos na configuração do Apache / nginx / Caddy e verifica, com pedidos ao próprio servidor, se os .git, .env, .DS_Store, phpinfo, dumps SQL, cópias de segurança e chaves privadas que lá existem podem realmente ser lidos através do servidor web. Um ficheiro só é considerado exposto se a resposta corresponder ao início do ficheiro em disco, pelo que um site que responde 200 a qualquer caminho, ou um ficheiro já negado com 403, não gera falsos alarmes. O conteúdo dos ficheiros nunca é reportado, apenas os caminhos. Não aplicável sem servidor web; se não for possível verificar, o resultado é «inconclusivo» e a pontuação não é reduzida. |
Cada um dos 34 itens recebe, quando aplicável, um identificador de função/categoria do NIST CSF 2.0 (por exemplo, PR.DS-01, DE.CM-09) e, apenas nos itens em que existe uma correspondência de alta confiança, também o número do controle do CIS Controls v8 (por exemplo, 10.1, 4.1). Os itens de correspondência ambígua não recebem um mapeamento forçado e permanecem sem mapeamento. Esta tabela de correspondência está incluída tanto na saída da CLI (roamswitch server status) quanto na do MCP (get_security_report), permitindo que operadores e auditores que precisam atender a requisitos de conformidade associem mecanicamente cada verificação do RoamSwitch aos frameworks existentes.
§6Autoverificação (verificação reproduzível em um ambiente Docker)
É executada uma Autoverificação que simula ataques internos e externos contra o pacote roamswitch-server instalado a partir do repositório APT oficial, com outro contêiner Docker no papel de atacante externo. A medição de 2026-09-07 na v1.3.2 teve todos os 18 itens PASS. Em 2026-09-25, a Autoverificação foi executada de novo com um pacote compilado a partir do código-fonte da série 1.10 (arm64, Docker Desktop), e 19 verificações passaram. A nova execução revelou seis defeitos do produto, todos corrigidos (incluídos na 1.10.5): o pacote não incluía os binários auxiliares, o FIM comunicava os honeytokens como arquivos novos, uma confirmação (ack) era ignorada, durante o isolamento as respostas do SSH de administração eram descartadas e o administrador ficava sem acesso, a porta 22 permanecia aberta mesmo com preserve_ssh_on_isolation=false, e o sandbox da unidade systemd bloqueava a gravação dos iscos. Você pode reproduzir esta verificação na sua própria máquina. Consulte o procedimento e os scripts em «Como reproduzir por conta própria», abaixo.
| # | Cenário | Vetor de ataque | Resultado da verificação |
|---|---|---|---|
| PENT-S1 | Nmap SYN Verificação furtiva | Sonde as portas 22, 80, 443, 3306, 8080 | O Default Drop do nftables descarta, sem qualquer resposta (Filtered), o tráfego para portas não permitidas, como 3306 (MySQL) e 8080. 100% bloqueado |
| PENT-S2 | Investigação de porta não permitida | curl conexões diretas às portas 3306 e 8080 | Com o bloqueio de entrada por padrão (inbound default deny), apenas a porta permitida 80 responde normalmente; as demais expiram por timeout (são bloqueadas) |
| PENT-S3 | Lista de bloqueio de Egress / C2 | Tentativa de conexão de saída para um endereço registrado no feed de IPs maliciosos | Apenas os endereços registrados são bloqueados por egress_ip_blocklist_enabled (true por padrão, nftables). O tráfego para hosts não registrados não é afetado (não é um bloqueio geral) |
| PENT-S4 | Ataque de adulteração FIM | Injetar carga útil de backdoor em /bin/login |
O FIM de Critical Path SHA-256 detecta a adulteração imediatamente. Após a restauração legítima, a linha de base é ressincronizada corretamente |
| PENT-S5 | Contenção baseada em gravidade via guard.yaml |
Injeção de um evento Falco Critical referenciando um processo real | Com on_critical: isolate_process + kill_process, o processo em questão é isolado da rede e, em seguida, recebe SIGKILL |
| PENT-S6 | Mecanismo de segurança para processos protegidos | Injeção de um evento do mesmo tipo referenciando o PID real do sshd |
A lista de processos protegidos (sshd, systemd, runtimes de contêiner etc.) mantém o sshd em execução. Apenas uma recusa é registrada em log, como falso positivo |
| PENT-S7 | Temporizador de segurança | Incidente de Air-Gap deixado sem confirmação (sem ACK do operador) | Com safety_timer_secs, o host se restaura automaticamente quando ninguém responde. Se houver ACK, o isolamento continua até o emergency-restore |
| PENT-S8 | Lacuna de fragmentação LPE do kernel | Execução de unshare -U -r com privilégios de usuário comum (verificado em uma VM real) |
O unshare -U -r, que é permitido sem o produto, é negado após a inicialização. user.max_user_namespaces e kernel.unprivileged_userns_clone ficam em 0, o ptrace_scope do Yama em 2 e o eBPF sem privilégios fica desativado (2026-09-25, VM Ubuntu 24.04, verificado tanto na versão pública v1.10.4 quanto na versão corrigida) |
Nota: a medição de PENT-S7 é da v1.3.2. Na versão atual, um isolamento causado por um gatilho de alta confiança é libertado quando se verifica que a sua causa desapareceu, e um isolamento reconhecido (ack) pelo operador mantém-se até o operador o libertar (um ack ignorado foi encontrado e corrigido na nova execução de 2026-09-25). Os gatilhos de baixa confiança recuperam com o mesmo temporizador. Ver §4.
Tipo de verificações — PENT-S8 confirma que uma funcionalidade do kernel (proibir namespaces de utilizador) está em vigor. PENT-S1 e S2 confirmam as regras nftables instaladas pelo RoamSwitch; quem descarta os pacotes é o kernel. Os pontos que exercitam a lógica própria do RoamSwitch são PENT-S3 (aplicação do feed), S4 (FIM), S5 e S6 (contenção e processos protegidos) e S7 (temporizador de segurança).
Prevenção de bloqueio de SSH
preserve_ssh_on_isolation=true (predefinição) foi concebido para manter o canal SSH de administração durante um Air-Gap (on_emergency). No entanto, a nova execução de 2026-09-25 mostrou que, até à 1.10.4, as regras de isolamento descartavam as respostas SSH, deixando o operador sem acesso durante o isolamento; a verificação anterior só tinha tido êxito depois de o isolamento ser levantado. A correção está na 1.10.5 e foi verificado, com a causa do isolamento ainda presente, que o SSH funciona durante o isolamento.
Limites do escopo de verificação (uma divulgação honesta)
O endurecimento do kernel (desativar user namespaces sem privilégios, elevar o ptrace_scope do Yama) não pode ser verificado de ponta a ponta a partir de dentro de um contêiner. Como esses sysctls não possuem namespace por contêiner, gravações a partir de um contêiner privilegiado (--privileged) afetam não um sandbox de teste, mas sim a própria máquina real que está executando o teste. Portanto, esta verificação confirma apenas que a gravação do sysctl degrada de forma controlada (sem travar) diante de um sistema de arquivos somente leitura; confirmar que o valor realmente é aplicado requer uma máquina real ou VM, que é o ambiente em que o produto foi projetado para funcionar. Essa confirmação foi feita uma única vez, em 2026-09-25, em uma VM Ubuntu 24.04 (consulte a linha PENT-S8).
Reproduza você mesmo
Todos os resultados acima podem ser reproduzidos 100% em sua própria máquina, usando apenas o pacote de distribuição oficial, por meio do conjunto de testes Docker publicado no repositório de suporte oficial (roamswitch-support) — não é necessário acesso ao código-fonte nem confiar em nós.
# Obtenha e reproduza o conjunto de verificação (instala automaticamente o roamswitch-server a partir do repositório APT oficial)
git clone https://github.com/lafine1211/roamswitch-support.git
cd roamswitch-support/test/docker/server
./run.sh
Cria três contêineres descartáveis (Target, Attacker e um decoy de C2) na rede bridge padrão do Docker e verifica automaticamente os 18 itens, imprimindo um relatório. O resultado completo da execução na v1.3.2 está publicado em RESULTS-PENTEST-SERVER-2026-09-07.ja.md (incluindo, para fins de transparência, os problemas do próprio arcabouço de teste encontrados e corrigidos durante sua construção). O registro da nova execução de 2026-09-25 está em RESULTS-PENTEST-2026-09-25.ja.md.
§7Operações, implantação e ciclo de vida
7.1 Assistente de configuração e ferramentas CUI sem cabeça
Gerenciamento remoto completo via CLI:
roamswitch server status: gera o relatório de diagnóstico de 34 itens (compatível com 10 idiomas, de acordo com a configuração do usuário que o executa ou com a localidade do sistema operacional).roamswitch server setup: Assistente de terminal interativo para portas e notificações.roamswitch server config show / set <key> <val>: Automação programável para Ansible/Terraform.roamswitch server test-notify [all|telegram|line|webhook]: Sondagem de notificação ponta a ponta.roamswitch server config set language <ja|en|zh-Hans|zh-Hant|ko|de|fr|es|it|pt|system>: o idioma do relatório de diagnóstico periódico do daemon (a cada hora) e das notificações push (Telegram / LINE / webhook, incluindo a mensagem de teste), um idioma por host.systemsegue a localidade do sistema operacional, e uma localidade não identificável viraja. O idioma de exibição deroamswitch server statusnão segue esta configuração, e sim a configuração do usuário que o executa ou a localidade do sistema operacional.roamswitch server bans [--json]/sudo roamswitch server unban <IP|/64 IPv6|--all>: estado da guarda contra força bruta SSH, e listagem e levantamento dos seus bloqueios. A ferramenta MCPget_ssh_guard_incidentsé só de leitura e não pode levantar um bloqueio.
TUI do Server (roamswitch server tui)
Uma interface de terminal que permite operar toda a edição Server por SSH, em 80x24 e apenas com o teclado (roamswitch server tui ou roamswitch-server-tui). Tem 11 telas: painel, proteção, incidentes, notificações e encaminhamento, Sensor, configuração, serviço, ferramentas, auditoria de logs, informações e ajuda, e Fleet. O editor de configuração é gerado a partir das definições de chaves (o esquema) de server.conf e guard.yaml: valida tipo, faixa e valores enumerados, indica se é preciso reiniciar, mostra um diff antes de salvar e salva com backup com carimbo de data e hora e gravação atômica (valores secretos, como tokens, são mascarados e digitados sem eco). Operações de grande impacto, como restaurar um isolamento, fazer ACK, atualizar a linha de base do FIM ou parar o serviço, mostram uma tela de confirmação que informa o efeito, e as de maior impacto exigem digitar yes (confirmação digitada). Sem root, é somente leitura e indica o comando sudo roamswitch ... necessário. Não há recarga de configuração; é preciso reiniciar o serviço para que as mudanças tenham efeito. A tela suporta 10 idiomas.
7.2 Embalagem
Fornecido por pacotes .deb para Debian / Ubuntu e por pacotes .rpm para RHEL / Fedora e para openSUSE.
§8Conclusão
O RoamSwitch Server Edition oferece à infraestrutura Linux de nuvem e corporativa, em um único pacote integrado, “Zero Telemetry (a única comunicação externa por padrão é uma receção de dados assinados, sem envio, que pode ser desativada)”, “proteção de perímetro robusta por negação de entrada por padrão”, “detecção imediata de adulteração de caminhos críticos” e “bloqueio preventivo da escalada de privilégios do kernel”.
Uma suíte de segurança para servidores Linux que combina deteção em camadas com contenção autónoma (Air-Gap) nas principais fases visadas pelos atacantes: reconhecimento inicial, intrusão, escalada de privilégios e persistência.