
Roba IPMI dal lavoro DARPA
<p>
Ho scritto alcuni software per esplorare IPMI; ecco alcuni dei risultati. Ho pensato di
fare il solito ciclo di rilevamento, acquisizione dati e audit. Ognuno di questi
si è rivelato un problema piuttosto interessante di per sé, almeno per me.
</p>
**BTW/FYI** - Ho rilasciato un nuovo strumento per esplorare IPMI - https://github.com/zenfish/zipmi -
così come una serie di ricette/immagini/etc. di Qemu per eseguire BMC come sistemi virtuali sotto
Qemu su https://github.com/zenfish/zbmc.
<h4>Sito web IPMI</h4>
I documenti e le cose da http://fish2.com/ipmi
<p> <a href="https://github.com/zenfish/ipmi/blob/master/html">html</a> </p>
<h4>Cracking delle password</h4>
Ecco un <a href="https://github.com/zenfish/ipmi/blob/master/rak-the-ripper.pl">piccolo programma Perl</a>
che tenta di indovinare un account su un BMC remoto, estrarne l'hash,
e poi provare a craccare la sua password (hashata con HMAC). Ho scritto un
<a href="http://fish2.com/ipmi/remote-pw-cracking.html">piccolo</a>
articolo su questo per i curiosi. Pesantemente commentato, potrebbe essere utile.
<h4> Ottenere i cipher</h4>
La specifica IPMI dice che puoi ottenere i cipher di un sistema remoto senza alcuna
autenticazione, ma non sono a conoscenza di alcuno strumento che lo faccia davvero
(tutti richiedono autenticazione, anche se ovviamente potresti inserire i byte hex
grezzi se volessi!) Quindi ho scritto questo piccolo programma per farlo; per lo più
cerca di seguire l'output di ipmitool; nel farlo credo di aver trovato un
bug in quell'utilità (nell'ultima riga *a volte* i sistemi emettono della
spazzatura che sembra essere interpretata male), ma chi lo sa, non ho
abbastanza sistemi per testarlo. Comunque... <a href="https://github.com/zenfish/ipmi/blob/master/ipmi-get-ciphers.py">ipmi-get-ciphers.py</a>.
Se non altro, utile per individuare sistemi Cipher0 (nota - questo
indica semplicemente i cipher supportati - non significa che
siano effettivamente attivi), ma ci sono cose interessanti in giro.
<h4> Ottenere i dettagli di autenticazione </h4>
Due programmi qui, uno è un semplice
prober remoto in Python (sto iniziando a odiare Perl, ve lo dico io) e un secondo
che usa le utilità di <a href="http://www.gnu.org/software/freeipmi/">FreeIPMI</a>
per recuperare dati di configurazione con credenziali.
</p> <p>
Un piccolo programma Python (oltre il 50% di commenti inline, 2.5k gzip'd) che invia un singolo pacchetto
a un BMC e riflette sulla risposta. Cosa puoi fare con un solo pacchetto, uno
potrebbe chiedere? 10+ diversi test di sicurezza per IPMI, tanto per cominciare. Beh, tanto per
cominciare e per finire, è solo un pacchetto :) Richiede Python, un BMC e un percorso aperto verso
la porta UDP 623 per funzionare. L'uso è semplicemente "ipmi-get-auth.py target".
<p style="padding-left:60px;">
<span style="padding: 5px; border: 1px solid #AAA;"> <a href="https://github.com/zenfish/ipmi/blob/master/ipmi-get-auth.py">ipmi-get-auth.py</a> /
<a href="http://trouble.org/?p=712">Una descrizione molto breve</a> </span><br />
</p> <p>
Portando questo agli estremi... beh, ecco una specie di versione mega
di quanto sopra che lo fa per tutti i canali, tutti i privilegi, tutti... beh,
avete capito. Per i monomaniaci (leggete i commenti o il post
che ho scritto al riguardo per capire perché fa quello che fa!)
<p style="padding-left:60px;">
<span style="padding: 5px; border: 1px solid #AAA;"> <a href="https://github.com/zenfish/ipmi/blob/master/mega_chan.py">mega_chan.py</a> /
<a href="http://trouble.org/?p=1046">Mega mega mega ... chan chan chan...</a> </span><br />
</p> <p>
<h4> Ottenere l'ID del dispositivo (GUID) </h4>
Ed ecco un semplice programma per inviare un pacchetto Get Device ID (vedi
p250 della specifica IPMI v 2) a un sistema. Questo dovrebbe, in teoria,
funzionare senza autenticazione. In una piccola indagine che ho condotto, circa il 90%
dei sistemi ha risposto a questo (anche se non tutti con informazioni valide!)
A volte puoi ottenere il vendor e altre informazioni, come
numeri di modello e simili, ma la cosa più interessante è ottenere
un ID univoco, tradizionalmente una cosa difficile da ottenere via rete.
<p style="padding-left:60px;">
<span style="padding: 5px; border: 1px solid #AAA;"> <a href="https://github.com/zenfish/ipmi/blob/master/mega_chan.py">get-ipmi-guid.py</a> /
<a href="http://trouble.org/wp-admin/post.php?post=1052">Get Device ID</a> </span><br />
</p> <p>
<h4> Estrarre le password da un file di password binario SuperMicro</h4>
Supermicro ha avuto alcuni problemi con la divulgazione dei file di password dai
loro BMC - per esempio, vedi questo e altri articoli:
<blockquote>
<a target="_blank" href="https://community.rapid7.com/community/metasploit/blog/2013/07/02/a-penetration-testers-guide-to-ipmi">a-penetration-testers-guide-to-ipmi</a>
</blockquote>
Per usare questo script basta dire:
<blockquote>
<a href="https://github.com/zenfish/ipmi/blob/master/dump_SM.py">dump_SM.py</a> password_file
</blockquote>
Funziona per me, nessuna garanzia implicita, garantita, ecc.
<h4>Rilevamento</h4>
Beh, se puoi parlare con la porta UDP 623, è abbastanza semplice
scoprire se un sistema remoto sta eseguendo IPMI. A meno che tu non sia dentro
un data center, comunque, la maggior parte delle persone blocca UDP. E anche se non lo
fanno... la scansione UDP è lenta quanto si possa immaginare. Quindi attualmente
sto usando due metodi di base, sfruttando il venerabile Nmap e
ipmiping (dagli strumenti GNU FreeIPMI.) La cosa più semplice da fare è:
</p> <p>
<ul>
<li>Usare ipmiping per chiedere a un sistema remoto se parla IPMI o no. Una risposta
positiva è l'indicazione più forte che un sistema parla IPMI
(ma nulla è certo!) Più tecnicamente invia due chiamate
Get Channel Authentication Capabilities IPMI tramite un datagramma di richiesta
Get Channel Authentication Capabilities sulla porta UDP 623 (due
richieste poiché usa UDP, e le connessioni non sono garantite.)
</p> <p>
Poiché Nmap è molto più efficiente nella scansione di reti su larga scala
rispetto a ipmiping, questo metodo viene usato solo se Nmap dice che un host
ha la porta UDP 623 aperta.
</p> <p>
Nel bene e nel male questa porta è spesso bloccata, quindi molte
volte altri metodi hanno più probabilità di scoprire indirettamente se
IPMI è in esecuzione o no.
<li>Il secondo metodo è un po' vago, e si basa su un po' di
induzione (ovvero congetture.) Nmap scansiona le porte note per essere
associate a IPMI e alle aggiunte dei vendor; UDP 623 è ovvia (la
porta IPMI predefinita), ma ci sono una varietà di porte (sia UDP che
TCP) che da sole potrebbero non dare subito una risposta,
ma prese nel loro insieme possono indicare fortemente la sua presenza.
TFTP, SNMP, SSH/SMASH, VNC e molti altri sono tra queste.
</p> <p>
Le porte sono pesate in base alla loro capacità indicativa e al fatto che
Nmap le trovi aperte, filtrate o in altri stati.
</p> <p>
Nmap può anche mostrare i banner dei servizi a cui si connette. Uso
espressioni regolari per cercare i target - per esempio le stringhe
"iLO" e "DRAC" sono buoni indicatori che un sistema potrebbe eseguire
il servizio Integrated Lights Out di HP, o iLO.
</p> <p>
<strong>Nota:</strong> Attualmente NON uso il metodo del
ping broadcast (un modo molto rapido per attraversare la sottorete in cui
ti trovi); semplicemente non ho dati sull'efficacia
di questo; anche se molto veloce quando funziona, non mi sembrava che
permettesse il controllo e l'affidabilità delle scansioni arbitrarie.
Due dei miei tre sistemi (Dell e HP) hanno risposto a un
ping RMCP. Nessuno ha risposto a un ping broadcast di idiscover
(ipmiutil discover.) Tutti, comunque, hanno risposto al mio
strumento di audit Python qui sotto.
</p> <p>
Sfortunatamente (ovviamente!) lo spettro delle comunicazioni e delle
reti entra in gioco - nmap dà un sacco di motivi diversi
sul perché una porta è aperta o no (open, closed, filtered, ecc.)
Un'altra tabella ha un insieme di pesi che dà più punti a
una porta aperta che a un risultato "open|filtered" (come direbbe Nmap).
Interpretare nmap e pesare è un po' frustrante,
ma c'est la vie.
</p> <p>
Prendi tutti i pesi, somma tutti i punti e hai un livello di certezza
IPMI. Ho scoperto in test ad hoc che 15 punti o
più sono forti indicatori che il sistema sta eseguendo IPMI.
</p> <p>
Attualmente ho varie soglie (no, forse, probabilmente,
sì.) Nei test - senza avere accesso noto ad altri server
oltre ai miei - sembra funzionare ragionevolmente bene. Cioè,
le cose che ritengo sospette e il mio modello di pensiero di base
di cui sopra fa effettivamente emergere certi server in cima e
lascia in pace gli host casuali. Ci sono però alcuni veri problemi con
i falsi positivi - molti firewall sembrano far credere a nmap che
ci sia qualcosa su qualsiasi porta (ho pensato di inserire una porta rara
o due (se ascolti qualcosa come la porta 1 e 31313,
per esempio, probabilmente non la stai *davvero* ascoltando!)
</p> <p>
Ma questo non vuole essere l'ultima parola sull'argomento. Dovrebbe
essere abbastanza semplice ottenere dei dati decenti sui banner IPMI, la mia
ipotesi è che sarebbe di gran lunga il modo migliore per scansionare rapidamente grandi
quantità di sistemi.
</ul>
</p> <p>
Ecco quattro pezzi di Perl per implementare quanto sopra; uno scansiona,
uno interpreta, e gli altri due sono usati per la pesatura. È uno
strumento di ricerca o una prova di concetto, non uno scanner di produzione, ma
produce comunque un output ragionevole.
</p> <p>
<strong>REQUISITO: Nmap versione 6.</strong>
</p>
<table border=1>
<tr> <td style="padding-left:30px;"> <span> <a href="https://github.com/zenfish/ipmi/blob/master/ipmi-scan/ipmi_scan.pl">ipmi_scan.pl</a> - scanner IPMI di base, usa Nmap e, se disponibile, ipmitool </span> </td> </tr>
<tr> <td style="padding-left:30px;"> <span> <a href="https://github.com/zenfish/ipmi/blob/master/ipmi-scan/ipmi_scan.out">pagina man di ipmi_scan</a> - pagina man per quanto sopra</span> </td> </tr>
<tr> <td style="padding-left:30px;"> <span> <a href="https://github.com/zenfish/ipmi/blob/master/ipmi-scan/post_ipmi_scan.pl">post_ipmi_scan.pl</a> - analizza l'output di quanto sopra, produce alcuni risultati pesati </span></td> </tr>
<tr> <td style="padding-left:30px;"> <span><a href="https://github.com/zenfish/ipmi/blob/master/ipmi-scan/j_vendor.pl">j_vendor.pl</a> - Alcuni dati di base sui vendor... quali porte usano?</span> </td> </tr>
<tr> <td style="padding-left:30px;"> <span><a href="https://github.com/zenfish/ipmi/blob/master/ipmi-scan/j_weights.pl">j_weights.pl</a> - Alcuni pesi di base dei vendor per quanto sopra</span> </span></td> </tr>
</table>
</p> <p>
L'uso è abbastanza semplice, anche se un po' strano. Dovrebbe essere eseguito come root. Verbose (-v) per molto output.
<blockquote>
<pre>
# esecuzione standard:
./ipmi_scan.pl -A -v -O yes 192.168.0.0/24
# veloce
./ipmi_scan.pl -tcp -v 192.168.0.0/24
# tutto incluso
./ipmi_scan.pl -A -v -O high 192.168.0.0/24
</pre>
</blockquote>
La scansione creerà una coppia di file di risultati che corrispondono ai
nomi dei target (le barre sono convertite in underscore.) Basta eseguire il
post-processore su di essi; passarli attraverso un ordinamento numerico inverso li mette
in un ordine più interessante. Qualsiasi cosa sopra 10 la definirei sospetta,
mentre maggiore di 20 è abbastanza certo che stia eseguendo IPMI.
In questo caso ho
usato il flag terse (-t) per ridurre l'output al minimo indispensabile.
<blockquote>
<pre>
./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
</pre>
</blockquote>
</p> <p>
Nei risultati sopra i primi 3 sistemi stanno effettivamente eseguendo IPMI,
ma solo l'HP ha detto a Nmap che la porta UDP 623 era aperta - il mio Dell e
Supermicro hanno restituito la risposta più ambigua "open|filtered",
che è abbastanza comunemente un falso allarme, bleah. Forse è meglio
semplicemente rassegnarsi e fare il ping IPMI in parallelo con lo scanner
(o scrivere un NSE per farlo correttamente in Nmap.)
</p> <p>
<h4>Audit</h4>
Ecco un paio di piccoli programmi Python che - usando gli strumenti FreeIPMI - (a) assorbono la
configurazione di base IPMI/BMC di un server e (b) fanno un piccolo controllo di sicurezza sui risultati.
Perché io... beh, nessuna buona ragione, in realtà. Uno è in python3 e l'
altro in python2. Immagino che stia testando la vostra prontezza. I programmi sono
abbastanza pesantemente commentati, specialmente ipmifreely.py, quindi controllate quello per
più dettagli su cosa succede. Richiede simplejson e ConfigParser,
forse qualcosa in più.
</p> <p>
<span style="color: #ff0000;">DEVI</span> avere <a title="FreeIPMI"
href="https://github.com/zenfish/ipmi/blob/master/www.gnu.org/software/freeipmi" target="_blank">FreeIPMI</a>
installato, che, al momento della scrittura, elimina le possibilità di Mac e Windows
di scaricare un bel file JSON da un server. E dovresti davvero,
davvero avere una versione recente. Non dire che non ti avevo avvisato.
Ma la vita continua.
</p> <p>
L'acquisizione dei dati è fatta tramite un programma Python (I-check.py) che
richiede credenziali valide per ottenere i dati. Converte i risultati in
JSON, che a sua volta può essere controllato dallo strumento di audit (ipmifreely.py.)
C'è una policy di esempio in "IPMI-policy.ini", dove ho messo alcuni valori
per i test.
</p> <p>
<table border=1>
<tr> <td style="padding-left:30px;"> <span> <a href="https://github.com/zenfish/ipmi/blob/master/iaudit/I-check.py">I-check.py</a> - recupera i dati di configurazione IPMI</span> </td> </tr>
<tr> <td style="padding-left:30px;"> <span> <a href="https://github.com/zenfish/ipmi/blob/master/iaudit/ipmifreely.py">ipmifreely.py</a> - analizza l'output di quanto sopra, produce alcuni risultati</span> </td> </tr>
<tr> <td style="padding-left:30px;"> <span> <a href="https://github.com/zenfish/ipmi/blob/master/iaudit/IPMI-policy.ini">IPMI-policy.ini</a> - file di policy IPMI</span></td> </tr>
</table>
</p> <p>
Esempio di utilizzo:
<blockquote>
<pre>
# questo recupera le cose di configurazione; qui lo sto usando su un server HP iLO 3
# l'output è reindirizzato a un file
$ ./ipmifreely.py -v -u admin -p admin 192.168.0.46 > hp.json
# Questo prende il file JSON e cerca problemi
$ ./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
</pre>
</blockquote>
Puoi dare un'occhiata ad alcune <a href="https://github.com/zenfish/ipmi/blob/master/ipmi/bp.pdf">Best Practice di Sicurezza IPMI</a> per maggiori
informazioni su cosa controllare, cose che considero buone da fare, dal punto di vista della sicurezza.