Explicaci贸n del error Heartbleed

    Como habr谩s escuchado, hay un nuevo error de OpenSSL y es malo. Este no es uno de esos errores o trucos de los que oye hablar en las noticias e ignora con seguridad como siempre lo hace. Afecta a alrededor del 66% de todos los servidores de Internet que existen, lo que probablemente incluye un sitio web que frecuenta o en el que tiene informaci贸n confidencial.

    C贸mo funciona

    Entonces, 驴cu谩l es el error exactamente? Para describir el error, necesitamos comprender solo algunas partes de la implementaci贸n de OpenSSL. La estructura siguiente contiene el registro SSL:

    typedef struct ssl3_record_st
    	{
    /*r */	int type;               /* type of record */
    /*rw*/	unsigned int length;    /* How many bytes available */
    /*r */	unsigned int off;       /* read/write offset into 'buf' */
    /*rw*/	unsigned char *data;    /* pointer to the record data */
    /*rw*/	unsigned char *input;   /* where the decode bytes are */
    /*r */	unsigned char *comp;    /* only used with decompression - malloc()ed */
    /*r */  unsigned long epoch;    /* epoch number, needed by DTLS1 */
    /*r */  PQ_64BIT seq_num;       /* sequence number, needed by DTLS1 */
    /*rw*/	unsigned int orig_len;  /* How many bytes were available before padding
    				   was removed? This is used to implement the
    				   MAC check in constant time for CBC records.
    				 */
    	} SSL3_RECORD;
    

    Esta estructura se utiliza en el dtls1_process_heartbeat(SSL *s) en el archivo d1_both.c para manejar los latidos que mantienen viva la conexi贸n SSL. Este m茅todo accede a los datos del registro en la estructura, como se muestra a continuaci贸n:

    int
    dtls1_process_heartbeat(SSL *s)
    	{
    	unsigned char *p = &s->s3->rrec.data[0], *pl;
    	unsigned short hbtype;
    	unsigned int payload;
    	unsigned int padding = 16; /* Use minimum padding */
        
        /* Read type and payload length first */
        hbtype = *p++;
        n2s(p, payload);
        pl = p;
    

    El primer byte del registro SSL es el tipo de latido recibido y la macro n2s(c, l) solo toma dos bytes de p, y los pone en payload. Estos bytes son la longitud de la carga 煤til en el latido. Lo importante a notar aqu铆 es que la longitud en el registro SSL no se comprueba / verifica. La variable pl ahora apunta a los datos de latidos, que fueron enviados por el cliente.

    El hecho de que no se verificara la longitud del registro SSL es un gran problema, ya que m谩s adelante en la misma funci贸n, la memoria se asigna usando la misma longitud de carga 煤til, que se muestra en el siguiente c贸digo:

    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;
    

    Ya que payload se le asignaron los primeros dos bytes de los datos de latido, que es proporcionado por el cliente, eso significa que puede tener un valor m谩ximo de 65535 (o 64k, cuando se refiere a bytes). Entonces, esencialmente, estamos asignando la cantidad de memoria que el cliente quiere que hagamos (hasta 64k), pero no es gran cosa, 驴verdad? Asignar cantidades de datos definidas por el usuario no es muy da帽ino en s铆 mismo (aunque definitivamente no es algo bueno), pero aqu铆 es da帽ino ya que m谩s adelante en la misma funci贸n copiamos esa cantidad de memoria en nuestro b煤fer:

    s2n(payload, bp);
    memcpy(bp, pl, payload);
    

    Aqu铆, s2n(c, l) mueve el tama帽o de la carga 煤til al bp buffer (opuesto a lo que n2s hizo), y memcpy copia el n煤mero de bytes de carga 煤til de pl a bp. Esto tampoco parece un gran problema hasta que considere el tama帽o real de pl. Y si pl es solo unos pocos bytes de tama帽o? 驴O incluso solo un byte? Un atacante podr铆a habernos dicho que la carga 煤til era de 64 kb, cuando solo era de 1 byte. Entonces, 驴de d贸nde se copiar铆a el resto de la memoria si pl es mucho m谩s peque帽o de lo esperado? Memoria circundante, que puede haber sido liberado recientemente del mismo proceso.

    Potencialmente, hay una gran cantidad de datos confidenciales en la memoria circundante, como nombres de usuario, contrase帽as e incluso claves privadas. Esto tiene a mucha gente preocupada ya que un atacante podr铆a enviar continuamente latidos maliciosos a un servidor y seguir recuperando 64 kb de su memoria cada vez. Luego, una simple b煤squeda de palabras clave como ‘contrase帽a’ o ‘tarjeta de cr茅dito’ y listo, el atacante rob贸 sus datos sin que nadie lo supiera. Mark Loman, investigador de seguridad, ya ha mostrado este ataque es posible con Yahoo Mail.

    Sin embargo, por suerte para nosotros, la clave privada probablemente sea segura, como se帽ala Neel Mehta (uno de los investigadores que descubri贸 el error):

    Los patrones de asignaci贸n de mont贸n hacen poco probable la exposici贸n de claves privadas #coraz贸n #dontpanico.

    – Neel Mehta (@neelmehta) 8 de abril de 2014

    Sean Cassidy proporciona informaci贸n muy 煤til sobre estos m茅todos de asignaci贸n de montones:

    Hay dos formas en que la memoria se asigna din谩micamente con malloc (en
    menos en Linux): usando sbrk (2) y usando mmap (2). Si la memoria es
    asignado con sbrk, entonces usa las viejas reglas de crecimiento del mont贸n y
    limita lo que se puede encontrar con esto, aunque m煤ltiples solicitudes
    (especialmente al mismo tiempo) todav铆a podr铆a encontrar algunas cosas divertidas1.

    Las asignaciones para bp no importan en absoluto, en realidad. La asignaci贸n
    para pl, sin embargo, importa mucho. Es casi seguro que est谩 asignado
    con sbrk debido al umbral de mmap en malloc. Sin embargo,
    cosas interesantes (como documentos o informaci贸n de usuario), es muy probable que
    asignado con mmap y puede ser accesible desde pl. M煤ltiple
    las solicitudes simult谩neas tambi茅n pondr谩n a disposici贸n algunos datos interesantes.

    驴C贸mo se fija?

    Dado que este error es tan simple de ejecutar, eso significa que tambi茅n es f谩cil de solucionar. OpenSSL ya ha publicado una actualizaci贸n, la versi贸n 1.0.1g. Contiene la siguiente soluci贸n:

    /* Read type and payload length first */
    if (1 + 2 + 16 > s->s3->rrec.length)
        return 0; /* silently discard */
    hbtype = *p++;
    n2s(p, payload);
    if (1 + 2 + payload + 16 > s->s3->rrec.length)
        return 0; /* silently discard per RFC 6520 sec. 4 */
    pl = p;
    

    Como puede ver, las diferencias son las verificaciones de longitud, que primero aseguran que el latido no est茅 vac铆o (longitud 0) y, en segundo lugar, verifica que la carga 煤til del latido coincida con la longitud proporcionada por el usuario. Es as铆 de simple. Cuatro l铆neas de c贸digo ahora protegen a m谩s del 66% de los servidores del catastr贸fico error Heartbleed.

    C贸mo est谩 parcheado

    驴Ejecuta un servidor de cara al p煤blico que utiliza SSL? Entonces definitivamente deber铆as parchearlo. Solo puedo asumir que alguien ya ha configurado un marcador de guerra que verifica cada servidor que puede para detectar este error y luego explota los que lo tienen. Entonces, si est谩 ejecutando Ubuntu, ejecute lo siguiente:

    sudo apt-get update
    sudo apt-get install -y libssl1.0.0 openssl
     
    # Verify that the Build Date is April 7th 2014 or later
    openssl version -a
    

    Luego, aseg煤rese de reiniciar todos y cada uno de los servicios que usan OpenSSL. Si no est谩 seguro de que el parche haya funcionado, utilice esta herramienta descubrir.

     

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *