
IPMI stuff from DARPA work
J'ai écrit quelques logiciels pour explorer IPMI ; voici quelques résultats. Je pensais faire le cycle habituel : détection, récupération de données et audit. Chacun de ces aspects s'est avéré être un problème assez intéressant en soi, du moins pour moi.
Les articles et autres ressources de http://fish2.com/ipmi
Voici un petit programme Perl qui tente de deviner un compte sur un BMC distant, d'extraire son hash, puis d'essayer de casser son mot de passe (haché en HMAC). J'ai écrit un petit peu à ce sujet pour les curieux. Largement commenté, il peut être utile.
La spécification IPMI indique que l'on peut obtenir le chiffrement d'un système distant sans aucune authentification, mais je ne connais aucun outil qui le fasse réellement (ils exigent tous une authentification, même si, bien sûr, vous pourriez saisir les octets hexadécimaux bruts si vous le vouliez !) J'ai donc écrit ce petit programme pour le faire ; il essaie surtout de suivre la sortie d'ipmitool ; ce faisant, je crois avoir trouvé un bug dans cet utilitaire (sur la dernière ligne, parfois les systèmes émettent des données parasites qui semblent être mal interprétées), mais qui sait, je n'ai pas assez de systèmes pour tester. Bref... ipmi-get-ciphers.py.
Si rien d'autre, utile pour repérer les systèmes Cipher0 (notez - cela indique simplement les chiffrements pris en charge - cela ne signifie pas qu'ils sont réellement activés), mais il y a des choses intéressantes dans la nature.
Deux programmes ici, l'un est un simple sondeur distant en Python (je commence à détester Perl, croyez-moi) et un second qui utilise des utilitaires de FreeIPMI pour récupérer des données de configuration avec identifiants.
Un petit programme python (plus de 50 % de commentaires en ligne, 2,5 ko compressé en gzip) qui envoie un seul paquet à un BMC et analyse la réponse. Que peut-on faire avec un seul paquet, demandera-t-on ? 10+ tests de sécurité différents pour IPMI, pour commencer. Eh bien, pour commencer et pour finir, ce n'est qu'un paquet :) Nécessite python, un BMC et un chemin ouvert vers le port UDP 623 pour fonctionner. L'utilisation est simplement « ipmi-get-auth.py target ».
ipmi-get-auth.py /
Une très petite description
En poussant les choses à l'extrême... eh bien, voici une sorte de version méga de ce qui précède qui le fait pour tous les canaux, tous les privilèges, tous... enfin, vous voyez l'idée. Pour les monomaniaques (lisez les commentaires ou l'article que j'ai écrit à ce sujet pour comprendre pourquoi il fait ce qu'il fait !)
mega_chan.py /
Méga méga méga ... chan chan chan...
Et voici un simple programme pour envoyer un paquet Get Device ID (voir p. 250 de la spécification IPMI v 2) à un système. Cela devrait, en théorie, fonctionner sans authentification. Dans une petite enquête que j'ai menée, environ 90 % des systèmes y ont répondu (mais pas tous avec des informations valides !) Vous pouvez parfois obtenir le vendeur et d'autres informations, comme les numéros de modèle et autres, mais le plus intéressant est d'obtenir un identifiant unique, traditionnellement une chose difficile à obtenir via le réseau.
get-ipmi-guid.py /
Get Device ID
Supermicro a eu quelques problèmes de divulgation de fichiers de mots de passe depuis leurs BMC - par exemple, voyez cet article et d'autres écrits :
a-penetration-testers-guide-to-ipmi
Pour utiliser ce script, il suffit de dire :
dump_SM.py password_file
Ça marche pour moi, aucune garantie implicite, garantie, etc.
Eh bien, si vous pouvez parler au port UDP 623, il est assez simple de savoir si un système distant exécute IPMI. Cependant, à moins d'être dans un centre de données, la plupart des gens bloquent UDP. Et même s'ils ne le font pas... le scan UDP est à peu près aussi lent que possible. J'utilise donc actuellement deux méthodes de base, en m'appuyant sur le vénérable Nmap et ipmiping (des outils GNU FreeIPMI.) La chose la plus simple à faire est :
</p> <p>
Comme Nmap est bien plus efficace pour scanner les réseaux à grande échelle
que ipmiping, cette méthode n'est utilisée que si Nmap indique qu'un hôte
a le port UDP 623 ouvert.
</p> <p>
Pour le meilleur ou pour le pire, ce port est souvent bloqué, donc la plupart
du temps, d'autres méthodes sont plus susceptibles de découvrir indirectement
si IPMI est exécuté ou non.
</p> <p>
Les ports sont pondérés par leur capacité indicative et selon que
Nmap les trouve ouverts, filtrés ou dans d'autres états.
</p> <p>
Nmap peut également afficher les bannières des services auxquels il se connecte. J'utilise
des expressions régulières pour chercher des cibles - par exemple, les chaînes
"iLO" et "DRAC" sont de bons indicateurs qu'un système exécute peut-être
le service Integrated Lights Out de HP, ou iLO.
</p> <p>
<strong>Note :</strong> Actuellement, je n'utilise PAS la méthode de ping par diffusion
(un moyen très rapide de parcourir le sous-réseau dans lequel vous vous trouvez) ;
je n'ai tout simplement aucune donnée sur son efficacité ; bien que très rapide
quand elle fonctionne, je n'avais pas l'impression qu'elle permettait le contrôle
et la fiabilité des scans arbitraires. Deux de mes trois systèmes (Dell et HP) ont
répondu à un ping RMCP. Aucun n'a répondu à un ping par diffusion d'idiscover
(ipmiutil discover.) Tous ont cependant répondu à mon outil d'audit Python
ci-dessous.
</p> <p>
Malheureusement (bien sûr !) le spectre des communications et des
réseaux entre en jeu - nmap donne un tas de raisons différentes
pour expliquer pourquoi un port est ouvert ou non (ouvert, fermé, filtré, etc.)
Un autre tableau a un ensemble de poids qui donne plus de points à
un port ouvert qu'à un résultat « open|filtered » (comme dirait Nmap).
Interpréter nmap et pondérer est un peu frustrant,
mais c'est la vie.
</p> <p>
Prenez tous les poids, additionnez tous les points et vous obtenez un niveau
de certitude IPMI. J'ai constaté lors de tests ad hoc que 15 points ou
plus sont de forts indicateurs que le système exécute IPMI.
</p> <p>
Actuellement, j'ai différents seuils (non, possiblement, probablement,
oui.) Lors des tests - sans avoir accès connu à d'autres serveurs
que les miens - cela semble fonctionner raisonnablement bien. C'est-à-dire que
les choses que je trouve suspectes et mon modèle de pensée de base
ci-dessus font effectivement remonter certains serveurs en haut de la liste et
laissent les hôtes aléatoires tranquilles. Il y a de vrais problèmes de
faux positifs, cependant - de nombreux pare-feux semblent indiquer à nmap que
quelque chose est présent sur n'importe quel port (j'ai pensé à ajouter un port
rare ou deux (si vous écoutez quelque chose comme le port 1 et 31313,
par exemple, vous ne l'écoutez probablement pas *vraiment* !)
</p> <p>
Mais cela n'a pas vocation à être le dernier mot sur le sujet. Il devrait
être assez simple d'obtenir de bonnes données sur les bannières IPMI ;
je pense que ce serait de loin la meilleure façon de scanner rapidement de grandes
quantités de systèmes.
Voici quatre programmes Perl pour implémenter ce qui précède ; l'un scanne, l'un interprète, et les deux autres servent à la pondération. C'est un outil de recherche ou une preuve de concept, pas un scanner de production, mais il produit des résultats raisonnables.
EXIGÉ : Nmap version 6.
L'utilisation est assez simple, bien qu'un peu particulière. Doit être exécuté en tant que root. Le mode verbeux (-v) donne beaucoup de sortie.
Le scan créera une paire de fichiers de résultats correspondant aux noms des cibles (les barres obliques sont converties en tirets bas.) Exécutez simplement le post-processeur sur eux ; un tri numérique inverse les place dans un ordre plus intéressant. Tout ce qui dépasse 10, je le qualifierais de suspect, et plus de 20 est assez certain d'exécuter IPMI.# standard run: ./ipmi_scan.pl -A -v -O yes 192.168.0.0/24 # fast ./ipmi_scan.pl -tcp -v 192.168.0.0/24 # kitchen sink ./ipmi_scan.pl -A -v -O high 192.168.0.0/24
Dans ce cas, j'ai utilisé l'option terse (-t) pour réduire la sortie au strict minimum.
./post_ipmi_scan.pl -t 192.168.0.0_24|sort -rn 96.3 192.168.0.69 16.25 192.168.0.46 10.8 192.168.0.23 7.33 192.168.0.202 5.4 192.168.0.189 5.4 192.168.0.179 1.7 192.168.0.9 1.23 192.168.0.1 1.1 192.168.0.8 0.9 192.168.0.251 0.63 192.168.0.55 0.43 silent/192.168.0.250 0.2 pi.fish2.com/192.168.0.14 0.2 fierce.fish2.com/192.168.0.6 0.2 192.168.0.88 0.01 192.168.0.16
Dans les résultats ci-dessus, les 3 premiers systèmes exécutent réellement IPMI, mais seul le HP a indiqué à Nmap que le port UDP 623 était ouvert - mon Dell et mon Supermicro ont renvoyé la réponse plus ambiguë « open|filtered », qui est assez souvent une fausse alerte, beurk. Peut-être vaut-il mieux serrer les dents et faire le ping IPMI en parallèle avec le scanner (ou écrire un NSE pour le faire correctement dans Nmap.)
Voici deux petits programmes python qui - utilisant les outils FreeIPMI - (a) aspirent la configuration IPMI/BMC de base d'un serveur et (b) effectuent un petit contrôle de sécurité sur les résultats.
Parce que je... eh bien, aucune bonne raison, en fait. L'un est en python3 et l' autre en python2. Je suppose que je teste votre préparation. Les programmes sont assez largement commentés, surtout ipmifreely.py, alors consultez-le pour plus de détails sur ce qui se passe. Nécessite simplejson et ConfigParser, peut-être un peu plus.
VOUS DEVEZ avoir FreeIPMI installé, ce qui, au moment où j'écris ces lignes, élimine toute chance pour Mac et Windows de récupérer un joli fichier JSON depuis un serveur. Et vous devriez vraiment, vraiment avoir une version récente. Ne dites pas que je ne vous ai pas prévenu. Mais la vie continue.
L'acquisition des données se fait via un programme python (I-check.py) qui nécessite des identifiants valides pour obtenir les données. Il convertit les résultats en JSON, qui peut à son tour être vérifié par l'outil d'audit (ipmifreely.py.) Il y a une politique d'exemple dans « IPMI-policy.ini », où j'ai mis quelques valeurs pour les tests.
| I-check.py - récupère les données de configuration IPMI |
Exemple d'utilisation :
# this grabs the configuration stuff; here I'm using it on an HP iLO 3 server # the output is redirected to a file $ ./ipmifreely.py -v -u admin -p admin 192.168.0.46 > hp.json # This takes the JSON file and looks for issues $ ./I-check.py drac.json ./I-check.py hp.json Host: 192.168.0.46 [bmc-config] Serial_Channel Non_Volatile_Enable_Pef_Alerting = No [bmc-config] Serial_Channel Volatile_Enable_Pef_Alerting = No [bmc-config] Serial_Channel Volatile_Enable_Per_Message_Auth = No [bmc-config] Serial_Channel Non_Volatile_Enable_Per_Message_Auth = No [bmc-config] Lan_Conf_Security_Keys K_G = 0x0000000000000000000000000000000000000000 [bmc-config] SOL_Conf Force_SOL_Payload_Authentication = No [bmc-config] SOL_Conf Force_SOL_Payload_Encryption = No [bmc-config] Lan_Conf_Auth Callback_Enable_Auth_Type_None = Yes [bmc-config] Lan_Conf_Auth Operator_Enable_Auth_Type_None = Yes [bmc-config] Lan_Conf_Auth OEM_Enable_Auth_Type_None = Yes [bmc-config] Lan_Conf_Auth Admin_Enable_Auth_Type_None = Yes [bmc-config] Lan_Conf_Auth User_Enable_Auth_Type_None = Yes [bmc-config] Rmcpplus_Conf_Privilege Maximum_Privilege_Cipher_Suite_Id_1 = OEM_Proprietary [bmc-config] Rmcpplus_Conf_Privilege Maximum_Privilege_Cipher_Suite_Id_0 = OEM_Proprietary [bmc-config] Rmcpplus_Conf_Privilege Maximum_Privilege_Cipher_Suite_Id_2 = OEM_Proprietary [pef-config] Community_String Community_String = public [pef-config] PEF_Conf Enable_PEF_Event_Messages = No
Vous pouvez consulter quelques Bonnes pratiques de sécurité IPMI pour en savoir plus sur ce qu'il faut vérifier et ce que je considère comme de bonnes choses à faire, côté sécurité.
| ipmi_scan.pl - scanner IPMI de base, utilise Nmap et, si disponible, ipmitool |
| page de manuel ipmi_scan - page de manuel pour ce qui précède |
| post_ipmi_scan.pl - analyse la sortie de ce qui précède, produit des résultats pondérés |
| j_vendor.pl - Quelques données de base sur les constructeurs... lesquels utilisent quels ports ? |
| j_weights.pl - Quelques pondérations de base pour les constructeurs ci-dessus |
| ipmifreely.py - analyse la sortie de ce qui précède, produit des résultats |
| IPMI-policy.ini - fichier de politique IPMI |