miércoles, 22 de noviembre de 2017

Echando un vistazo al heap overflow de procmail

Se ha corregido una vulnerabilidad en procmail que podría causar una denegación de servicio y potencialmente ejecutar código arbitrario de forma remota. 

procmail, es un agente de correo que es usado para filtrar los mensajes entrantes, tanto por motivos de SPAM como por, simplemente, enviar los correos al buzón de acuerdo a una reglas predeterminadas y programadas por el usuario mediante su propio lenguaje de programación.

El fallo ha sido encontrado por Jakub Wilk y se trata de un desbordamiento de memoria basada en montículo (Heap-based overflow). El error está localizado en la función loadbuf del archivo fuente formisc.c

Como podemos observar, en el parche:


diff --git a/src/formisc.c b/src/formisc.c
index d91b227..6c7594b 100644
--- a/src/formisc.c
+++ b/src/formisc.c
@@ -103,7 +103,7 @@ void loadsaved(sp)const struct saved*const sp;      /* load some saved text */
 }
            /* append to buf */
 void loadbuf(text,len)const char*const text;const size_t len;
-{ if(buffilled+len>buflen)     /* buf can't hold the text */
+{ while(buffilled+len>buflen)     /* buf can't hold the text */
      buf=realloc(buf,buflen+=Bsize);
   tmemmove(buf+buffilled,text,len);buffilled+=len;
 }


Si leemos el código, la función posee dos parámetros, text y len, que suponemos es un puntero a una zona de memoria (const char*) con el texto a almacenar y su tamaño (size_t). La función compara el tamaño del bufé que ya posee, buffilled, más el tamaño del texto que le llega, len, y si es superior a la capacidad del bufé, entonces procede a ampliarlo.

El problema está en que cuando utiliza la función estándar realloc, hace lo siguiente:

buf = realloc(buf, buflen += Bsize)

Es decir, le está diciendo, mueve buf a un bloque de memoria más grande (o amplía el que posee) y hazlo con el siguiente tamaño: buflen, el tamaño que ya tenía, más Bsize. ¿Qué valor posee Bsize? Pues exactamente: 128. 

¿Pero qué ocurre si buffilled + len sigue siendo mayor de buflen + 128? Que podemos, potencialmente, sobreescribir con nuestro contenido depositado en text, estructuras organizativas de la zona de memoria conocida como montículo.

De ahí que el parche (que es precisamente eso, un parche) transforme una bifurcación en un bucle. Del if pasamos a un while que no cesa de requerir memoria hasta que la condición de tamaño no sea la adecuada. 

Algo, computacionalmente muy discutible, ya que vamos a llamar a realloc tantas veces como (buffilled+len) / buflen+128). Si len es bastante grande, podemos estar dando varias vueltas en círculo hasta que alcancemos el tamaño de memoria correcto. Pero bueno, ¿es un parche, no?

Como nota curiosa, procmail dejó de ser mantenido en 2001, pero esto no ha supuesto que deje de usarse, de hecho sigue estando presente en muchas instalaciones de correo. Así que como siempre, recomendamos encarecidamente que se actualicen las versiones de procmail inferiores a la 3.22.




David García


Más información:

formail: CVE-2017-16844: heap-based buffer overflow in loadbuf()