Torna agli aggiornamenti
New releaseAug 1, 2026

maltrail v2.2

Sistema di rilevamento del traffico dannoso in tempo reale che utilizza blacklist pubbliche, tracce statiche di malware e analisi euristica per identificare minacce nel traffico DNS, HTTP e IP.

Condividi

Maltrail

License Sensor Server Trails X

Sistema di rilevamento del traffico dannoso. Maltrail osserva la tua rete per contatti con elementi che sono noti per essere dannosi — e ti dice, in una riga, cosa è stato visto e perché è considerato dannoso.

"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)

Nessun linguaggio di regole, nessun rituale di tuning, nessun ML. Una trail è un dominio, URL, indirizzo IP, IP:port o User-Agent noto per appartenere a qualcosa di dannoso, e Maltrail ti dice quando una di esse appare sulla rete.


Perché Maltrail

La maggior parte degli strumenti di rilevamento di rete ti chiedono di descrivere comportamenti. Maltrail pone una domanda più semplice che risponde alla maggior parte degli incidenti reali: questo host sta parlando con qualcosa che sappiamo già essere dannoso?

  • Più di 1,5 milioni di trail, da oltre 3.000 liste statiche curate e 46 feed pubblici, aggiornati quotidianamente e in crescita. Fortemente orientate verso malware — domini C2, dropper, stealer, infrastrutture APT — perché è quello che compare in una compromissione reale.
  • Le trail sono testo semplice. Un indicatore per riga, in un file che puoi leggere, fare grep e su cui inviare una pull request. È per questo che la copertura resta aggiornata, e perché puoi sempre rispondere a "perché è scattato questo?".
  • Abbastanza veloce da smettere di pensarci. Un singolo core gestisce un link 10 GbE con un mix di traffico realistico; vedi Performance.
  • Euristica in aggiunta, non in sostituzione — ognuna nominata nell'evento, mai un punteggio nudo: scansione di porte, UDP e web, esaurimento DNS, query con forma DGA (soglie di entropia e consonanti, NXDOMAIN eccessivo), domini sinkholed, sequestrati e parcheggiati, domini lunghi, download diretti via IP e di malware IoT, user agent sospetti e probe proxy.

Architettura

Due processi indipendenti. Esegui entrambi su una singola macchina o su più macchine.

   ┌──────────┐   events (UDP or file)   ┌──────────┐
   │  sensor  │ ───────────────────────► │  server  │ ◄── browser
   └──────────┘                          └──────────┘
    Rust                                  Python
    libpcap + PACKET_FANOUT               reporting UI + API
    trail matching, heuristics

Un sensore può registrare localmente (LOG_DIR), inviare a un server remoto (LOG_SERVER), o entrambi. Per un SIEM esistente emette anche CEF via syslog (SYSLOG_SERVER) e JSON Logstash (LOGSTASH_SERVER).


Performance

Il sensore è in Rust, un thread per worker di cattura, che condividono un unico store di trail immutabile. Costo per pacchetto, per tipo di traffico:

trafficoper pacchetto
ICMP echo (58 B)101 ns
TCP SYN (70 B)302 ns
bulk TLS (1,473 B)402 ns
query DNS, cache calda (93 B)452 ns
traffico misto (media 866 B)552 ns
richiesta HTTP (169 B)602 ns
query DNS, ogni nome univoco (flood DGA)1,102 ns

I worker non condividono nulla di mutabile, quindi quel costo è ciò che ogni core aggiuntivo ti offre. Riproducendo il mix da 866 byte:

workerspacchetti/sGbit/svs 1 worker
11,687,99111.691.00×
23,209,62722.241.90×
45,379,43637.273.19×
88,552,23159.255.07×
1610,165,77370.436.02×

Un singolo core satura 10 GbE. Lo scaling è quasi lineare fino a quattro worker, poi diminuisce su una macchina con otto core fisici, perché il resto è SMT — hardware, non contesa sui lock.

Rispetto al vecchio sensore Python, riproducendo la stessa cattura di 300,000 pacchetti con le stesse 1,505,265 trail e la stessa configurazione, un worker ciascuno — escluso l'avvio, quindi questo è il costo a pacchetto a regime. Entrambe le cifre qui sono per l'intero processo (inclusi lettura pcap e dispatch), motivo per cui il numero del sensore è più alto del percorso a 552 ns per pacchetto misurato isolatamente sopra:

per pacchettopacchetti/s
sensore (Rust)865 ns1,156,423
vecchio sensore (Python)23,448 ns42,648
27× più veloce

Riproducilo tu stesso — l'harness è incluso nel repository, e stampa il conteggio degli eventi di entrambi i sensori, così un valore di throughput non potrà mai essere citato senza il suo contesto di correttezza:

python3 sensor/tools/bench_compare.py --packets 300000 --trails ~/.maltrail/trails.csv --repeat 3

La memoria non cresce con il numero di core: lo store da 1,5M di trail è 68,5 MB, costruito in 1,2 s e condiviso in modo immutabile da ogni worker.

Un solo worker di cattura di default, che gestisce ~1,1M di pacchetti/s ed è sufficiente per quasi tutti gli host sensore. I worker aggiuntivi sono un'opzione esplicita (CAPTURE_FANOUT), perché il kernel esegue l'hash di flusso della cattura mentre le euristiche di scansione contano per sorgente: degli allarmi euristici generati da un worker, il 91% sopravvive con 2 socket, l'86% con 4, il 65% con 8. Il rilevamento esatto delle trail è identico a qualsiasi numero di worker. Fai scale out quando maltrail_capture_dropped_total lo indica, non prima.

AMD Ryzen 7 PRO 4750U (8 core fisici), euristiche attive, set di trail reale, migliore di tre esecuzioni. Il rapporto è variato da 14–27× tra esecuzioni e hardware; i costi per pacchetto sopra sono quelli che delimitano quanto traffico un worker può assorbire. Queste sono cifre del percorso software — una NIC reale aggiunge costi di driver e ring, quindi misura il tuo hardware e controlla maltrail_capture_dropped_total. Metodo, suddivisione per protocollo, conteggi di istruzioni e output del profiler sono in sensor/docs/REPORT.md.


Avvio rapido

Linux, libpcap, Rust 1.74+ per il sensore, Python 3.7+ per il server.

I binari del sensore precompilati per x86_64 e aarch64 sono allegati a ogni release con un checksum SHA-256, quindi una toolchain Rust serve solo per compilare dai sorgenti. Per compilarla comunque:

git clone --depth 1 https://github.com/stamparm/maltrail.git
cd maltrail

# 1. build the sensor
cd sensor && cargo build --release && cd ..

# 2. let it capture without running as root
sudo setcap cap_net_raw,cap_net_admin=eip sensor/target/release/maltrail-sensor

# 3. give it somewhere to write events (LOG_DIR, /var/log/maltrail by default)
sudo install -d -o "$USER" -g "$USER" -m 750 /var/log/maltrail

# 4. check the deployment before trusting it — exits non-zero if anything is wrong
sensor/target/release/maltrail-sensor -T

# 5. run it (first start builds the trail set; takes a minute)
sensor/target/release/maltrail-sensor

In un altro terminale, o su un'altra macchina:

python3 server.py

Poi apri http://127.0.0.1:8338 e accedi con le credenziali in maltrail.conf (USERS).

-T è la scorciatoia per "funzionerà?" — valida la configurazione, le trail, la whitelist, la directory di log, il filtro di cattura e i privilegi, e ti dice esattamente cosa manca:

[o] log directory: '/var/log/maltrail' is writable
[o] capture privileges: CAP_NET_RAW present
[o] capture filter: udp or icmp or (tcp and (tcp[tcpflags] == tcp-syn or port 80 or port...
[o] interface: any
[o] workers: 16 (PACKET_FANOUT required; verify with tools/fanout_check.py as root)
[o] whitelist: 3440 entries, 18 CIDR range(s)
[o] trails: 1505265 loaded (0 malformed row(s)), ipv4=144758 ipv4:port=253517 ipv6=2014 wildcard=29
[o] heuristics: on (disabled: none)
[i] configuration test PASSED

Saltare i passaggi 2 o 3 è il modo più comune per ritrovarsi con un sensore che si avvia e non rileva nulla; -T li segnala entrambi.

Come servizio

sudo useradd --system --no-create-home --shell /usr/sbin/nologin maltrail
sudo rsync -a --exclude .git . /opt/maltrail/
sudo cp /opt/maltrail/maltrail-{server,sensor}.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now maltrail-server maltrail-sensor

Questa è l'intera installazione — nessuna directory da creare, nessun setcap. Le unità creano e possiedono /var/log/maltrail (eventi) e /var/lib/maltrail (il set di trail) tramite LogsDirectory=/StateDirectory= di systemd, eseguono entrambi i processi come utente non privilegiato maltrail con un filesystem in sola lettura, e danno al sensore esattamente CAP_NET_RAW e CAP_NET_ADMIN — nient'altro, e nessun root da nessuna parte. Il sensore esegue -T come ExecStartPre, quindi una distribuzione rotta fallisce su systemctl start invece di eseguire alla cieca.

Verifica: systemctl status maltrail-sensor e journalctl -u maltrail-sensor -f.

Docker

docker compose -f docker/docker-compose.yml up -d

Vedi docker/README.md.


Configurazione

Tutto si trova in maltrail.conf, diviso in [Sensor] e [Server]. Le opzioni più utili da conoscere:

opzionefunzione
MONITOR_INTERFACEinterfaccia/e su cui catturare, o any
CAPTURE_FILTERfiltro BPF; il default tiene il traffico bulk a velocità di linea fuori dallo userspace
PROCESS_COUNTworker di cattura — uno per core è un default ragionevole
LOG_DIRdove vengono scritti gli eventi (/var/log/maltrail)
TRAILS_FILEdove vive il set di trail costruito (~/.maltrail/trails.csv; /var/lib/maltrail sotto le unità)
LOG_SERVERinvia gli eventi a un server remoto invece di, o oltre a, registrarli localmente
STATS_ADDRESSespone metriche Prometheus (sensore; disattivato se non impostato)
UPDATE_PERIODogni quanto vengono aggiornate le trail
USER_WHITELISTla tua lista personale di elementi da non segnalare mai
CUSTOM_TRAILS_DIRle tue trail personali, insieme a quelle incluse

Trails

trails/static/malware/asyncrat.txt      # one indicator per line
trails/static/malicious/…
trails/static/suspicious/…
trails/feeds/*.py                       # public feeds, pulled on update

Aggiungere un indicatore significa aggiungere una riga a un file di testo. Aggiungere un feed è un piccolo modulo Python. Entrambi sono normali pull request, ed è questo basso attrito a mantenere utile il set.

I tuoi indicatori personali vanno in CUSTOM_TRAILS_DIR; tutto ciò di cui non vuoi mai sentire parlare va in USER_WHITELIST.


Eventi

Una riga per rilevamento, separati da spazi bianchi, con virgolette CSV dove serve:

"<time>" <sensor> <src_ip> <src_port> <dst_ip> <dst_port> <proto> <type> <trail> "<info>" <reference>

type è ciò che ha fatto match — DNS, IP, IPORT, URL, PATH, HTTP, UA, PORTinfo spiega perché è considerato dannoso, e reference indica da dove proviene la trail: (static), un nome di feed, o (heuristic).


Gestione

  • -T valida una configurazione ed esce. Utilizzabile come gate di deploy; l'unità systemd lo esegue come ExecStartPre.

  • STATS_ADDRESS espone metriche Prometheus. Le quattro su cui vale la pena fare alerting, tutte significano questo sensore non sta rilevando ciò che pensi:

    metricacosa significa
    maltrail_up == 0nessun worker di cattura è attivo — questo host non è monitorato
    rate(maltrail_capture_dropped_total)il ring sta scartando pacchetti — rilevamenti mancati
    rate(maltrail_local_log_errors_total)i rilevamenti sono stati prodotti e poi persi
    maltrail_trail_generation non avanzale trail hanno smesso di aggiornarsi

    Utili anche: maltrail_log_dir_free_bytes (vedi sotto) e maltrail_state_saturations_total, che è diverso da zero quando un flood di esaurimento dello stato ha ridotto le euristiche. Il matching esatto delle trail non è influenzato da questo, per design.

  • systemctl reload (SIGHUP) ricarica le trail senza riavvio. Le trail aggiornate da qualsiasi altra cosa vengono rilevate entro un secondo, con uno scambio atomico — nessun riavvio, nessun pacchetto perso.

  • Lo store osservabile condensato (USE_CONDENSED_STORAGE, meta.sqlite) che alimenta le viste /meta di novità e retro-hunt del server è scritto nello stesso formato prodotto dal vecchio sensore, e i due vengono confrontati riga per riga dall'harness di parità. Ogni differenza deliberata tra i sensori è elencata in sensor/docs/COMPATIBILITY.md.

Conservazione degli eventi

Maltrail non elimina mai le prove degli eventi. Non esiste un'impostazione di conservazione che faccia scadere i tuoi log, ed è una scelta deliberata: questi sono i record a cui torni dopo un incidente, e uno strumento che li scarta silenziosamente è peggio che inutile durante l'unica settimana in cui ti servono.

Questo rende lo spazio libero qualcosa da gestire attivamente, non da ignorare:

  • Spedisci la copia durevole fuori dalla macchina. LOG_SERVER (o SYSLOG_SERVER / LOGSTASH_SERVER) rende il server o il tuo SIEM il sistema di registrazione di riferimento, e il file locale del sensore un buffer. Questa è la strategia di conservazione; il disco locale non lo è.
  • Imposta alert su maltrail_log_dir_free_bytes con un margine reale. -T lo riporta anch'esso, e avvisa sotto i 10 GB. Quando arriva a zero il sensore non può più appendere e i rilevamenti vengono persi.
  • L'archiviazione è una tua decisione. Comprimi o sposta i vecchi log giornalieri secondo i tuoi tempi se ti serve spazio. Nota che l'interfaccia di reporting serve i log storici come semplici file seekable, quindi comprimerli sul posto rimuove quei giorni dall'interfaccia — archiviali altrove.

Se la tua policy richiede la cancellazione (i log degli eventi contengono indirizzi IP e domini, che in alcune giurisdizioni sono dati personali), quella è una decisione esplicita dell'operatore — prendila con i tuoi strumenti, deliberatamente, piuttosto che lasciare che un default del sensore lo faccia in silenzio.


Documentazione

sensor/docs/INSTALL.mdinstallazione, privilegi, configurazione, risoluzione dei problemi
sensor/docs/ARCHITECTURE.mdcome funziona internamente il sensore
sensor/docs/COMPATIBILITY.mdogni differenza deliberata rispetto al vecchio sensore
sensor/docs/REPORT.mdmisurazioni, profili e risultati dei test
sensor/docs/ROADMAP.mdcosa resta ancora aperto
old/README.mdil precedente sensore Python, conservato come riferimento e oracolo di test

Contribuire

Le trail sono il contributo più prezioso: una riga nel file giusto, con una fonte. Feed, segnalazioni di bug e lavoro sul sensore sono ugualmente benvenuti.

Il gate completo del sensore è un unico comando:

bash sensor/tools/check.sh

Esegue formattazione, lint, la suite di test in entrambi i profili debug e release, e riproduce un corpus sia con il sensore attuale sia con quello vecchio in Python, richiedendo eventi identici byte per byte. Il lato Python è bash tests/run.sh.


Licence

MIT. Vedi LICENSE.

Categorie