Aller au contenu

Comment casser la sécurité des kimsufi chez OVH

Network

A l’origine j’avais « juste » un nouveau serveur qui coupait toutes les 24 heures alors qu’il était tout neuf.. Aussi bien que c’était gênant, les techniciens étaient assez rapide pour redémarrer gentiment (reboot soft) la machine.

C’est au pendant le debug de ce problème que je suis tombé sur un problème de sécurité.

Mais bon quatre coupures en quatre jours, ca commençait à m’embêter..

reboot system boot 4.19.0-10-amd64 Wed Sep 2 17:08 - 17:21 (00:13)
reboot system boot 4.19.0-10-amd64 Tue Sep 1 16:58 - 17:21 (1+00:23)
reboot system boot 4.19.0-10-amd64 Mon Aug 31 16:46 - 17:21 (2+00:35)
reboot system boot 4.19.0-10-amd64 Mon Aug 31 14:41 - 16:11 (01:29)
reboot system boot 4.19.0-10-amd64 Mon Aug 31 12:36 - 12:53 (00:17)
reboot system boot 4.19.0-10-amd64 Sun Aug 30 12:22 - 12:53 (1+00:30)
reboot system boot 4.19.0-10-amd64 Sat Aug 29 11:33 - 12:53 (2+01:19)
reboot system boot 4.19.0-10-amd64 Fri Aug 28 11:15 - 12:53 (3+01:37)
reboot system boot 4.19.0-10-amd64 Thu Aug 27 10:38 - 12:53 (4+02:15)

Après avoir rebooté la machine en rescue lundi pour tester cpu et mémoire (qui était bonne), j’ai quand même demandé au support de faire changer la carte mère. L’intervention a été faite dans les deux heures des échanges avec le support.

Mardi a nouveau coupé, j’ai donc lancé :

  • une capture de trame (en filtrant tous les ports tcp/udp qui sont utilisés sur la machine)
  • un log de l’état de l’interface réseau (un simple contrab toutes les 5 minutes avec date >> /var/log/net_debug && ifconfig >> /var/log/net_debug)

La capture de trame n’a rien donné de très explicite sur le souci, par contre le debug d’état des interface donne quelquechose d’utile :

Wed 02 Sep 2020 04:55:01 PM UTC

enp1s0: flags=4163 mtu 1500
inet 188.165.214.25 netmask 255.255.255.0 broadcast 188.165.214.255
inet6 2001:41d0:2:a119::1 prefixlen 128 scopeid 0x0
inet6 fe80::225:90ff:fe54:5a00 prefixlen 64 scopeid 0x20
ether 00:25:90:54:5a:00 txqueuelen 1000 (Ethernet)
RX packets 77606056 bytes 99617488313 (92.7 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 49074438 bytes 29605997019 (27.5 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 16 memory 0xfbce0000-fbd00000

Wed 02 Sep 2020 05:05:01 PM UTC

enp1s0: flags=4163 mtu 1500
inet6 2001:41d0:2:a119::1 prefixlen 128 scopeid 0x0
inet6 fe80::225:90ff:fe54:5a00 prefixlen 64 scopeid 0x20
ether 00:25:90:54:5a:00 txqueuelen 1000 (Ethernet)
RX packets 78904821 bytes 101492927137 (94.5 GiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 49733001 bytes 29820473784 (27.7 GiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 16 memory 0xfbce0000-fbd00000

Alors bizarrement l’IPv4 a sauté 🤔

Du coup je regarde dans ma capture de trame les échanges DHCP, et il n’y en as aucun pour mon serveur…


Par contre qu’est ce que je trouve?

Des « DHCP Offer » et « DHCP ACK » en broadcast vers des serveurs qui ne sont pas sur la bonne interface…. Alors jusque la aucun souci, sauf que je n’ai aucun « DHCP Discover ».

Alors sur le coup je me dit, le switch doit avoir le private-vlan d’activé, sauf qu’ici je suis sur un Cisco 2960G qui ne supporte pas le private-vlan (seul le Cisco 2960-X le supporte (dans la gamme C-2960), et avec des serveurs en 100Mbit/s, je doute que ce soit réellement un 2960-X.

Donc d’après la capture je vois que les serveurs bootent en pxe quand ils passent en rescue.

Alors c’est bien utile pour les utilisateurs, mais du coup je découvre quelque-chose d’assez inhabituel : pour chaque serveur qui reboot en pxe, chaque gateway (les deux routeurs qui sont en HSRP) envoient des « DHCP Offer » et « DHCP Ack » à la machine qui passe en rescue avec les infos suivantes :

  • Identifiant serveur dhcp
  • une ip/masque/gateway, dns
  • boot file name
  • le root path (pour charger l’OS en mode diskless via nfs)
Dump DHCP
Dump packet DHCP

Du coup on voit que ce processus ne respecte pas vraiment la RFC2131 car pas de « DHCP Discover » ou de « DHCP Request », mais bon c’est peut-être voulu, ou obligatoire pour combler à un problème d’implémentation coté hardware des serveur.

Alors en quoi c’est gênant?

C’est simple si je suis un méchant :

  • je capture toutes les associations ip/mac par le biais des infos reçus via les échanges ARP reçu (un simple scan icmp me permet d’avoir cela et un script scapy pour dumper les réponses ARP dans un fichier csv – voir Script 1)
  • après avec cette base j’utilise un script qui envois en masse à toutes ces macs (en broadcast comme vu içi), des « DHCP Offer » et « DHCP Ack » avec les mêmes paramètres qu’OVH, mais avec une IP que je contrôle
  • sur cette IP que je contrôle, je met à disposition le fichier pxelinux.0 en tftp et l’OS en mode diskless via un partage NFS

La subtilité ici : via le chargement de l’OS en mode diskless que je met à disposition via la réponse DHCP, j’intègre au démarrage du faux « rescue » un script qui va installer une backdoor dans l’OS du serveur. Cette backdoor envoyant un ping à un serveur central, ou un botnet permettra soit d’agir vers d’autres serveurs (DDOS par exemple) ou même récupérer tous les fichiers du serveur

Existe t’il des solutions?

Malheureusement ce n’est pas si simple.
Comme les machines n’ont pas encore d’OS de chargé et d’IP attribué, il est obligatoire d’envoyer les « DHCP Offer » et « DHCP Ack » en broadcast. Ce qui fait que tous les utilisateurs du sous-réseau vont recevoir les infos. De plus l’équipement ne supportant pas le private-vlan, il est impossible d’obliger les machines à transiter via le routeur pour filtrer les annonces « DHCP Offer » et « DHCP Ack » de machines malveillantes..

Par contre

Je propose de passer les machines qui bootent en rescue dans un vlan dédié au rescue. Cela permet d’éviter qu’une autre machine puisse en prendre le contrôle comme cités ci-dessus. Cela rajoute du travail coté netops en plus en termes de conf, proposer une nouvelle IP pour le serveur (sauf en attribuant une IP en /32 et plus en /24) et risque d’augmenter la durée de passage en rescue, mais la sécurité se voie plus importante

Note :

  • La probabilité que ce problème soit exploitable n’est pas de 100% car pour chaque passage en rescue, OVH envois une douzaines d’Offer/ACK DHCP. Pour augmenter la probabilité, il faudrait flooder le réseau et potentiellement déclencher le Storm Control qui couperai le serveur du réseau en mettant l’interface en err-disable.
  • Pour des raisons évidente de sécurité et de légalité, je n’ai pas effectué de Proof Of Concept (POC) de cette hypothèse.

Script 1 – Récupération ARP dans fichier csv

#! /usr/bin/env python3

from scapy.all import ARP, sniff

def arp_display(pkt):
    if pkt[ARP].op == 2:  # is-at (response)
        f = open("mac.csv", "a")
        f.write("%s;%s\n"%(pkt[ARP].hwsrc,pkt[ARP].psrc))
        f.close()
        return f"*Response: {pkt[ARP].hwsrc} has address {pkt[ARP].psrc}"
sniff(prn=arp_display, filter="arp", store=0)

Timeline de ce post

  • 20200902 :
    • Rédaction du document en mode privé (mot de passe pour accéder au document.
    • Mail envoyé à sec[email protected] pour les informer et donner les accès au document.
  • 20200908 – Relance en indiquant que l’article sera publié le 16/09/2020 si pas de réponses
  • 20200913 – Ajout script 1
  • 20200914 – Relance auprès du responsable du pôle SOC
  • 20200916 :
    • Quelques ajustements du document
    • Publication en publique
  • 20200918 – Retour du responsable du pôle SOC m’indiquant qu’une sécurité niveau 2 (difficilement visible sans lancer des tests) est présente pour protéger les serveurs entre eux. Donc a priori pas de soucis de sécurité.

2 commentaires sur “Comment casser la sécurité des kimsufi chez OVH”

  1. Le vlan spécifique au rescue me parait la bonne pratique. (c’est ce que je faisais chez des hébergeurs lors de mes taf précédents)

    Après, rien ne t’empêchera de laisser ton serveur en rescue, de poser tes scripts dessus et de renouveler l’attaque depuis celui-ci :-/

    Ça reste moins trivial à découvrir, et on peut envisager de la génération de vlan « à la volée » selon le niveau du matériel réseau. En tout cas, ça reste moins moche que là où une simple capture de trame fait sonner l’alarme 😅

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée.