
Il bug Heartbleed `CVE-2014-0160` è un grave difetto di implementazione nella libreria OpenSSL, che consente agli aggressori di rubare dati dalla memoria del server vittima. Il contenuto dei dati rubati dipende da ciò che è presente nella memoria del server. Potrebbe potenzialmente contenere chiavi private, chiavi di sessione TLS, nomi utente, password, carte di credito, ecc. La vulnerabilità risiede nell'implementazione del protocollo Heartbeat, utilizzato da SSL/TLS per mantenere viva la connessione.
Il bug Heartbleed CVE-2014-0160 è un grave difetto di implementazione nella libreria OpenSSL che consente agli attaccanti di rubare dati dalla memoria del server vittima. Il contenuto dei dati rubati dipende da ciò che è presente nella memoria del server. Potrebbe potenzialmente contenere chiavi private, chiavi di sessione TLS, nomi utente, password, carte di credito, ecc. La vulnerabilità risiede nell'implementazione del protocollo Heartbeat, utilizzato da SSL/TLS per mantenere viva la connessione.
L'intervallo di versioni di OpenSSL interessate va dalla 1.0.1 alla 1.0.1f. La versione nella VM Ubuntu è la 1.0.1.
L'attacco Heartbleed si basa sulla richiesta Heartbeat. Questa richiesta invia semplicemente alcuni dati al server e il server copia i dati nel proprio pacchetto di risposta, quindi tutti i dati vengono rimandati indietro. Nel caso normale, supponiamo che la richiesta includa 3 byte di dati "ABC", quindi il campo della lunghezza ha valore 3. Il server inserisce i dati in memoria e copia 3 byte dall'inizio dei dati nel proprio pacchetto di risposta. Nello scenario di attacco, la richiesta può contenere 3 byte di dati, ma il campo della lunghezza può indicare 1003. Quando il server costruisce il pacchetto di risposta, copia dall'inizio dei dati (cioè "ABC"), ma copia 1003 byte, invece di 3. Questi 1000 byte extra ovviamente non provengono dal pacchetto di richiesta; provengono dalla memoria privata del server e possono contenere informazioni di altri utenti, chiavi segrete, password, ecc.
Successivamente, modifica il campo della lunghezza della richiesta. Per prima cosa, capiamo come viene costruito il pacchetto di risposta Heartbeat dalla figura sopra. Quando arriva il pacchetto di richiesta Heartbeat, il server analizza il pacchetto per ottenere il payload e il valore Payload_length (evidenziato sopra). Qui, il payload è solo una stringa di 3 byte "ABC" e il valore Payload_length è esattamente 3. Il programma del server prende ciecamente questo valore di lunghezza dal pacchetto di richiesta. Costruisce quindi il pacchetto di risposta puntando alla memoria che contiene "ABC" e copia Payload_length byte nel payload di risposta. In questo modo, il pacchetto di risposta conterrebbe una stringa di 3 byte "ABC".
Successivamente, lancia l'attacco Heartbleed come mostrato nella figura sotto. Mantieni lo stesso payload (3 byte), ma imposta il campo Payload_length a 1003. Il server prenderà di nuovo ciecamente questo valore Payload_length quando costruisce il pacchetto di risposta. Questa volta, il programma del server punterà alla stringa "ABC" e copierà 1003 byte dalla memoria nel pacchetto di risposta come payload. Oltre alla stringa "ABC", gli extra 1000 byte vengono copiati nel pacchetto di risposta e possono essere qualsiasi cosa presente in memoria, come attività segrete, informazioni di logging, password e così via.
Il codice dell'attacco consente di modificare il valore Payload_length. Di default, il valore è impostato a uno piuttosto grande (0x4000), ma può essere ridotto.
Il modo più semplice per correggere la vulnerabilità Heartbleed è aggiornare la libreria OpenSSL alla versione più recente. Tuttavia, l'obiettivo è correggere la vulnerabilità tramite il codice sorgente.
Formato del pacchetto di richiesta/risposta Heartbeat
struct {
HeartbeatMessageType type; // 1 byte: request or the response
uint16 payload_length; // 2 byte: the length of the payload
opaque payload[HeartbeatMessage.payload_length];
opaque padding[padding_length];
} HeartbeatMessage;
Il primo campo (1 byte) del pacchetto è l'informazione sul tipo, e il secondo campo (2 byte) è la lunghezza del payload, seguito dal payload effettivo e dal padding. La dimensione del payload dovrebbe essere la stessa del valore nel campo della lunghezza del payload, ma nello scenario di attacco, la lunghezza del payload può essere impostata a un valore diverso. Il seguente frammento di codice mostra come il server copia i dati dal pacchetto di richiesta al pacchetto di risposta.
Elaborazione del pacchetto di richiesta Heartbeat e generazione del pacchetto di risposta
/* Allocate memory for the response, size is 1 byte
* message type, plus 2 bytes payload length, plus
* payload, plus padding
*/
unsigned int payload;
unsigned int padding = 16; /* Use minimum padding */
// Read from type field first
hbtype = *p++; /* After this instruction, the pointer
* p will point to the payload_length field */
// Read from the payload_length field from the request packet
n2s(p, payload); /* Function n2s(p, payload) reads 16 bits
* from pointer p and store the value
* in the INT variable "payload". */
pl = p; // pl points to the beginning of the payload content
if (hbtype == TLS1_HB_REQUEST)
{
unsigned char *buffer, *bp;
int r;
/* Allocate memory for the response, size is 1 byte
* message type, plus 2 bytes payload length, plus
* payload, plus padding
*/
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;
// Enter response type, length and copy payload *bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
// copy payload
memcpy(bp, pl, payload); /* pl is the pointer which
* points to the beginning
* of the payload content */
bp += payload;
// Random padding
RAND_pseudo_bytes(bp, padding);
// this function will copy the 3+payload+padding bytes
// from the buffer and put them into the heartbeat response
// packet to send back to the request client side.
OPENSSL_free(buffer);
r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
}
La vulnerabilità si trova qui
// copy payload
memcpy(bp, pl, payload);
Non c'è alcun controllo per determinare se pl è valido o meno. Pertanto, può verificarsi una violazione della memoria.
Patch:
memcpy()Le patch sono state applicate nella VM ma non sono mostrate in questo repository.
Grazie per il tuo interesse, questo progetto è stato divertente e illuminante!