Aller au contenu principal

Réseau

Le réseau du projet sépare deux besoins:

  • un réseau privé stable entre attaquant et victime pour le scénario
  • un accès NAT QEMU pour télécharger paquets et scripts depuis le host.

Topologie

Interfaces

MachineConnexionAdresseUsage
Hostbr-wlkom192.168.100.254/24bridge privé
Attaquantwlkom-lab192.168.100.1/24dashboard, payloads, listener
Victimewlkom-lab192.168.100.2/24HTTP vers page victime, TCP reverse
VMswlkom-wanDHCP QEMUapt, accès 10.0.2.2:8000

Les scripts NetworkManager ciblent les interfaces par MAC QEMU. Cela évite de dépendre des noms ens3, enp0s3, etc.

Le projet choisit des IPs fixes configurées dans les VMs (192.168.100.1 pour l'attaquant, 192.168.100.2 pour la victime) plutôt qu'une IP DHCP à recopier à chaque lancement. C'est le scénario le plus proche d'un contrôleur déjà maîtrisé: le module connaît l'adresse du serveur C2 dès son chargement via attacker_ip.

Le piège à éviter: 10.0.2.2 n'est pas l'attaquant. C'est l'adresse spéciale du host vue depuis le NAT QEMU. Le module, lui, revient vers 192.168.100.1:4444.

Ports

PortMachineService
8000/tcphostserveur de fichiers host served/
8080/tcpattaquantFlask, dashboard, page victime, payloads
4444/tcpattaquantlistener C2 du module

Le port 8000 est vu depuis les VMs via:

http://10.0.2.2:8000

Le port 8080 est vu depuis la victime via:

http://192.168.100.1:8080

Le canal C2 est:

wlkom.ko victime -> 192.168.100.1:4444 attaquant

Flux HTTP

La page victime et les payloads sont publics sur le réseau privé. Le dashboard et l'API /api/rootkit/* sont restreints à l'attaquant et localhost.

Flux C2

Le backend découpe une réponse avec le marqueur __KOZACI_RESPONSE_END_8F8F6A0E6D4A41C2__, puis consomme le prompt suivant. Il ne s'appuie pas seulement sur wlkom>, car une commande pourrait afficher ce texte elle-même.

Pourquoi une connexion reverse?

La victime ne garde pas de port ouvert. Le module connaît seulement:

attacker_ip=192.168.100.1
command_port=4444

Il tente donc de joindre l'attaquant. Ce choix simplifie le fonctionnement:

  • le dashboard peut rester en attente
  • le module retente si le panel n'est pas encore lancé
  • une déconnexion ferme la socket et déclenche une nouvelle boucle
  • l'état UI reste lisible: absent, détecté, besoin de mot de passe, connecté.

Techniquement, le module utilise sock_create_kern, kernel_connect, kernel_sendmsg, kernel_recvmsg, kernel_sock_shutdown, kvec et msghdr. Le backend utilise une socket Python classique. Les deux côtés appliquent le même chiffrement XOR dérivé du mot de passe, avec offsets émission et réception séparés.

Pour comprendre ces fonctions kernel, voir Sockets kernel et kvec, msghdr et envoi partiel.

Retry et état

Côté kernel:

SituationComportement
kernel_connect échouepause 10 secondes, retry
mot de passe fauxmessage Bad password., fermeture socket, pause 5 secondes
session terminéefermeture socket, pause 5 secondes
module stoppékernel_sock_shutdown(..., SHUT_RDWR) réveille kernel_recvmsg(), puis sortie via kthread_should_stop()

Côté backend, status expose:

listener_bound
detected
needs_password
connected
active_peer
pending_peer
connection_attempts
auth_failures
last_seen_at
last_error
crypto.tx_offset
crypto.rx_offset

Contrôles rapides

Host:

ip addr show br-wlkom
ip link show tap-attacker
ip link show tap-victim

Attaquant:

ip -brief addr
ss -lntp | grep -E ':8080|:4444'
curl -fsS http://192.168.100.1:8080/api/rootkit/status

Victime:

ip -brief addr
curl -I http://192.168.100.1:8080/freecloude
curl -I http://192.168.100.1:8080/payload/freecloude.py
curl -I http://192.168.100.1:8080/payload/freecloude.sh

Si ces commandes passent mais que le C2 ne se connecte pas, le problème est probablement côté listener 4444, mot de passe ou chargement du module. Voir Troubleshooting.