Skip to content

Repository files navigation

Metasoma: Decentralized and Collaborative Early-Stage Detection of IoT Botnets

Metasoma is a supervised deep learning system for detecting the spreading phase of IoT botnets in a fully decentralized, collaborative fashion. Each device runs a local instance of the model, monitors its own traffic, and periodically gossips learned device embeddings to peers — achieving detection accuracy competitive with centralized approaches without any global observer.

Ahmed Lekssays, Lodovico Giaretta, Barbara Carminati, Elena Ferrari, Šarūnas Girdzijauskas
Qatar Computing Research Institute · RISE Research Institutes of Sweden · Università degli Studi dell'Insubria · KTH Royal Institute of Technology


How it works

Each IoT device maintains a memory tensor — one GRU-based embedding per peer it has observed. When a new packet arrives, the memory updater revises the embeddings of the source and destination devices. A packet classifier and a device classifier read from these embeddings to predict (i) whether the current packet is malicious, (ii) whether the source/destination is a malware-infected node, and (iii) whether the source/destination is currently executing an attack.

Periodically, each device gossips a subset of its embeddings to a randomly chosen peer. The receiver merges the incoming embeddings with its own via a trainable GRU merger, propagating knowledge about devices it has never directly communicated with.

All three components — updater, merger, classifier — are trained jointly on a single weighted binary cross-entropy loss.


Repository structure

metasoma/
├── training/
│   ├── train_v2.py              # Main entry point: cross_dataset, in_distribution, combined
│   ├── models_v2.py             # GPU-optimized model (micro-batched TBPTT)
│   ├── models.py                # Base GRU components (MemoryUpdater, MemoryMerger2)
│   ├── data_loading_v2.py       # Batch construction + gossip schedule pre-computation
│   ├── data_preparation.py      # Feature engineering; produces Window objects
│   ├── create_splits.py         # Generates temporal 80/10/10 splits → data/splits/splits.json
│   ├── preprocess_iot23.py      # Parses Zeek conn.log.labeled files (IoT-23)
│   ├── preprocess_kitsune.py    # Extracts features from Kitsune pcap + label alignment
│   ├── preprocess_medbiot.py    # Converts MedBIoT pcap captures to CSV
│   ├── fraud_detector.py        # Normalizing-flow forgery detector (security analysis)
│   └── prepare-models.py        # Trains the forgery model for the security experiments
├── runs/v2/
│   ├── cross_dataset/           # Cross-dataset transfer results (Table 2 in paper)
│   ├── in_distribution/         # In-distribution holdout results (Table 3 in paper; also Table 1)
│   └── combined/                # Combined training results
├── inference/                   # C++ on-device inference
├── gossip/                      # Go gossip protocol implementation
├── autopeering/                 # Go peer-discovery implementation
├── simulator/                   # Network simulator for gossip/eclipse experiments
├── data/splits/splits.json      # Fixed train/val/test indices (do not regenerate)
└── requirements.txt

Datasets

Three publicly available IoT botnet datasets are used. Do not regenerate data/splits/splits.json — the archived indices are the ones used to produce all reported results.

MedBIoT

Guerra-Manzanares et al., IFIP SEC 2020.
Download: https://cs.taltech.ee/research/data/medbiot/
Captures: Bashlite, Mirai, Torii — network of 83 devices.
Place raw pcap files under data/raw/medbiot/.

Kitsune

Mirsky et al., NDSS 2018.
Download: https://www.kaggle.com/datasets/ymirsky/network-attack-dataset-kitsune
Capture: Mirai — network of 12 devices.
Place the Mirai pcap + label CSV under data/raw/kitsune/.

IoT-23

García et al., CTU-Prague 2020.
Download: https://www.stratosphereips.org/datasets-iot23
Captures used (Zeek conn.log.labeled files):

Capture Family Role
CTU-IoT-Malware-Capture-60-1 Gagfyt Test — unseen
CTU-IoT-Malware-Capture-8-1 Hakai Test — unseen
CTU-IoT-Malware-Capture-42-1 Trojan Test — unseen
CTU-IoT-Malware-Capture-34-1 Mirai Test — cross-net
CTU-IoT-Malware-Capture-44-1 Mirai Test — cross-net
CTU-IoT-Malware-Capture-20-1 Torii Test — cross-net
CTU-IoT-Malware-Capture-21-1 Torii Test — cross-net
CTU-Honeypot-Capture-4-1 Benign Test — benign
CTU-Honeypot-Capture-5-1 Benign Test — benign

Place the labeled Zeek logs under data/raw/iot23/.


Environment setup

Python 3.8+ and PyTorch 1.9+ are required. A CUDA-capable GPU is strongly recommended (experiments were run on a single GPU; CPU training is supported but much slower).

pip install -r requirements.txt

Reproducing the results

Step 1 — Preprocess raw data

# IoT-23 (Zeek conn.log.labeled → CSV)
python training/preprocess_iot23.py

# Kitsune (pcap → CSV with Mirai labels)
python training/preprocess_kitsune.py

# MedBIoT (pcap → CSV)
python training/preprocess_medbiot.py

Preprocessed CSVs should end up under:

  • data/raw/iot23/
  • data/raw/kitsune_csv/
  • data/raw/medbiot_csv/

Step 2 — Do NOT regenerate splits

The file data/splits/splits.json contains the exact per-family train/val/test indices used in the paper. Leave it as is.

If you ever need to regenerate it from scratch (e.g., for a new dataset):

python training/create_splits.py

Step 3 — Run experiments

All experiments share the same hyperparameters and split file.

# In-distribution holdout (Table 3 in paper)
# Train: MedBIoT + Kitsune (80%); Test: same families, held-out 10%
python training/train_v2.py in_distribution

# Cross-dataset transfer (Table 2 in paper)
# Train: MedBIoT + Kitsune; Test: IoT-23 (entire dataset, never seen during training)
python training/train_v2.py cross_dataset

# Combined training
# Train: all datasets (80%); Test: all datasets, held-out 10%
python training/train_v2.py combined

Optional environment variables:

Variable Default Description
METASOMA_EPOCHS 5 Number of training epochs
METASOMA_MAX_PKTS 500000 Max packets per family (evenly-spaced subsampling)
METASOMA_MAX_WINS unlimited Max windows per epoch

Results are written to runs/v2/{exp_name}/results.json and logged to Weights & Biases.


Key hyperparameters

Parameter Value Description
Memory dimension $D$ 32 Per-device GRU hidden size
Window size 5,000 packets Truncated-BPTT sequence length
TBPTT interval 50 packets Micro-batch size (graph truncation)
Gossip interval 15 s Average time between gossip rounds
Memories per gossip 8 IP entries shared per round
Learning rate 1e-3 Adam optimizer
Epochs 5
Public IP buckets 256 Hash buckets for non-private IPs
Random seed 42

Results

Table 3 — In-distribution holdout (Exp 3)

Train: MedBIoT + Kitsune (80%). Test: same families, last 10% by timestamp.

Family PKT F1 PKT AUROC NMAL F1 NMAL AUROC NATK F1 NATK AUROC
Kitsune-Mirai 0.999 1.000 0.978 1.000 0.996 1.000
MedBIoT-Bashlite 0.993 1.000 0.964 0.999 0.915 0.982
MedBIoT-Mirai 0.988 0.998 0.966 0.998 0.963 0.999
MedBIoT-Torii 0.999 1.000 0.984 1.000 0.994 1.000
Macro avg. 0.960 0.998 0.572 0.751 0.798 0.722

PKT = packet malicious detection; NMAL = node malware detection; NATK = node attack detection.

Table 2 — Cross-dataset transfer to IoT-23 (Exp 2)

Train: MedBIoT + Kitsune. Test: IoT-23 (zero-shot — never seen during training).
AUROC is omitted (—) where the test set contains only one class.

Family Type PKT F1 PKT AUROC NMAL F1
Gagfyt Unseen 0.966 0.902 0.936
Hakai Unseen 0.983 0.659
Trojan Unseen 0.985 0.659
Mirai Cross-net 0.983 0.661
Torii Cross-net 0.986 0.662
Benign Benign 0.984

Packet-level F1 ≥ 0.96 across all IoT-23 families, including three (Gagfyt, Hakai, Trojan) entirely absent from the training data.

Table 1 — Comparison with LiMNet on Kitsune (AUROC)

Model D PKT NMAL NATK
LiMNet 32 99.7 81.2 82.2
Metasoma 32 99.2 80.1 81.6
LiMNet 64 99.8 82.0 82.9
Metasoma 64 99.2 81.4 82.4

Metasoma operates in a fully decentralized setting (no central observer) while matching the centralized LiMNet to within 0.5–1.1 AUROC points on packet classification.


Pre-trained models

The best checkpoints from each experiment are archived under runs/v2/:

Path Experiment
runs/v2/in_distribution/best_model.pt In-distribution holdout (Table 3); also used for the LiMNet comparison (Table 1)
runs/v2/cross_dataset/best_model.pt Cross-dataset transfer to IoT-23 (Table 2)
runs/v2/combined/best_model.pt Combined training

Load with:

import torch
from training.models_v2 import TrainerV2

model = torch.load('runs/v2/in_distribution/best_model.pt', map_location='cpu')

Security analysis

The fraud_detector.py and prepare-models.py scripts implement the Normalizing Flow-based forgery detector described in Section 4 of the paper. The forgery detector estimates the density of the training embedding distribution and rejects embeddings with anomalously low likelihood. At the operating point where 0% of honest memories are rejected, only ~0.2% of adversarially forged memories are accepted.


Citation

@article{lekssays2025metasoma,
  title   = {Metasoma: Decentralized and Collaborative Early-Stage Detection of {IoT} Botnets},
  author  = {Lekssays, Ahmed and Giaretta, Lodovico and Carminati, Barbara and Ferrari, Elena and Girdzijauskas, {\v{S}}ar{\={u}}nas},
  year    = {2025}
}

Update with the venue, volume, DOI, and pages once the paper is published.

About

ADeLe: Advanced Decentralized LiMNet Environment

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages