Modificación de la LSSICE

El pasado sábado 10 de mayo, se publicó en el Boletín Oficial del Estado (BOE), la nueva Ley de Telecomunicaciones (Ley 9/2014, de 9 de mayo), que introduce modificaciones a la vigente Ley 34/2002, de Servicios de la Sociedad de la Información y de Comercio Electrónico, más conocida como LSSI o LSSICE.

En este artículo se realiza un análisis sobre los aspectos relevantes de dichas modificaciones, de manera que se tengan en cuenta para futuras interpretaciones de la ley.

Las modificaciones más destacables son las siguientes:
  • En el artículo 21, de Prohibición de las comunicaciones comerciales no solicitadas realizadas a través de correo electrónico o equivalentes, se añade que dicha prohibición no será de aplicación cuando exista una relación contractual previa, siempre que el prestador haya obtenido los datos de contacto del destinatario de una forma lícita, y los emplee para el envío de comunicaciones comerciales referentes a productos o servicios de su propia empresa, que sean similares a los inicialmente contratados por el cliente.
    A pesar de dicha excepción, el prestador debe ofrecer al destinatario la posibilidad de oponerse al tratamiento de sus datos con fines promocionales mediante un procedimiento sencillo y gratuito, tanto en el momento de la recogida de los datos como en cada una de las comunicaciones comerciales realizadas. En el caso del uso del correo electrónico como medio para realizar la comunicación, éstos deberán incluir una dirección de correo electrónico donde el usuario pueda ejercitar dicho derecho.
  • En el artículo 22, de Derechos de los destinatarios de comunicaciones comerciales, se introduce la opción de uso de cookies de sesión en los terminales de los destinatarios por los prestadores de servicio, siempre que los destinatarios hayan dado su  consentimiento a dicho uso (por ejemplo a través de una aceptación en el navegador). En el momento que el destinatario dé su consentimiento, éste deberá ser informado de manera clara y completa sobre la utilización de dichas cookies, y en particular, sobre los fines del tratamiento de sus datos, en relación a lo dispuesto en la Ley Orgánica 15/1999, de tratamiento de datos de carácter personales, o LOPD.
  • En el artículo 38, de Infracciones y sanciones, se introduce como sanción leve el uso de cookies de sesión en los terminales de los destinatarios sin el consentimiento de los mismos, siempre que sea la primera vez en tres años. En caso de reincidencia de una sanción leve, y siempre que la reincidencia se efectúe en un periodo inferior a tres años, ésta pasaría a considerar-se una sanción grave.
  • Se introduce el nuevo artículo 39 bis, de Moderación de sanciones, en el que se indica que el órgano sancionador establecerá el valor de la sanción a la clase de infracciones que preceda de manera inmediata a la sanción vigente, es decir, que se introducirá una reducción de la cuantía de la sanción, en los casos siguientes:
    • a) Cuando exista una disminución de la culpabilidad del imputado como consecuencia de la concurrencia de alguno de los factores del artículo 40:
      • No existencia de intencionalidad en la infracción.
      • Plazo de tiempo de la infracción.
      • No reincidencia de infracciones de la misma naturaleza.
      • Naturaleza y cuantía de los perjuicios causados.
      • Beneficios obtenidos por la infracción.
      • Volumen de facturación que afecta a la infracción.
      • Adhesión a un código de conducta o sistema autoregulatorio publicitario aplicable a la infracción cometida.
    • b) Cuando la entidad infractora haya regularizado la situación irregular de sanción.
    • c) Cuando la conducta del afectado haya podido inducir la realización de la infracción.
    • d) Cuando el infractor haya reconocido espontáneamente su culpabilidad.
    • e) Cuando se haya producido un proceso de absorción entre entidades, no siendo imputable la entidad absorbente.
Además, los órganos sancionadores podrán acordar no iniciar la apertura del procedimiento sancionador, y en su lugar, apercibir al acusado, de manera que en el plazo determinado, éste acredite la adopción de las medidas correctoras adecuadas. Dicho caso solo se podrá dar en caso que el órgano competente no hubiese sancionado o apercibido con anterioridad al infractor por infracciones incluidas en ésta ley.
  • El artículo 40, de Competencia sancionadora, introduce a la Agencia de Protección de Datos como responsable de la imposición de sanciones por la comisión de infracciones relacionadas con los siguientes aspectos:
    • a) Envío masivo de comunicaciones comerciales por correo electrónico u otro medio equivalente (SPAM).
    • b) Incumplimiento habitual de la obligación de confirmar la recepción de una aceptación.
    • c) Resistencia, excusa o negativa a la actuación inspectora de los órganos autorizados a llevarlas.
    • d) Reincidencia en la comisión de infracciones leves en un plazo inferior a tres años desde la primera infracción.
    • e) Uso de cookies de sesión en los dispositivos de los destinatarios sin su previa autorización.
  • Se introduce el nuevo apartado 5 bis, en la disposición adicional sexta, de Sistema de asignación de nombres de dominio bajo el <<.es>>. En dicho apartado, se especifica que la autoridad de asignación de nombres de dominio de internet suspenderá cautelarmente, siempre que exista el requerimiento judicial correspondiente, los nombres de dominio mediante los cuales se esté cometiendo un delito o falta tipificada en el código penal. Dicha suspensión solo se podrá efectuar en el caso de que el prestador de servicios o persona responsable no haya atendido el requerimiento dictado para la interrupción de la infracción.
    Dicha suspensión consistirá en la imposibilidad de utilizar el nombre del dominio relacionado en efectos del direccionamiento en internet, junto con la prohibición de modificar la titularidad y los datos de registro del mismo.
  • Se introduce una disposición adicional octava, de Colaboración de los registros de nombres de dominio establecidos en España en la lucha contra actividades ilícitas. En dicha disposición, se establece que las entidades de registros de nombres en Internet están obligadas a facilitar los datos relativos a los titulares de los nombres de dominio, siempre que las autoridades públicas lo soliciten para el ejercicio de sus competencias de inspección, control y sanción, y siempre que las actividades que se persigan tengan relación con los nombres de dominio nombrados, como por ejemplo en el caso de investigación y mitigación de incidentes de ciberseguridad.
  • Se introduce una disposición adicional novena, de Gestión de incidentes de ciberseguridad que afecten a la red de Internet, en el que se establecen los siguientes principios:
    • a) Los prestadores de servicios implicados en la sociedad de la información, los registros de nombres de dominio y los agentes registradores están obligados a prestar su colaboración con el CERT competente, en la resolución de incidentes de ciberseguridad. Dicha colaboración puede incluir suministrar información implicada en el incidente, como direcciones IP o identificadores de usuarios, siempre que se respete el secreto de las comunicaciones.
    • b) En un plazo de seis meses, el gobierno pondrá en marcha un programa para impulsar un esquema de colaboración público-privada, con el fin de identificar los incidentes de ciberseguridad en España. En dicho programa, se elaborarán códigos de conducta en materias de ciberseguridad para los distintos prestadores de servicio relacionados con la sociedad de la información.
    • c) En caso de darse incidentes de seguridad, los prestadores de servicio deberán identificar a los usuarios afectados por los mismos, bajo notificación del CERT competente, e indicarles las acciones a tomar y los tiempos de actuación para la mitigación del incidente. En el caso que los usuarios no ejerciesen sus responsabilidades, los prestadores de servicio deberán aislar dichos equipos o servicios de la red.
    • d) La secretaría de Estado de Telecomunicaciones y para la Sociedad de la Información, garantizará un intercambio fluido de información con la Secretaría de Estado de Seguridad del Ministerio del Interior sobre incidentes, amenazas y vulnerabilidades, según lo contemplado en la ley 8/2001, de medidas de protección de las infraestructuras críticas, con el objetivo de garantizar una respuesta coordinada ante incidentes de ciberseguridad.

Como vemos, son bastantes las modificaciones y actualizaciones sufridas por la LSSICE con la nueva Ley de Telecomunicaciones, con el objetivo de adaptar-se a las nuevas necesidades de la sociedad, así como a las nuevas tecnologías presentes, y conseguir así una mayor protección de la sociedad de la información en España.

Referencias:

http://www.boe.es/boe/dias/2014/05/10/pdfs/BOE-A-2014-4950.pdf
https://www.boe.es/boe/dias/2002/07/12/pdfs/A25388-25403.pdf


Autor: Guillem Fàbregas - CISA, CISM, PCIP
Departamento de Consultoría.

Patrocinamos el II Congreso Iberoamericano de Ciberseguridad Industrial de Bogotá

Después del éxito del Primer Congreso Iberoamericano de Ciberseguridad Industrial celebrado en Madrid (España) los pasados 2 y 3 de Octubre de 2013, donde se dieron cita casi 200 asistentes de la industria, este año 2014 repetimos, este segundo evento se celebrará en el Hotel Dann Carlton de Bogotá (Colombia) los próximos 27 y 28 de Mayo de 2014 y alrededor del mismo se organizarán una serie de talleres pre y post congreso que complementarán las temáticas abordadas en el mismo.

El evento contará con ponentes internacionales que harán un repaso al estado y experiencias desarrolladas en todo el mundo, y en el que estarán representados fabricantes industriales, de ciberseguridad, ingenierías, consultoras, integradores, usuarios finales o infraestructuras críticas.

Desde Internet Security Auditors hemos querido participar y apoyar este nuevo encuentro. Es por ello que animamos a asistir a todo el que esté interesado y donde estaremos encantados de responder en persona cualquier cuestión sobre nuestros servicios y, en concreto, los relacionados con Ciberseguridad Industrial facilitando toda la información que puedan necesitar.

Encontrarán más información en la páginadel CCI.

Sangrando corazones criptográficos: Deconstruyendo la vulnerabilidad de OpenSSL

Como ya debe ser bien sabido por nuestros lectores, hace unas semanas la red se inundó con miles de referencias a lo que parece que será el bug del año.

Tanto es así que ya ha habido varias reacciones importantes para intentar que errores de esta magnitud no vuelvan a ocurrir. Por un lado tenemos el fork de OpenSSL por parte de OpenBSD, llamado LibreSSL [1], y por otro lado, tenemos la iniciativa de la Linux Foundation en la que se han asociado varias de las compañías más importantes del sector IT a nivel mundial (Intel, Microsoft, Google, IBM, DELL, Facebook, etc) para proveer de fondos a todos aquellos proyectos open source que sean críticos [2][3].

En esta entrada vamos a analizar técnicamente a qué se debe esta vulnerabilidad y a tratar ciertos aspectos que, generalmente, se han comentado menos como, por ejemplo, la explotación de esta vulnerabilidad en clientes en vez de en servidores.

Versiones vulnerables y versiones corregidas

Lo primero que se debe definir es que esta vulnerabilidad afecta a la versión de OpenSSL 1.0.1, pasando por la  1.0.1a hasta la  1.0.1f. También afecta a la versión 1.0.2-beta1. Los parches han sido liberados a partir de la versión 1.0.1g y en la versión 1.0.2 a partir de la versión 1.0.2-beta2. Por su parte, Debian ha liberado el parche en el paquete 1.0.1e-2+deb7u5. [4]

Heartbeat contra Heartbleed

Estas últimas semanas no ha habido descanso. En la red no se han parado de escuchar los siguientes términos. Heartbleed, heartbeat, heartbeat y de nuevo heartbleed. Pero ¿qué significan?

Heartbleed es el nombre que se le ha dado a una vulnerabilidad que afecta a una extensión del protocolo TLS y DTLS. Esta extensión se llama Heartbeat y se encarga de mantener las conexiones entre cliente y servidor abiertas sin necesidad de llevar a cabo renegociaciones. De ahí que el nombre de la vulnerabilidad haya jugado con el término del latido (beat) al sangrado (bleed), por el efecto de “fuga” que ha implicado esta vulnerabilidad.

El funcionamiento básico de este protocolo pasa por enviar dos tipos de paquetes, HeartbeatRequest y HeartbeatResponse. El paquete HeartbeatRequest se envía con un contenido arbitrario de modo que si la máquina que recibe dicho paquete contesta con un paquete HeartbeatResponse con el mismo contenido, la conexión se mantiene abierta. [5]

Así de simple.

Antes de continuar, es importante destacar lo siguiente. En la mayoría de protocolos es necesario especificar el tamaño de los datos que se van a enviar, de modo que el otro extremo de la comunicación sepa hasta donde debe leer para obtener todo el paquete. Esto también ocurre en el caso que nos concierne.

¿Cuál es la vulnerabilidad?

Conociendo lo anterior, entender la vulnerabilidad es muy simple.

Tenemos dos tipos de mensajes. HeartbeatRequest y HeartbeatResponse. Como ya hemos explicado, cuando se envía un mensaje HeartbeatRequest, el otro extremo debe enviar un mensaje HeartbeatResponse con el mismo contenido (o payload) que tenía el mensaje HeartbeatRequest. Fácil, ¿verdad?

El otro extremo de la comunicación necesita saber el tamaño del mensaje HeartbeatRequest que se le envía. Para ello, dentro del mensaje HeartbeatRequest existe un campo que indica el tamaño del contenido de dicho mensaje. Por ejemplo, si el mensaje HeartbeatRequest tiene como contenido "hola", el campo de tamaño será igual a 4.

Al recibir el mensaje HeartbeatRequest, el otro extremo de la comunicación reservará tanto espacio de memoria como indique el campo de tamaño de dicho mensaje para almacenar su contenido.

A continuación, responderá con un mensaje HeartbeatResponse enviando los datos para los que ha reservado memoria que, en principio, deberían ser los mismos que los que se han enviado con el mensaje HeartbeatRequest.

La mayoría ya entenderéis donde está el problema. ¿Qué ocurre si el contenido del mensaje HeartbeatRequest es igual a x, pero el campo de tamaño es igual a x+n? Pues que el mensaje de respuesta HeartbeatResponse enviará de vuelta x+n bytes, leídos todos ellos de la propia memoria del proceso openSSL.

Todo esto lo han resumido perfectamente en una imagen los maestros de XKCD: http://xkcd.com/1354/

Talk is cheap, show me the code

El código que se muestra a continuación se ha extraído de la versión 1.0.1e de openSSL. La función vulnerable se encuentra en la línea 2481 del archivo ssl/t1_lib.c y se llama tls1_process_heartbeat. A continuación se muestra la función al completo que después vamos a ir analizando:

int tls1_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;

 if (s->msg_callback)
  s->msg_callback(0, s->version, TLS1_RT_HEARTBEAT,
   &s->s3->rrec.data[0], s->s3->rrec.length,
   s, s->msg_callback_arg);

 if (hbtype == TLS1_HB_REQUEST)
  {
  unsigned char *buffer, *bp;
  int r;

  /* Allocate memory for the response, size is 1 bytes
   * 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);
  memcpy(bp, pl, payload);
  bp += payload;
  /* Random padding */
  RAND_pseudo_bytes(bp, padding);

  r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload 
                + padding);

  if (r >= 0 && s->msg_callback)
   s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
    buffer, 3 + payload + padding,
    s, s->msg_callback_arg);

  OPENSSL_free(buffer);

  if (r < 0)
   return r;
  }
 else if (hbtype == TLS1_HB_RESPONSE)
  {
  unsigned int seq;
  
  /* We only send sequence numbers (2 bytes unsigned int),
   * and 16 random bytes, so we just try to read the
   * sequence number */
  n2s(pl, seq);
  
  if (payload == 18 && seq == s->tlsext_hb_seq)
   {
   s->tlsext_hb_seq++;
   s->tlsext_hb_pending = 0;
   }
  }

 return 0;
 }
                           [ssl/t1_lib.c:2481]

Esta función es corta y simple. Comprueba si se recibe un mensaje HeartbeatRequest o HeartbeatResponse e implementa el comportamiento definido anteriormente. La variable 'p' apuntará al mensaje. En la variable 'hbtype' se almacenará el tipo de mensaje (HeartbeatRequest o HeartbeatResponse) y en 'payload', por engañoso que parezca, se almacenará el tamaño del payload, no el payload en sí. Con el siguiente código se establecen estos datos.
 
/* Read type and payload length first */
hbtype = *p++;
n2s(p, payload);
pl = p;
                            [ssl/t1_lib.c:2489]

La macro 'n2s' está definida en el archivo ssl/ssl_loc1.h, en la línea 249. Simplemente se encarga de recibir los dos bytes del campo de tamaño de un mensaje Heartbeat y los almacena en una variable de tipo unsigned int. Además, avanza el puntero que apunta al mensaje dos bytes, para que éste apunte al contenido del mensaje.


#define n2s(c,s)        ((s=(((unsigned int)(c[0]))<< 8)| \
                            (((unsigned int)(c[1]))    )),c+=2)
                            [ssl/ssl_locl.h:249]


Además, tenemos la instrucción 'pl = p'. Esta instrucción es muy importante porqué 'pl' se utilizará a continuación. Como ya hemos dicho, 'p' apunta al mensaje. Después establecer el tipo del mensaje y el tamaño del contenido, 'p' apuntará directamente al contenido del mensaje, con lo que 'pl' apuntará al mismo sitio.

A continuación se evalúa si el mensaje recibido es del tipo Request o Response. La vulnerabilidad se produce si el mensaje es de tipo Request, y este es el código que se ejecuta:

if (hbtype == TLS1_HB_REQUEST)
    {
    unsigned char *buffer, *bp;
    int r;

    /* Allocate memory for the response, size is 1 bytes
     * 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);
    memcpy(bp, pl, payload);
    bp += payload;
    /* Random padding */
    RAND_pseudo_bytes(bp, padding);

    r = ssl3_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);

    if (r >= 0 && s->msg_callback)
        s->msg_callback(1, s->version, TLS1_RT_HEARTBEAT,
            buffer, 3 + payload + padding,
            s, s->msg_callback_arg);

    OPENSSL_free(buffer);

    if (r < 0)
        return r;
    }
                            [ssl/ssl_locl.h:2499]

Como se puede ver, una de las primeras instrucciones que se ejecuta es un malloc en el que se reserva espacio para una variable  de un tamaño de 3 bytes más el padding y, además, se le añaden tantos bytes como se le haya especificado en el campo de tamaño del mensaje. Como se puede ver, ¡en ningún momento se ha comprobado este tamaño!

buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;
                            [ssl/ssl_locl.h:2508]

A continuación, se hace que el puntero 'bp' apunte al inicio del búfer que se ha reservado.

Con las siguientes líneas, en este búfer se almacena lo que se enviará como respuesta. Primero el tipo de mensaje (HeartbeatResponse), después el tamaño del contenido, a continuación el contenido en sí y, por último, cierto padding. Este búfer será el que se envié de vuelta como HeartbeatResponse.

Estas líneas son las que construyen lo que se enviará de respuesta.

/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);
bp += payload;
/* Random padding */
RAND_pseudo_bytes(bp, padding);
                            [ssl/ssl_locl.h:2511]

Con la función 'memcpy' se copian tantos bytes como se especifique en la variable 'payload', en la dirección donde apunte 'bp' como destino cogiendo los datos de la dirección a la que apunte 'pl'.

'bp' apunta al búfer que se ha reservado con 'malloc', o sea, es lo que se enviará como respuesta.

'pl' apunta al mensaje HeartbeatRequest que se ha recibido, que se habrá almacenado en algún punto de la memoria. Específicamente, la estructura en la que se almacena este mensaje se pasa como parámetro de esta función (SSL *s). Lo primero que se hace es asignar el puntero 'p' a esta estructura y, después, 'pl' apunta a cierto offset de 'p'. Esto se puede ver a continuación.

unsigned char *p = &s->s3->rrec.data[0], *pl;
(...)
pl = p;
                            [ssl/ssl_locl.h:2584,2592]

Así pues, se están copiando tantos bytes como especifique la variable 'payload', de donde apunta 'pl' a donde apunta 'bp'.

Si todo funcionara con normalidad, 'pl' apuntaría al contenido del mensaje HeartbeatRequest y sólo se copiarían tantos bytes como largo fuera dicho mensaje. Sin embargo, ¿qué ocurre si como tamaño se le envía un número mucho más grande? Pues que la función 'memcpy' empezará a copiar desde la dirección a la que apunte 'pl' tantos bytes como se le hayan especificado en el campo de tamaño (ahora almacenado en la variable 'payload').

Este comportamiento hará que en el mensaje de respuesta HeartbeatResponse se envíen tantos bytes como se le especifique en el mensaje HeartbeatRequest, consiguiendo así filtrar todos los datos que haya en la memoria del proceso a partir de la dirección a la que apunte 'pl'.

Y esta es, al fin, la vulnerabilidad Heartbleed.

Limitaciones

La pregunta más obvia una vez definida la vulnerabilidad es ¿Qué puedo leer? Esta pregunta se puede dividir, básicamente, en dos preguntas. La primera de ellas sería ¿De dónde puedo leer? Y la segunda sería ¿Cuánto puedo leer?

Empecemos por la segunda.

Tal y como se puede extraer del RFC [5], una estructura Heartbeat se define tal que así:

struct {
    HeartbeatMessageType type;
    uint16 payload_length;
    opaque payload[HeartbeatMessage.payload_length];
    opaque padding[padding_length];
} HeartbeatMessage;

Parece que esta estructura no se define en el código fuente de openSSL. Al menos, yo no he sido capaz de encontrarla. Pero para lo que necesitamos explicar, tenemos más que suficiente.
Como se puede ver, el campo 'payload_length' está definido como 'uint16', que viene a signifcar que esta variable será un 'unsigned int' de 16 bits, o sea, dos bytes.
Con una variable de 16 bits sin signo, el máximo valor que se puede especificar es 2^16 - 1, que es igual a 65535.

Esto significa que, como máximo, al explotar esta vulnerabilidad podremos leer 64Kb de la memoria del proceso vulnerable, o sea, openSSL.

La siguiente pregunta es ¿a partir de qué dirección de memoria podremos leer esos 64Kb?

Como ya se ha explicado, los datos de memoria que se leen parten desde la dirección origen apuntada por el puntero 'pl'. Este puntero apunta a un offset de la dirección a la que apunta el puntero 'p', que a su vez, apunta a la siguiente estructura de memoria &s->s3->rrec.data[0].

La variable 's' es de tipo 'SSL', que está definido del siguiente modo:

                    typedef struct ssl_st SSL;
                    [include/openssl/ossl_typ.h:172]

A su vez, la estructura 'ssl_st' se define del siguiente modo:
struct ssl_st
        {
        (...)
        struct ssl3_state_st *s3; /* SSLv3 variables */
        (...)
        }
                     [include/openssl/ssl.h:1105]

La estructura 'ssl_st' es muy grande, pero en este caso sólo nos interesa la variable 's3', que es la que se utiliza para leer el mensaje Heartbeat. Más específicamente nos interesa la variable 'rrec' que forma parte de la estructura 'ssl3_state_st', que se define de la siguiente manera:

typedef struct ssl3_state_st
        {
        (...)
        SSL3_RECORD rrec;       /* each decoded record goes in here */
        (...)
        }
                      [include/openssl/ssl3.h:405]


Por último, la estructura SSL3_RECORD tiene la siguiente definición:
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 */  unsigned char seq_num[8]; /* sequence number, needed by DTLS1 */
        } SSL3_RECORD; 
 
                       [include/openssl/ssl3.h:348]

De esta estructura sólo nos interesa el puntero 'data', ya que es en éste en el que se almacenará el mensaje Heartbeat y al que apuntarán 'p' y 'pl'. Desde la dirección a la que apunte este puntero hacia adelante se podrán leer 64Kb. Por tanto, para saber qué datos se van a poder leer, es necesario tener una idea de hacia qué dirección apuntará este puntero.

Lo cierto es que descubrir el origen de esta variable no fue nada fácil. No os vamos a aburrir con la media hora de indirecciones que se tuvieron que hacer para llegar al origen. Basta comentar que los datos que se almacenan en esta variable se leen en la función ssl3_setup_read_buffer que se llama, a su vez, desde ssl3_read_bytes.

int ssl3_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek)
        {
 (...)
        if (s->s3->rbuf.buf == NULL) /* Not initialized yet */
                if (!ssl3_setup_read_buffer(s))
                        return(-1);
 (...)
 }
                        [ssl/s3_pkt.c:941]


int ssl3_setup_read_buffer(SSL *s)
        {
 (...)
 if (s->s3->rbuf.buf == NULL)
 {
 (...)
 if ((p=freelist_extract(s->ctx, 1, len)) == NULL)
  goto err;
 s->s3->rbuf.buf = p;
 s->s3->rbuf.len = len;
 }

 s->packet= &(s->s3->rbuf.buf[0]);
 return 1;
 (...)
 }
                       [ssl/s3_both.c:736]

Es de la variable 's->packet' de la que se lee el contenido del mensaje Heartbeat, y esta variable apunta a 'p' que, a su vez, se obtiene a través de la función 'freelist_extract'.

La función 'freelist_extract' se encarga de obtener espacio de memoria para almacenar una variable. Dependiendo de cómo se haya compilado openSSL, este espacio se obtiene de un modo u otro, pero dicho espacio siempre se acabará obteniendo a través de una llamada a 'OPENSSL_malloc'. La diferencia está en que, por defecto, openSSL mantiene una lista de fragmentos de memoria libres de manera interna para no tener que depender de los algoritmos de la LIBC del sistema operativo. Y por lo visto, esto ha tenido su polémica estos días [7], pero eso ya es otro tema...

Básicamente OPENSSL_malloc es una macro que llama a la función CRYPTO_malloc. Esta función, después de dar unas cuantas vueltas, acaba llamando al malloc de toda la vida.


¡Todo este camino para descubrir que la región de memoria desde la que se pueden leer datos es el heap!  Es cierto que hace ya días que la gente comenta que los datos que se pueden leer son del heap. Sin embargo, en Internet Security Auditors nos gusta hacer las cosas bien. Y para hacerlas bien no queda otra que hundirte en el código y no creer a ciegas lo que se comenta.

Esto, aparte de robarnos algunas horas, nos ha permitido descubrir varias cosas. La primera es que los desarrolladores de openSSL implementan su propio sistema de gestión de memoria dinámica, no carente de vulnerabilidades [8].

Además, lo más importante es que hemos descubierto que la memoria se obtiene usando malloc. La función malloc, internamente, utiliza brk() o mmap() dependiendo del tamaño de la memoria a reservar. A grandes rasgos, la diferencia entre ambas funciones es que brk() reserva memoria de manera incremental a partir de la reserva de memoria anterior y mmap() reserva memoria a partir de una dirección que tú le especifiques.

Imagino que la mayoría de vosotros habréis deducido que el mejor modo para explotar esta vulnerabilidad es a través de llamar a mmap() en vez de brk(), ya que sería posible, de un modo u otro, especificar la dirección de memoria que se quiere leer. Siento decepcionaros, pero parece ser que eso no es posible. La función malloc, internamente, utiliza mmap, por defecto, sólo para fragmentos de memoria mayores a 128Kb y, como recordaréis, a través de esta vulnerabilidad sólo se puede pedir 64Kb de memoria.

Así pues, parece que la lectura de memoria va a ser bastante limitada ya que dependemos de las reservas de memoria incrementales a través de brk(). Esto significa que, en principio, no deberíamos ser capaces de leer datos en memoria que estén en una dirección inferior a la que apunta brk() y que aún no se hayan liberado.

¿Qué implica esto? Pues que, por ejemplo, no se deberían poder leer las claves privadas que el proceso openSSL tiene en memoria, ya que, en principio, éstas se almacenan al inicio de la ejecución del proceso y no se liberan en ningún momento.

Esta es nuestra teoría... que desastrosamente se ve tirada por el suelo por el challenge de CloudFlare en el que varias personas han podido obtener su clave privada a través de Heatbleed [9]. Aunque hayan necesitado unos cuantos millones de peticiones.

¿Qué nos enseña esto? Que cuando la lógica no aplique, siempre quedará la fuerza bruta.

¿A qué se puede deber? Pues especulando por especular, pensé que quizá podía ser algún 'corner case' del algoritmo de gestión de memoria dinámica del sistema operativo o del propio openSSL, en el que se mueven de sitio los datos en memoria debido al estrés de peticiones y la falta de espacio, o a la fragmentación interna de la memoria.

Tras unos días la gente de CloudFlare aclaró el misterio: la clave privada no sólo se almacena en memoria una sola vez al iniciarse el proceso, sino que se almacena en memoria varias veces, al realizarse peticiones al servidor web. La lectura de su análisis es altamente recomendado. [10]

En todo caso, hay otros datos críticos que se pueden leer. Estos datos son las peticiones pasadas de otros usuarios que ya se hayan liberado. Llegados a este punto se puede obtener todo lo que se os pase por la cabeza; usuario y contraseñas, identificadores de sesión, peticiones, etc.

Para acabar…


Esperamos poder haber hecho un análisis un poco más a fondo de lo que se ha estilado en la red estos días. Aún faltan cosas interesantes por explicar como, por ejemplo, la explotación de clientes en vez de la explotación típica de servidores. Pero, eso, mejor lo dejamos para otra entrada.

¡Hasta la próxima!

Referencias

[1] http://www.libressl.org/
[2] http://www.linuxfoundation.org/news-media/announcements/2014/04/amazon-web-services-cisco-dell-facebook-fujitsu-google-ibm-intel
[3] http://www.linuxfoundation.org/programs/core-infrastructure-initiative
[4] https://www.openssl.org/news/secadv_20140407.txt
[5] https://tools.ietf.org/html/rfc6520
[6] http://www.openssl.org/source/openssl-1.0.1e.tar.gz
[7] http://www.tedunangst.com/flak/post/analysis-of-openssl-freelist-reuse
[8] http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2010-5298
[9] http://blog.cloudflare.com/the-results-of-the-cloudflare-challenge
[10] http://blog.cloudflare.com/searching-for-the-prime-suspect-how-heartbleed-leaked-private-keys

Autor: Albert López
Departamento de Auditoría.