
maltrail v3.2
Sistema de detecção de tráfego malicioso em tempo real que utiliza listas negras públicas, rastros estáticos de malware e análise heurística para identificar ameaças no tráfego DNS, HTTP e IP.

Maltrail
Maltrail é um sistema de detecção de tráfego de rede que identifica comunicação com infraestrutura maliciosa conhecida e reporta anomalias de tráfego selecionadas. Ele compara domínios, URLs, endereços IP, pares IP:port e valores de User-Agent observados na rede com um conjunto de indicadores chamados trails.
Uma detecção é registrada como um único evento contendo a origem, o destino, o protocolo, o trail correspondente, a classificação e a origem do trail:```text "2026-08-07 09:14:22.117034" gw 10.13.13.2 57809 1.1.1.1 53 UDP DNS malware.bakewithdavid.com "asyncrat (malware)" (static)
O Maltrail foi projetado para monitoramento de rede baseado em indicadores. Suas detecções heurísticas complementam
a correspondência de trails, mas não substituem a telemetria de endpoint ou um sistema de prevenção de intrusão
de uso geral.
## Recursos
- Uma construção completa de trails combinando mais de 3.000 arquivos estáticos incluídos, 42 integrações de feeds públicos,
e trails opcionais fornecidos pelo operador.
- Um sensor Rust multithread usando libpcap, com workers de captura Linux `PACKET_FANOUT` opcionais.
- Um servidor Python fornecendo a interface de relatórios, ingestão de eventos e API HTTP.
- Trails personalizados em texto simples e whitelists que podem ser revisados e versionados.
- Heurísticas para varredura, esgotamento de DNS, consultas do tipo DGA, downloads suspeitos, sondagens de proxy,
valores de User-Agent suspeitos e atividades de rede relacionadas.
- Registro de eventos local, registro remoto do Maltrail, CEF sobre syslog e saída Logstash JSON.
- Validação de implantação com `maltrail-sensor -T` e métricas Prometheus opcionais.
## Conteúdo
- [Arquitetura](#architecture)
- [Interface de relatórios](#reporting-interface)
- [Desempenho](#performance)
- [Instalação](#installation)
- [Instalador](#installer)
- [Compilação a partir do código-fonte](#building-from-source)
- [Systemd](#systemd)
- [Docker](#docker)
- [Configuração](#configuration)
- [Trails](#trails)
- [Eventos e API](#events-and-api)
- [Operações](#operations)
- [Monitoramento](#monitoring)
- [Retenção de eventos](#event-retention)
- [Documentação](#documentation)
- [Contribuindo](#contributing)
- [Projeto](#project)
- [Licença](#license)
- [Mantenedores](#maintainers)
- [Patrocinadores](#sponsors)
- [Apresentações e publicações](#presentations-and-publications)
- [Blacklist derivada](#derived-blacklist)
- [Integrações de terceiros](#third-party-integrations)
- [Agradecimentos](#acknowledgements)
## Arquitetura
O Maltrail consiste em dois processos independentes que podem ser executados no mesmo host ou em hosts separados:```text
┌──────────┐ events (UDP or file) ┌──────────┐
│ sensor │ ───────────────────────► │ server │ ◄── browser
└──────────┘ └──────────┘
Rust Python
libpcap + PACKET_FANOUT reporting UI + API
trail matching + heuristics
O sensor captura tráfego, realiza correspondência de trilhas e análise heurística, e produz eventos.
Ele pode gravar eventos localmente (LOG_DIR), enviá-los a um servidor Maltrail remoto (LOG_SERVER), ou
ambos. Também pode emitir CEF via syslog (SYSLOG_SERVER) e JSON para o Logstash
(LOGSTASH_SERVER).
O servidor recebe e armazena eventos remotos, serve logs de eventos disponíveis localmente e fornece a interface web e a API.
Interface de relatórios
O Maltrail inclui uma interface de relatórios baseada em navegador para explorar o tráfego detectado, com atualizações ao vivo, busca por campo, caça retroativa, visualizações geográficas, triagem, visualizações salvas e exportação.

A interface é servida por server.py em HTTP_ADDRESS:HTTP_PORT. É JavaScript puro com uma
única dependência de runtime de terceiros (PapaParse, para análise de CSV) e sem etapa de build. Um dia é
visualizado por vez, selecionado com um seletor de data que também funciona como uma grade de densidade de eventos sobre os
logs diários disponíveis. Os eventos são transmitidos de /events e agregados no navegador em
ameaças — uma linha por (source, trail) distinto — exibidas em uma grade classificável com um painel de detalhes.
| Recurso | Notas |
|---|---|
| Modo ao vivo | Eventos anexados são enviados via Server-Sent Events (/live) e mesclados na visualização atual. Recorre à sondagem de intervalos de bytes do log diário quando o SSE não está disponível, ou para sessões que o stream não consegue atender. Novas ameaças de alta severidade podem acionar uma notificação de desktop e um alerta sonoro; ambos podem ser silenciados |
| Busca | Tokens com escopo de campo (src: dst: port: proto: type: trail: info: family: tag: uid: sev: dir: status:; family:interlock inclui interlock-1/-2, os fragmentos em que um dump de feed chega dividido) combinados com espaço como AND, - para excluir, curingas *, CIDR (src:10.0.0.0/8), e intervalos numéricos e comparações (port:>1024, count:>=100). Filtros ativos aparecem como chips removíveis |
| Caça retroativa | Pesquisa em todos os logs diários retidos por um indicador (/hunt), não apenas no dia em visualização. Limitada por um limite de dias, um orçamento de tempo real e um limite de amostras; um dia que o orçamento interrompeu é relatado separadamente dos dias concluídos em vez de contado como um total finalizado. Um índice sidecar por dia (LOG_DIR/index/, USE_EVENT_INDEX) permite que a varredura pule todas as linhas não correspondentes e torna /counts exato |
| Mapa mundial | Densidade de eventos por país para o dia selecionado (/geo), posicionando o endpoint externo de cada evento. Eventos que não podem ser atribuídos a um endereço externo são relatados como não mapeados em vez de adivinhados. Defina HOME_LAT / HOME_LON para desenhar arcos de origem |
| Triagem | Status por ameaça (nova / em investigação / resolvida / falso positivo), notas de texto livre, tags e ocultação. Regras de whitelist e pivôs de OSINT estão disponíveis no menu de contexto da linha |
| Visualizações salvas | Presets de filtro nomeados |
| Exportação | A visualização filtrada atual como CSV, JSON ou indicadores defanged |
| Aparência | Temas escuro e claro, e etapas discretas de tamanho de texto |
O estado de triagem, visualizações salvas, tags e configurações de aparência são armazenados no navegador
(localStorage), não no servidor: são por navegador e por origem, e não são compartilhados
entre analistas.
Sessões restritas com um filtro de rede veem apenas eventos de suas próprias redes, e essa restrição se aplica às contagens, ao mapa e aos endpoints de blacklist, bem como à lista de eventos.
O enriquecimento de país e ASN para endereços individuais é consultado em stat.ripe.net pelo
servidor, que armazena os resultados em cache e os serve à interface a partir de seu próprio endpoint /ripe;
o navegador não se comunica com nada além do Maltrail. Defina DISABLE_RIPE_LOOKUPS para desativar
completamente as consultas de saída. Sem elas — ou em um host sem acesso à internet — as bandeiras vêm
da tabela RIR local e todo o resto na interface funciona offline.
Desempenho
O desempenho depende do processador, da composição do tráfego, do tamanho do conjunto de trilhas, do driver de captura e da interface de rede. Os números abaixo medem o caminho de processamento de pacotes do sensor isoladamente; não são medições de captura ao vivo de ponta a ponta.
Medições representativas em um AMD Ryzen 7 PRO 4750U com heurísticas habilitadas e um conjunto de trilhas de 1,5 milhão de linhas:
| Tráfego | Tempo por pacote |
|---|---|
| ICMP echo, 58 bytes | 101 ns |
| TCP SYN, 70 bytes | 302 ns |
| TLS em massa, 1.473 bytes | 402 ns |
| Consulta DNS com cache quente, 93 bytes | 452 ns |
| Tráfego misto, média de 866 bytes | 552 ns |
| Requisição HTTP, 169 bytes | 602 ns |
| Consulta DNS com nome único, 93 bytes | 1.102 ns |
Execuções de comparação offline usando a mesma captura gerada, configuração e conjunto de trilhas mediram um
custo por pacote em estado estacionário de 14–37× menor do que o sensor Python aposentado nos sistemas testados.
Esses números separam o tempo de processo inteiro do estado estacionário, porque o carregamento de trilhas domina uma
reprodução curta. A detecção em si é verificada separadamente, pelo corpus de 42 casos em
sensor/tests/replay.rs.
Meça no sistema de destino com:```bash cargo bench --manifest-path sensor/Cargo.toml --bench hotpath
Um worker de captura é usado por padrão. Workers adicionais podem aumentar a capacidade de captura, mas o hashing de fluxo do Linux divide o estado por origem entre os workers e, portanto, reduz a sensibilidade de algumas heurísticas de varredura. No teste documentado, 91% dos alertas heurísticos com um único worker permaneceram com dois workers, 86% com quatro e 65% com oito. A correspondência exata de trilhas permaneceu inalterada. Aumente `CAPTURE_FANOUT` apenas quando as métricas de perda de captura mostrarem que é necessário.
A metodologia de benchmark, os resultados de hardware, a saída do profiler, as medições de memória e as verificações de fanout em tempo real estão documentados em [`sensor/docs/REPORT.md`](https://github.com/stamparm/maltrail/blob/master/sensor/docs/REPORT.md).
## Instalação
### Instalador
O instalador é verificado em doze distribuições Linux — Debian, Ubuntu, Fedora, Rocky, AlmaLinux, Arch, openSUSE Leap e Tumbleweed, e Alpine — além de FreeBSD e macOS, em cada versão, com o resultado completo registrado em [`docs/compat`](https://github.com/stamparm/maltrail/blob/master/docs/compat). O Raspberry Pi OS e outros sistemas ARM de 64 bits usam a compilação `aarch64`; o ARM de 32 bits não possui sensor pré-compilado e deve compilá-lo a partir do código-fonte.```bash
curl -fsSL https://raw.githubusercontent.com/stamparm/maltrail/master/install.sh | sudo sh
Ele instala dependências, cria um checkout gerenciado em /opt/maltrail, verifica o checksum
do sensor pré-compilado, cria uma conta maltrail sem privilégios, instala unidades systemd, prepara
os diretórios de log e de estado, e inicia o sensor e o servidor. Reexecutar o instalador atualiza
o checkout gerenciado.
Revise o script antes de executá-lo com privilégios elevados. A partir de um checkout existente, a execução de teste (dry run) mostra os comandos sem alterar o sistema:```bash sh install.sh --dry-run
Opções comuns do instalador:```bash
sh install.sh --role sensor # Install only the sensor
sh install.sh --ref 3.1.2 # Install a release tag instead of master
sh install.sh --no-service # Install without changing systemd
sh install.sh --dry-run # Print commands without applying them
sh install.sh --uninstall # Remove the managed installation; keep logs and state
O dashboard está disponível em http://127.0.0.1:8338 após a instalação. Note que o
HTTP_ADDRESS fornecido é 0.0.0.0, portanto é acessível em todas as interfaces, não apenas no loopback — e
as credenciais padrão são admin / changeme!. Altere USERS e defina HTTP_ADDRESS como
127.0.0.1 (ou coloque o servidor atrás de um proxy reverso com TLS), antes que o host esteja numa
rede não confiável.
A construção inicial do trail pode demorar vários minutos. O sensor não deteta correspondências de trail até que um
conjunto de trails válido esteja disponível. A unit systemd executa a validação -T do sensor antes do arranque para
que privilégios em falta, um diretório de logs sem permissão de escrita ou um conjunto de trails inválido façam o arranque
falhar de forma visível.
O harness de teste do instalador cobre doze distribuições, e "instalou" não é a asserção: em
cada uma, o servidor é iniciado e é-lhe pedido /ping, é pedido ao sensor que se valide com
-T, as units são verificadas quanto a caminhos que resolvem, o instalador é executado novamente para provar que uma atualização
mantém a configuração do operador, e --uninstall é executado. Cada resultado é registado por plataforma em
docs/compat, e a página lá é gerada a partir dessas linhas em vez de escrita
à mão.
Alpine e outros sistemas musl recebem uma build do sensor -musl. Costumavam ser informados de que o binário
pré-compilado era ligado a glibc e que deviam compilar o seu próprio; o sensor compila e corre nativamente em musl, portanto isso era
um artefacto em falta em vez de um limite da plataforma.
Compilar a partir do código-fonte
O sensor requer Rust 1.74 ou mais recente, cabeçalhos de desenvolvimento do libpcap e as ferramentas de capacidades do sistema. O servidor e o atualizador de trails requerem Python 3.6 ou mais recente.
Instale os pacotes da distribuição:```bash
Debian / Ubuntu / Raspberry Pi OS
sudo apt-get install cargo libpcap-dev libcap2-bin python3
RHEL / Fedora
sudo dnf install cargo libpcap-devel libcap python3
openSUSE / SLES
sudo zypper install cargo rust libpcap-devel libcap-progs python311
Em seguida, compile e valide o sensor:```bash
git clone --depth 1 https://github.com/stamparm/maltrail.git
cd maltrail
cargo build --release --manifest-path sensor/Cargo.toml
sudo setcap cap_net_raw,cap_net_admin=eip \
sensor/target/release/maltrail-sensor
sudo install -d -o "$USER" -g "$(id -gn)" -m 750 /var/log/maltrail
sensor/target/release/maltrail-sensor -T
sensor/target/release/maltrail-sensor
Inicie o servidor em outro terminal ou em outro host:```bash python3 server.py
Binários pré-compilados do sensor estão anexados às versões atuais com checksums SHA-256: Linux `x86_64`
e `aarch64` para glibc e musl, macOS em Apple silicon e Intel, FreeBSD `amd64`, e
Windows `x86_64`.
As compilações glibc ligam a libpcap estaticamente e têm como alvo glibc 2.28, pelo que a biblioteca C é a única coisa
de que precisam — nada para instalar, tanto em RHEL 8+, Debian 10+, Ubuntu 18.04+ como em Leap 15.x. As compilações musl
são totalmente estáticas, pelo que o Alpine não precisa de nada. A compilação Windows é de 64 bits e requer Windows 10 ou posterior mais
[Npcap](https://npcap.com) instalado antes de arrancar — `wpcap.dll` é uma dependência de tempo de carregamento,
pelo que sem ela o loader recusa o executável em vez de falhar na captura. O arquivo diz isso
também.
Binários de **3.1.1 e anteriores** não o faziam: ligavam a libpcap dinamicamente, e pediam-na pelo
nome que o seu host de compilação AlmaLinux usa. Debian e Ubuntu fornecem a biblioteca idêntica sob o
nome mais antigo `libpcap.so.0.8`, pelo que esses binários param antes de arrancar —```
./maltrail-sensor: error while loading shared libraries: libpcap.so.1: cannot open shared object file
— em uma máquina que tenha libpcap instalado. O install.sh cria o link do nome ausente para você. Manualmente:```bash
adjust the directory for your architecture: aarch64-linux-gnu, or /usr/lib64 on RPM distributions
sudo ln -sf /usr/lib/x86_64-linux-gnu/libpcap.so.0.8 /usr/lib/x86_64-linux-gnu/libpcap.so.1 sudo ldconfig
### Systemd
As unidades fornecidas em `packaging/systemd/` executam ambos os processos como o
usuário sem privilégios `maltrail`. O Systemd cria `/var/log/maltrail` e `/var/lib/maltrail`, restringe
o acesso ao sistema de arquivos e concede ao sensor `CAP_NET_RAW` e `CAP_NET_ADMIN`.
O instalador configura essas unidades automaticamente. Para uma instalação a partir do código-fonte existente, siga
o procedimento manual de serviço em [`sensor/docs/INSTALL.md`](https://github.com/stamparm/maltrail/blob/master/sensor/docs/INSTALL.md).
Verifique o estado do serviço e os logs com:```bash
systemctl status maltrail-sensor maltrail-server
journalctl -u maltrail-sensor -f
Docker
Inicie a implantação do Compose fornecida com:```bash docker compose -f docker/docker-compose.yml up -d
A configuração do contêiner, o armazenamento, os privilégios e as verificações de integridade estão documentados em
[`docker/README.md`](https://github.com/stamparm/maltrail/blob/master/docker/README.md).
## Configuração
O Maltrail lê o `maltrail.conf`, que contém configurações separadas de `[Sensor]` e `[Server]`. O
instalador coloca a configuração gerenciada em `/etc/maltrail.conf`.
As opções de sensor usadas com frequência incluem:
| Opção | Finalidade |
| --- | --- |
| `MONITOR_INTERFACE` | Interface ou interfaces de captura; `any` seleciona todas as interfaces suportadas |
| `CAPTURE_FILTER` | Filtro de captura BPF |
| `CAPTURE_FANOUT` | Número de sockets de captura do Linux; o padrão é um |
| `CAPTURE_WORKERS` | Workers de captura, um socket cada; o padrão é `CAPTURE_FANOUT`, portanto um, a menos que um deles seja definido |
| `LOG_DIR` | Diretório local de log de eventos |
| `TRAILS_FILE` | Banco de dados de trails gerado |
| `LOG_SERVER` | Servidor remoto de eventos do Maltrail |
| `SYSLOG_SERVER` | Destino ou destinos de syslog CEF |
| `LOGSTASH_SERVER` | Destino ou destinos de JSON do Logstash |
| `STATS_ADDRESS` | Listener de métricas do Prometheus; desabilitado a menos que configurado |
| `UPDATE_PERIOD` | Intervalo de atualização dos trails |
| `STATIC_TRAILS_URL` | De onde o conjunto estático de trails montado é obtido; fixe-o em uma versão datada para controlar quando novo conteúdo chega |
| `USER_WHITELIST` | Indicadores gerenciados pelo operador que não devem gerar alertas |
| `CUSTOM_TRAILS_DIR` | Diretório de trails gerenciado pelo operador |
| `STATIC_TRAILS_DIR` | Checkout opcional do repositório de trails; usado apenas para mostrar a citação da fonte de um trail na UI |
`PROCESS_COUNT` aplica-se ao sensor Python descontinuado e ao throttle legado de log de eventos; ele
**não** define a contagem de workers do sensor Rust. Configure os workers de captura com `CAPTURE_FANOUT` ou
`CAPTURE_WORKERS`.
Execute a verificação de implantação após alterar a configuração:```bash
sensor/target/release/maltrail-sensor -T
A verificação valida a configuração, os trails, as entradas da whitelist, o filtro de captura, os privilégios, o armazenamento de logs, o suporte a atualizações e as configurações do worker. Uma verificação bem-sucedida inclui contagens positivas de trails e whitelist, em vez de apenas confirmar que os arquivos existem.
Trails
Um trail é um indicador — um domínio, URL, endereço IP, par IP:port, User-Agent, impressão digital JA3/JA4 ou hash de certificado — juntamente com o que significa e de onde veio. O atualizador combina quatro fontes em TRAILS_FILE, nesta ordem:
| fonte | de onde vem |
|---|---|
| Feeds | feeds/*.py, obtidos diretamente pela sua implantação de cada publicador |
| Custom | CUSTOM_TRAILS_DIR e CUSTOM_TRAILS_URL, seus próprios indicadores |
| Static | o conjunto montado a partir de stamparm/trails, obtido de STATIC_TRAILS_URL; licenciado separadamente |
| Engine lists | data/mass_scanner*.txt, incluídos aqui porque mudam raramente |
Os trails estáticos residem em seu próprio repositório. O conteúdo de detecção muda dezenas de vezes por dia; o motor não, e mantê-los juntos significava que atualizar a detecção exigia baixar código e tornava o histórico deste repositório inutilizável. STATIC_TRAILS_URL aponta para o conjunto publicado mais recente:```text
STATIC_TRAILS_URL https://github.com/stamparm/trails/releases/latest/download/trails.csv.gz
Aponte-o para uma versão específica `content-YYYYMMDD-HHMM` em vez disso, para fixar uma versão, de modo que uma publicação defeituosa não se torne imediatamente global. O conjunto é armazenado em cache ao lado de `TRAILS_FILE`, o que é o que faz funcionar uma reconstrução offline ou em rede isolada; o `sha256` publicado é verificado antes do download, pelo que uma implantação que atualiza com mais frequência do que o conteúdo muda transfere 65 bytes em vez de 11 MB, e um payload que não corresponde ao seu digest é recusado em favor da cache.
`update_trails()` publica um novo `TRAILS_FILE` atomicamente e apenas após uma compilação bem-sucedida. Os feeds que não retornam nada são reportados por nome, para que uma implantação não dependa silenciosamente de uma fonte que se retirou discretamente.
Adicione os seus próprios indicadores em `CUSTOM_TRAILS_DIR`, e qualquer coisa que nunca deva gerar um evento em `USER_WHITELIST`. Mantenha ambos fora do diretório de instalação para que uma atualização não os possa substituir.
As contribuições de trails estáticos vão para [stamparm/trails](https://github.com/stamparm/trails); os novos feeds vão aqui. De qualquer forma, um indicador precisa de uma classificação e de uma fonte que alguém possa verificar — consulte [Contributing](#contributing).
## Events and API
O Maltrail registra um evento separado por espaços em branco por detecção, usando aspas CSV quando um valor contém espaços:```text
"<time>" <sensor> <src_ip> <src_port> <dst_ip> <dst_port> <proto> <type> <trail> "<info>" <reference>
O campo type identifica o que correspondeu, incluindo DNS, IP, IPORT, URL, PATH, HTTP,
UA, PORT, CERT, JA3 e JA4. O campo info contém a classificação do rasto, e
reference identifica a lista estática, feed, fonte personalizada ou heurística que o produziu. Os
tipos JA3/JA4 disparam em impressões digitais de cliente TLS: a stack TLS de um implante sobrevive a cada
rotação de endereço e domínio, pelo que o seu hash de hello continua a corresponder depois de tudo o resto ter sido queimado
(publicado pelo feed SSLBL JA3 da abuse.ch).
Consulta de indicadores
Use /check para consultar um domínio, endereço IP ou URL:```bash
curl 'http://127.0.0.1:8338/check?q=www.sub.evil.example'
## 🎯 Objetivos de Aprendizagem
Ao final deste módulo, você será capaz de:
- ✅ Compreender a arquitetura do sistema de plugins do Artemis
- ✅ Criar plugins personalizados para necessidades específicas de segurança
- ✅ Implementar verificações de segurança personalizadas
- ✅ Integrar APIs e serviços externos
- ✅ Testar e depurar plugins de forma eficaz
- ✅ Empacotar e distribuir plugins
## 📋 Pré-requisitos
Antes de começar, certifique-se de ter:
- **Java 17+** instalado
- **Maven 3.8+** para gerenciamento de dependências
- **Conhecimento básico de Java** (interfaces, anotações, genéricos)
- **Familiaridade com conceitos de segurança** (XSS, SQLi, SSRF, etc.)
- **IDE** (IntelliJ IDEA, Eclipse ou VS Code)
- **Artemis** instalado e funcionando
## 🏗️ Arquitetura de Plugins
### Visão Geral do Sistema de Plugins
O Artemis utiliza um sistema de plugins baseado em **Java SPI (Service Provider Interface)** que permite estender funcionalidades sem modificar o núcleo da aplicação.
┌─────────────────────────────────────────────────────────┐ │ Artemis Core │ │ ┌───────────────────────────────────────────────────┐ │ │ │ Plugin Manager │ │ │ │ - Descoberta de Plugins │ │ │ │ - Ciclo de Vida │ │ │ │ - Isolamento │ │ │ └───────────────────────────────────────────────────┘ │ │ │ │ │ ┌────────────────┼────────────────┐ │ │ ▼ ▼ ▼ │ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ │ │ │ Plugin A │ │ Plugin B │ │ Plugin C │ │ │ │ (Scanner) │ │ (Reporter)│ │ (Notifier)│ │ │ └────────────┘ └────────────┘ └────────────┘ │ └─────────────────────────────────────────────────────────┘
### Tipos de Plugins
| Tipo | Descrição | Caso de Uso |
|------|-----------|-------------|
| **Scanner** | Analisa alvos em busca de vulnerabilidades | Detecção de XSS, SQLi, SSRF |
| **Reporter** | Gera relatórios em diferentes formatos | PDF, JSON, HTML, SARIF |
| **Notifier** | Envia notificações sobre descobertas | Slack, Discord, Email |
| **Analyzer** | Analisa e correlaciona resultados | Detecção de falsos positivos |
| **Integration** | Integra com ferramentas externas | Jira, GitHub, DefectDojo |
### Ciclo de Vida do Plugin
```java
public interface ArtemisPlugin {
// Chamado quando o plugin é carregado
void initialize(PluginContext context) throws PluginException;
// Chamado quando o plugin é iniciado
void start() throws PluginException;
// Chamado quando o plugin é parado
void stop() throws PluginException;
// Chamado quando o plugin é descarregado
void destroy() throws PluginException;
// Retorna metadados do plugin
PluginMetadata getMetadata();
}
🚀 Criando Seu Primeiro Plugin
Passo 1: Configuração do Projeto
Crie um novo projeto Maven com a seguinte estrutura:
my-artemis-plugin/
├── pom.xml
├── src/
│ └── main/
│ ├── java/
│ │ └── com/
│ │ └── example/
│ │ └── plugin/
│ │ ├── MyScannerPlugin.java
│ │ └── MyPluginMetadata.java
│ └── resources/
│ └── META-INF/
│ └── services/
│ └── com.example.artemis.plugin.ArtemisPlugin
Passo 2: Configuração do pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>my-artemis-plugin</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<artemis.version>1.0.0</artemis.version>
</properties>
<dependencies>
<!-- Artemis Plugin API -->
<dependency>
<groupId>com.artemis</groupId>
<artifactId>artemis-plugin-api</artifactId>
<version>${artemis.version}</version>
<scope>provided</scope>
</dependency>
<!-- Dependências adicionais -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.9</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Passo 3: Implementando o Plugin
package com.example.plugin;
import com.artemis.plugin.ArtemisPlugin;
import com.artemis.plugin.PluginContext;
import com.artemis.plugin.PluginException;
import com.artemis.plugin.PluginMetadata;
import com.artemis.scanner.ScannerPlugin;
import com.artemis.scanner.ScanResult;
import com.artemis.scanner.ScanTarget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.concurrent.CompletableFuture;
/**
* Plugin de scanner personalizado para Artemis.
*
* Este plugin demonstra como criar um scanner personalizado
* que pode ser integrado ao pipeline de segurança do Artemis.
*/
public class MyScannerPlugin implements ArtemisPlugin, ScannerPlugin {
private static final Logger logger = LoggerFactory.getLogger(MyScannerPlugin.class);
private PluginContext context;
private boolean running = false;
@Override
public void initialize(PluginContext context) throws PluginException {
logger.info("Inicializando MyScannerPlugin...");
this.context = context;
// Validar configuração
if (context.getConfiguration() == null) {
throw new PluginException("Configuração do plugin não encontrada");
}
logger.info("MyScannerPlugin inicializado com sucesso");
}
@Override
public void start() throws PluginException {
logger.info("Iniciando MyScannerPlugin...");
this.running = true;
logger.info("MyScannerPlugin iniciado");
}
@Override
public void stop() throws PluginException {
logger.info("Parando MyScannerPlugin...");
this.running = false;
logger.info("MyScannerPlugin parado");
}
@Override
public void destroy() throws PluginException {
logger.info("Destruindo MyScannerPlugin...");
this.context = null;
logger.info("MyScannerPlugin destruído");
}
@Override
public PluginMetadata getMetadata() {
return new MyPluginMetadata();
}
@Override
public CompletableFuture<List<ScanResult>> scan(ScanTarget target) {
return CompletableFuture.supplyAsync(() -> {
logger.info("Escaneando alvo: {}", target.getUrl());
List<ScanResult> results = new java.util.ArrayList<>();
try {
// Implementar lógica de scan personalizada aqui
// Este é um exemplo simplificado
// Verificar headers de segurança
checkSecurityHeaders(target, results);
// Verificar configurações de CORS
checkCorsConfiguration(target, results);
// Verificar exposição de informações
checkInformationDisclosure(target, results);
} catch (Exception e) {
logger.error("Erro durante o scan: {}", e.getMessage(), e);
}
return results;
});
}
private void checkSecurityHeaders(ScanTarget target, List<ScanResult> results) {
// Implementação da verificação de headers
logger.debug("Verificando headers de segurança para: {}", target.getUrl());
// Lógica de verificação aqui
}
private void checkCorsConfiguration(ScanTarget target, List<ScanResult> results) {
// Implementação da verificação de CORS
logger.debug("Verificando configuração CORS para: {}", target.getUrl());
// Lógica de verificação aqui
}
private void checkInformationDisclosure(ScanTarget target, List<ScanResult> results) {
// Implementação da verificação de exposição de informações
logger.debug("Verificando exposição de informações para: {}", target.getUrl());
// Lógica de verificação aqui
}
}
Passo 4: Implementando os Metadados do Plugin
package com.example.plugin;
import com.artemis.plugin.PluginMetadata;
import java.util.List;
import java.util.Map;
/**
* Metadados do MyScannerPlugin.
*/
public class MyPluginMetadata implements PluginMetadata {
@Override
public String getId() {
return "my-scanner-plugin";
}
@Override
public String getName() {
return "My Custom Scanner Plugin";
}
@Override
public String getVersion() {
return "1.0.0";
}
@Override
public String getDescription() {
return "Plugin de scanner personalizado para verificações de segurança";
}
@Override
public String getAuthor() {
return "Seu Nome";
}
@Override
public String getLicense() {
return "MIT";
}
@Override
public List<String> getDependencies() {
return List.of();
}
@Override
public Map<String, Object> getConfigurationSchema() {
return Map.of(
"timeout", Map.of(
"type", "integer",
"default", 30,
"description", "Timeout em segundos para operações de scan"
),
"maxDepth", Map.of(
"type", "integer",
"default", 3,
"description", "Profundidade máxima de crawling"
),
"enabledChecks", Map.of(
"type", "array",
"default", List.of("headers", "cors", "info-disclosure"),
"description", "Verificações habilitadas"
)
);
}
}
Passo 5: Registrando o Plugin
Crie o arquivo src/main/resources/META-INF/services/com.example.artemis.plugin.ArtemisPlugin:
com.example.plugin.MyScannerPlugin
Passo 6: Compilando e Empacotando
# Compilar o plugin
mvn clean package
# O JAR será criado em target/my-artemis-plugin-1.0.0.jar
Passo 7: Instalando o Plugin
# Copiar o plugin para o diretório de plugins do Artemis
cp target/my-artemis-plugin-1.0.0.jar /path/to/artemis/plugins/
# Ou usar o comando de instalação do Artemis
artemis plugin install target/my-artemis-plugin-1.0.0.jar
# Verificar se o plugin foi carregado
artemis plugin list
🔧 Tópicos Avançados
Configuração do Plugin
public class ConfigurablePlugin implements ArtemisPlugin {
private PluginConfiguration config;
@Override
public void initialize(PluginContext context) throws PluginException {
this.config = context.getConfiguration();
// Acessar configurações
int timeout = config.getInt("timeout", 30);
String apiKey = config.getString("apiKey", "");
List<String> targets = config.getStringList("targets");
// Validar configurações obrigatórias
if (apiKey.isEmpty()) {
throw new PluginException("apiKey é obrigatória");
}
}
}
Tratamento de Eventos
public class EventAwarePlugin implements ArtemisPlugin, EventListener {
@Override
public void onEvent(PluginEvent event) {
switch (event.getType()) {
case SCAN_STARTED:
logger.info("Scan iniciado: {}", event.getData());
break;
case SCAN_COMPLETED:
logger.info("Scan concluído: {}", event.getData());
break;
case VULNERABILITY_FOUND:
handleVulnerability(event.getData());
break;
default:
logger.debug("Evento não tratado: {}", event.getType());
}
}
private void handleVulnerability(Map<String, Object> data) {
// Processar vulnerabilidade encontrada
}
}
Integração com APIs Externas
public class ApiIntegrationPlugin implements ArtemisPlugin {
private final HttpClient httpClient;
public ApiIntegrationPlugin() {
this.httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.build();
}
public CompletableFuture<String> sendToExternalApi(ScanResult result) {
return CompletableFuture.supplyAsync(() -> {
try {
String json = objectMapper.writeValueAsString(result);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/vulnerabilities"))
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + apiKey)
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
HttpResponse<String> response = httpClient.send(
request,
HttpResponse.BodyHandlers.ofString()
);
return response.body();
} catch (Exception e) {
throw new CompletionException(e);
}
});
}
}
🧪 Testando Plugins
Testes Unitários
package com.example.plugin;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
class MyScannerPluginTest {
private MyScannerPlugin plugin;
@Mock
private PluginContext mockContext;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
plugin = new MyScannerPlugin();
}
@Test
void testInitialize() throws PluginException {
when(mockContext.getConfiguration()).thenReturn(mock(PluginConfiguration.class));
assertDoesNotThrow(() -> plugin.initialize(mockContext));
}
@Test
void testInitializeWithoutConfiguration() {
when(mockContext.getConfiguration()).thenReturn(null);
assertThrows(PluginException.class, () -> plugin.initialize(mockContext));
}
@Test
void testMetadata() {
PluginMetadata metadata = plugin.getMetadata();
assertNotNull(metadata);
assertEquals("my-scanner-plugin", metadata.getId());
assertEquals("1.0.0", metadata.getVersion());
}
}
Testes de Integração
class MyScannerPluginIntegrationTest {
private ArtemisTestServer testServer;
private MyScannerPlugin plugin;
@BeforeEach
void setUp() throws Exception {
testServer = new ArtemisTestServer();
testServer.start();
plugin = new MyScannerPlugin();
plugin.initialize(createTestContext());
plugin.start();
}
@AfterEach
void tearDown() throws Exception {
plugin.stop();
plugin.destroy();
testServer.stop();
}
@Test
void testScanDetectsMissingHeaders() {
ScanTarget target = ScanTarget.builder()
.url(testServer.getUrl("/no-security-headers"))
.build();
List<ScanResult> results = plugin.scan(target).join();
assertFalse(results.isEmpty());
assertTrue(results.stream()
.anyMatch(r -> r.getType().equals("MISSING_SECURITY_HEADER")));
}
}
📦 Empacotamento e Distribuição
Estrutura do Pacote
my-artemis-plugin-1.0.0.jar
├── META-INF/
│ ├── MANIFEST.MF
│ └── services/
│ └── com.example.artemis.plugin.ArtemisPlugin
├── com/
│ └── example/
│ └── plugin/
│ ├── MyScannerPlugin.class
│ └── MyPluginMetadata.class
└── plugin.properties
Arquivo plugin.properties
plugin.id=my-scanner-plugin
plugin.name=My Custom Scanner Plugin
plugin.version=1.0.0
plugin.author=Seu Nome
plugin.license=MIT
plugin.description=Plugin de scanner personalizado para verificações de segurança
plugin.mainClass=com.example.plugin.MyScannerPlugin
plugin.apiVersion=1.0
Publicando no Repositório de Plugins
# Empacotar o plugin
mvn clean package
# Assinar o plugin (opcional)
gpg --detach-sign target/my-artemis-plugin-1.0.0.jar
# Publicar no repositório
artemis plugin publish \
--file target/my-artemis-plugin-1.0.0.jar \
--repository https://plugins.artemis.example.com
🐛 Solução de Problemas
Problemas Comuns
| Problema | Causa | Solução |
|---|---|---|
ClassNotFoundException | Dependência ausente | Verificar pom.xml e empacotamento |
PluginException: Configuration not found | Configuração ausente | Criar arquivo de configuração |
NoSuchMethodError | Conflito de versões | Verificar versões das dependências |
| Plugin não carrega | Arquivo de serviço ausente | Verificar META-INF/services/ |
OutOfMemoryError | Vazamento de memória | Revisar recursos e usar try-with-resources |
Depuração
# Habilitar logs de depuração
artemis --log-level DEBUG plugin load my-plugin.jar
# Verificar dependências do plugin
artemis plugin inspect my-plugin.jar
# Validar estrutura do plugin
artemis plugin validate my-plugin.jar
Logging
public class MyPlugin implements ArtemisPlugin {
private static final Logger logger = LoggerFactory.getLogger(MyPlugin.class);
@Override
public void initialize(PluginContext context) throws PluginException {
logger.debug("Configuração: {}", context.getConfiguration());
logger.info("Plugin inicializado");
logger.warn("Recurso não disponível, usando fallback");
logger.error("Falha ao conectar", exception);
}
}
📚 Melhores Práticas
1. Tratamento de Erros
// ❌ Ruim
public void process() {
try {
doSomething();
} catch (Exception e) {
// Ignorar silenciosamente
}
}
// ✅ Bom
public void process() throws PluginException {
try {
doSomething();
} catch (SpecificException e) {
logger.error("Falha ao processar: {}", e.getMessage(), e);
throw new PluginException("Falha no processamento", e);
}
}
2. Gerenciamento de Recursos
// ❌ Ruim
public String readFile(String path) {
BufferedReader reader = new BufferedReader(new FileReader(path));
return reader.readLine(); // Vazamento de recurso
}
// ✅ Bom
public String readFile(String path) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
return reader.readLine();
}
}
3. Concorrência
// ❌ Ruim
public class MyPlugin {
private List<ScanResult> results = new ArrayList<>();
public void addResult(ScanResult result) {
results.add(result); // Não é thread-safe
}
}
// ✅ Bom
public class MyPlugin {
private final List<ScanResult> results =
Collections.synchronizedList(new ArrayList<>());
public void addResult(ScanResult result) {
synchronized (results) {
results.add(result);
}
}
}
4. Configuração
// ❌ Ruim
public class MyPlugin {
private static final String API_KEY = "hardcoded-key"; // Nunca faça isso
}
// ✅ Bom
public class MyPlugin {
private String apiKey;
@Override
public void initialize(PluginContext context) throws PluginException {
this.apiKey = context.getConfiguration().getString("apiKey");
if (apiKey == null || apiKey.isEmpty()) {
throw new PluginException("apiKey é obrigatória");
}
}
}
📖 Recursos Adicionais
- Documentação da API de Plugins do Artemis
- Repositório de Plugins da Comunidade
- Exemplos de Plugins
- Guia de Contribuição
✅ Resumo
Neste módulo, você aprendeu:
- Arquitetura de Plugins: Como o sistema de plugins do Artemis funciona
- Criação de Plugins: Passo a passo para criar um plugin do zero
- Tipos de Plugins: Scanner, Reporter, Notifier, Analyzer, Integration
- Ciclo de Vida: initialize, start, stop, destroy
- Configuração: Como usar e validar configurações
- Testes: Testes unitários e de integração
- Empacotamento: Como empacotar e distribuir plugins
- Melhores Práticas: Tratamento de erros, recursos, concorrência
🎯 Próximos Passos
Agora que você domina o desenvolvimento de plugins, explore:
- Módulo 11: Integração com CI/CD - Automatize seus scans
- Módulo 12: Implantação em Produção - Implante em escala
- Módulo 13: Solução de Problemas - Resolva problemas comuns
Anterior: Módulo 9: Desenvolvimento de Payloads | Próximo: Módulo 11: Integração com CI/CD```json { "query": "www.sub.evil.example", "found": true, "trail": "evil.example", "info": "asyncrat (malware)", "reference": "(static)", "confidence": 100 }
O campo `confidence` (0-100, ou `null` quando indisponível) indica quão fortemente as fontes
sustentam a listagem: 40 para um único feed, +15 por cada feed adicional que concorda
independentemente até 100, e pontuação máxima para as entradas personalizadas e estáticas do
próprio operador. É calculado no momento da atualização do trail a partir da concordância dos feeds
num sidecar `trails.confidence` junto ao `trails.csv`; um servidor que obtém trails de um
`UPDATE_SERVER` não tem proveniência para pontuar e reporta `null`. Use-o para priorizar a triagem
- uma listagem de feed único com 40 merece uma segunda análise antes de ganhar uma regra de
firewall.
Uma consulta de subdomínio pode corresponder ao seu parent listado. As consultas de URL verificam
`host/path` antes de verificar apenas o host. O servidor lê a base de dados de trails mapeada em
memória e observa atualizações de trails sem reiniciar.
Os trails estáticos públicos e de feeds estão disponíveis sem autenticação, consistente com o
endpoint `/trails` usado por sensores remotos. Os trails personalizados requerem uma sessão
autorizada; uma consulta apenas de personalizados não autorizada é reportada como uma falha. Os
dados de eventos permanecem autenticados.
## Operações
### Monitorização
Use `maltrail-sensor -T` como um portão de implantação e configuração. A unidade systemd fornecida
executa-o como `ExecStartPre`.
Para confirmar que a própria deteção funciona — não apenas que os processos arrancam — execute:```bash
python3 server.py --detect-test
Ele reproduz um pcap construído de tráfego malicioso emulado (acertos de trail numa consulta DNS, um IP, um
IP:port, um caminho de URL e um cabeçalho Host, além das heurísticas de SQL-injection, traversal, RCE, XSS, proxy-probe,
sinkhole, Host ausente e port/web/infection-scanning) através do sensor instalado
e verifica que todas as detecções esperadas disparam. Não precisa de root, nem de interface, nem de um conjunto de trails próprio. Uma instalação saudável imprime 20/20 detection(s) fired.
Quando STATS_ADDRESS está configurado, monitorize pelo menos estas métricas Prometheus:
| Métrica | Significado operacional |
|---|---|
maltrail_up == 0 | Nenhum worker de captura está em execução |
maltrail_capture_dropped_total a aumentar | O anel de captura está a descartar pacotes |
maltrail_local_log_errors_total a aumentar | Foram produzidos eventos mas não foi possível escrevê-los localmente |
maltrail_remote_log_errors_total a aumentar | Os eventos não puderam ser entregues a um sink remoto; com DISABLE_LOCAL_LOG_STORAGE são perdidos |
maltrail_trail_generation sem avançar | O conjunto de trails ativo não está a ser atualizado |
maltrail_log_dir_free_bytes | Capacidade restante para armazenamento local de eventos |
maltrail_state_saturations_total a aumentar | Foi atingido um limite de estado de uma heurística |
maltrail_throttle_evictions_total a aumentar | A tabela de event-throttle está no seu limite, pelo que os eventos são agregados mais cedo do que o configurado |
A saturação de estado afeta a heurística correspondente; a correspondência exata de trails permanece ativa.
Envie SIGHUP ou use systemctl reload maltrail-sensor para pedir um recarregamento de trails. Ficheiros de trail
atualizados por outro processo são detetados automaticamente e publicados nos workers sem reiniciar
o sensor.
O armazenamento observável condensado (USE_CONDENSED_STORAGE, meta.sqlite) suporta as vistas de
novidade e retro-hunt do servidor. O índice sidecar do registo de eventos por dia (USE_EVENT_INDEX,
LOG_DIR/index/*.sqlite, aproximadamente o dobro do tamanho do log em disco) é o que torna /counts exato e
/hunt rápido; é mantido incrementalmente a partir dos próprios logs e pode ser reconstruído com
server.py --rebuild-index. A compatibilidade com o sensor retirado está documentada em
sensor/docs/COMPATIBILITY.md.
Retenção de eventos
O Maltrail não roda nem elimina registos de eventos. Os operadores são responsáveis por definir a retenção, o arquivamento e a eliminação de acordo com os requisitos de armazenamento e a política organizacional.
Práticas recomendadas:
- Envie a cópia durável dos eventos para um servidor Maltrail remoto ou SIEM com
LOG_SERVER,SYSLOG_SERVERouLOGSTASH_SERVER. - Alerte sobre
maltrail_log_dir_free_bytescom margem suficiente para a taxa de eventos esperada. - Rode, arquive ou remova os logs diários locais usando ferramentas externas.
- Mantenha os ficheiros necessários à interface de relatórios descomprimidos em
LOG_DIR; arquive os ficheiros comprimidos noutro local.
Quando o sistema de ficheiros de logs está cheio, o sensor não consegue acrescentar eventos. Os registos de eventos podem também conter endereços IP e domínios que são regulados como dados pessoais em algumas jurisdições; a política de retenção deve ter em conta os requisitos aplicáveis.
Tráfego sintético
Para verificar que a deteção e o dashboard continuam a funcionar, sem esperar por tráfego real:```bash python3 server.py --detect-test # assert every detection fires, then exit python3 server.py --detect-test --keep DIR --serve # ...and keep the events, serving them on :8338
`--keep` também reproduz `sensor/tests/corpus/` no mesmo log e imprime quais das formas que o
dashboard renderiza de forma diferente têm um evento por trás delas, para que um ícone, cor ou glifo
ausente seja visível em vez de presumido. Os carimbos de data/hora são deslocados para que o dia mais
recente seja hoje. É necessário um binário do sensor (`cargo build --release --manifest-path sensor/Cargo.toml`).
Os dados da demonstração pública são regenerados a partir de uma execução desse tipo:```bash
python3 sensor/tools/gen_demo_js.py --from DIR/logs # tops up html/js/demo.js
Documentação
| Documento | Conteúdo |
|---|---|
sensor/docs/INSTALL.md | Instalação, privilégios, configuração e resolução de problemas |
sensor/docs/ARCHITECTURE.md | Funcionamento interno do sensor e fluxo de dados |
sensor/docs/COMPATIBILITY.md | Diferenças deliberadas em relação ao sensor Python descontinuado |
sensor/docs/REPORT.md | Medições, perfis e resultados de testes |
sensor/docs/ROADMAP.md | Trabalho aberto no sensor |
SekuriPy Labs | Notas de engenharia, benchmarks e análises |
Contribuição
Adições de trails, manutenção de feeds, relatórios de bugs, documentação e melhorias no sensor são bem-vindas. Submissões de trails devem incluir uma fonte confiável e devem usar a classificação adequada mais restrita.
Execute as verificações relevantes antes de submeter código. A verificação completa do sensor é:```bash bash sensor/tools/check.sh
Ele executa formatação, Clippy com avisos negados e as suítes de teste de debug e release. Execute a suíte do servidor Python com:```bash
bash tests/run.sh python3
A build do Windows pode ser exercitada a partir do Linux, que é onde os seus bugs foram encontrados:```bash sh sensor/tools/check_windows.sh
Ele faz compilação cruzada do sensor com mingw-w64, extrai a biblioteca de espaço de usuário do Npcap do seu instalador
(um arquivo NSIS, portanto nada é instalado) e executa o resultado sob o Wine — toda a suíte de testes,
`-T` contra a configuração fornecida, o corpus pcap comparado byte a byte com o binário
nativo, e o servidor respondendo a `/ping` sob um Python do Windows. A captura ao vivo é a única coisa que
ele não consegue cobrir; isso requer o driver de kernel do Npcap e uma máquina Windows real. Os pré-requisitos são
`gcc-mingw-w64-x86-64`, `wine` e `p7zip-full`.
## Projeto
### Licença
**TL;DR:** O Maltrail é licenciado sob MIT, mas o conjunto de dados Maltrail Trails tem termos separados. A consulta/referência independente de IOC é permitida; o uso sistemático do Trails como fonte de inteligência em um produto ou serviço comercial requer permissão/licenciamento.
O Maltrail é distribuído sob a Licença MIT. Consulte [`LICENSE`](https://github.com/stamparm/maltrail/blob/master/LICENSE).
Esse é o motor. O conjunto de trails estático é um trabalho separado sob termos separados: gratuito para uso
defensivo interno, pesquisa e ensino, mas um produto comercial, serviço, oferta de MSSP ou MDR, ou um
feed redistribuído precisa de uma licença. Um motor MIT não torna o conteúdo livre para venda — consulte
[`LICENSE.md`](https://github.com/stamparm/trails/blob/main/LICENSE.md) em
[stamparm/trails](https://github.com/stamparm/trails) antes de distribuí-lo em algo pelo qual você cobra.
### Mantenedores
- Miroslav Stampar ([@stamparm](https://github.com/stamparm))
- Mikhail Kasimov ([@MikhailKasimov](https://github.com/MikhailKasimov))
### Patrocinadores
- [Sansec](https://sansec.io/) (2024–2025)
- [Sansec](https://sansec.io/) (2020–2021)
### Apresentações e publicações
- 47ª Reunião TF-CSIRT, Praga, 2016
([slides](https://web.archive.org/web/20161109135211/https://www.terena.org/activities/tf-csirt/meeting47/M.Stampar-Maltrail.pdf))
- _Detect attacks on your network with Maltrail_, Linux Magazine, 2022
([artigo](https://www.linux-magazine.com/Issues/2022/258/Maltrail))
- _Best Cyber Threat Intelligence Feeds_, Silent Push, 2022
([análise](https://www.silentpush.com/blog/best-cyber-threat-intelligence-feeds))
- _Research on Network Malicious Traffic Detection System Based on Maltrail_, Nanotechnology
Perceptions, 2024
([artigo](https://nano-ntp.com/index.php/nano/article/view/1915/1497))
### Integrações de terceiros
- [FreeBSD Port](https://www.freshports.org/security/maltrail)
- [OPNsense Gateway Plugin](https://github.com/opnsense/plugins/pull/1257)
- [D4 Project](https://www.d4-project.org/2019/09/25/maltrail-integration.html)
- [BlackArch Linux](https://github.com/BlackArch/blackarch/blob/master/packages/maltrail/PKGBUILD)
- [Validin](https://x.com/ValidinLLC/status/1719666086390517762)
- [Maltrail Add-on for Splunk](https://splunkbase.splunk.com/app/7211)
- [Maltrail decoder and rules for Wazuh](https://github.com/MikhailKasimov/maltrail-wazuh-decoder-and-rules)
- [GScan](https://github.com/grayddq/GScan) (apenas trails)
- [MalwareWorld](https://www.malwareworld.com/) (apenas trails)
- [oisd domain blocklist](https://oisd.nl/?p=inc) (apenas trails)
- [NextDNS](https://github.com/nextdns/metadata/blob/e0c9c7e908f5d10823b517ad230df214a7251b13/security/threat-intelligence-feeds.json) (apenas trails)
- [NoTracking](https://github.com/notracking/hosts-blocklists/blob/master/SOURCES.md) (apenas trails)
- [OWASP Mobile Audit](https://github.com/mpast/mobileAudit#environment-variables) (apenas trails)
- [Mobile Security Framework MobSF](https://github.com/MobSF/Mobile-Security-Framework-MobSF/commit/12b07370674238fa4281fc7989b34decc2e08876) (apenas trails)
- [pfBlockerNG-devel](https://github.com/pfsense/FreeBSD-ports/blob/devel/net/pfSense-pkg-pfBlockerNG-devel/files/usr/local/www/pfblockerng/pfblockerng_feeds.json) (apenas trails)
- [Sansec eComscan](https://sansec.io/kb/about-ecomscan/ecomscan-license) (apenas trails)
- [Palo Alto Networks Cortex XSOAR](https://xsoar.pan.dev/docs/reference/integrations/github-maltrail-feed) (conector de trail)
### Agradecimentos
- Thomas Kristner
- Eduardo Arcusa Les
- James Lay
- Ladislav Baco (@laciKE)
- John Kristoff (@jtkdpu)
- Michael Münz (@mimugmail)
- David Brush
- @Godwottery
- Chris Wild (@briskets)
- Keith Irwin (@ki9us)
- Simon Szustkowski (@simonszu)