En el ultimo tiempo hemos recibido en el Laboratorio de Análisis e Investigación de ESET Latinoamérica diversas muestras de malware que simulan ser archivos legítimos de diversos formatos como PDF,DOC odocumentos HTML. Estos no son los únicos documentos afectados pero si los mas comunes, por tratarse de documentos altamente usados y estandarizados. La forma que ejecutan códigos maliciosos pueden ser muy variadas, pero por lo general hacen uso de algún exploit para lograr corromper la memoria, y así forzar la ejecución de código malintencionado.

En las siguientes lineas analizaremos una muestra que es detectada por ESET NOD32 Antivirus como PDF/CVE-2010-0188. La vulnerabilidad anteriormente mencionada es relativamente antigua, concretamente data de febrero de 2010.

La única razón por la que esta muestra se sigue difundiendo es porque está dirigida a usuarios de Adobe Reader, sin duda alguna el lector de archivos PDF más difundido. Es relativamente común encontrarse con versiones viejas de este lector, pero las versiones que nos competen en el día de hoy, están comprendidas entre la versión 8.0 a la versión 9.3. Estas versiones poseen un bug que dispara la ejecución de código arbitrario al tener incrustada una imagen TIFF especialmente manipulada.

En esta primera etapa, trataremos de desglosar los diferentes fases que contempla el reto de análisis para comprender el accionar del código malicioso y, en un futuro post, detallaremos cómo se explota la vulnerabilidad. Entonces, ¿cómo se realiza el análisis?

Primer acercamiento

Para comenzar, analizamos el archivo PDF con cualquier editor de texto. En este caso utilicé WordPad, para ver la estructura que tiene el archivo:

Los archivos PDF puede contener cualquier flujo de bytes representados con diferentes encoders, estos se encuentran entre los tags "stream" y "endstream". Lo primero que llama la atención de este exploit en particular, es que no contiene código Javascript. En la imagen se observa en naranja que posee un archivo embebido que está codificado con FlateDecode. Algunos de otros codificadores que pueden utilizarse son:

  • ASCIIHexDecode
  • ASCII85Decode
  • LZWDecode
  • RunLengthDecode
  • CCITTFaxDecode
  • JBIG2Decode
  • DCTDecode
  • JPXDecode
  • Crypt

Existen multitud de herramientas para extraer estos archivos embebidos (varias de estas fueron creadas por Didier Stevens), pero en esta ocasión no haremos uso de herramientas de terceros, sino que trataremos de salir airosos del reto solo aplicando sentido común y programando nuestra propia artillería :). La técnica expuesta solo será valida para FlateDecode.

Este encoder en particular utiliza Zlib para comprimir el flujo de bytes. La cabecera Zlib solo consta de 2 bytes y 4 bytes al final para chequeo de integridad. Si miramos el header con un editor hexadecimal podemos ver el texto "stream", un enter y después el "magic number" de zlib:

Posteriormente, se presenta el footer:

Los bytes marcados corresponden a un checksum que usa internamente zlib, luego tenemos un "enter" y el texto "endstream" finalizando el flujo de bytes. Todo lo que esta entre la cabecera y el pie son los datos codificados con zlib. Si nos informamos un rato de la mano de Google notaremos cómo en varias paginas oficiales del proyecto se hace referencia a la compatibilidad entre zlib y gzip.

Gzip al igual que Zlib se basa en el algoritmo Deflate. Nuestro objetivo sera crear un archivo '.gz' funcional a partir de estos bytes, para poder abrirlo con cualquier descompresor, como por ejemplo 7-Zip, para eso vamos a comprimir el mismo archivo con los dos compresores, en busca de similitudes. Como muestra de nuestra creatividad e innovación, el string sera "hola mundo" :):

Subrayado con naranja tenemos los bytes de Deflate, lo único que cambia es la cabecera. En Gzip tiene la siguiente forma:

  • Magic number de Gzip: "x1fx8b",
  • compresión Deflate: "x08",
  • los siguientes 7 bytes tienen información irrelevante (fecha de creación, nombre, etc.) que pueden estar rellenos con bytes NULLs.

Este compresor también tiene un footer que contiene el checksum y tamaño del archivo antes de ser comprimido.

Pasando de un formato a otro

Para lograr este cometido, tendríamos que extraer los bytes Deflate y ponerle la cabecera gzip, definiendo cualquier tamaño y CRC32 (ya que no lo sabemos). El siguiente script se encarga de eso:

El script abre el archivo PDF que se le pasa como primer argumento, extrae los bytes deflate y crea un Gzip definido en el segundo argumento, con un checksum 0xDEADC0DE y un tamaño de 11 bytes.

Una vez ejecutado, nos crea el archivo 'example.gz' y procedemos a abrirlo con algún compresor:

Como era de esperar, no pasamos el chequeo de integridad, debido a que el CRC32 del archivo descomprimido no es 0xDEADC0FE. Para solucionar esto, en el laboratorio de Análisis e Investigación de ESET Latinoamérica desarrollamos una pequeña herramienta que extrae el CRC correcto al momento de comparar dichos datos.

Ahora transferiremos esos bytes al CRC32 definido en el archivo example.gz:

Guardamos los cambios y intentamos abrirlo nuevamente:

Esta vez pasamos con éxito el chequeo de CRC y extrajimos un archivo XML. La zona que marcamos con verde corresponden a una codificación en base64. La siguiente captura de pantalla muestra el final de la codificación:

No hay una metodología definida para notar esto, y solo la experiencia nos puede ayudar en este caso, pero como pauta podemos decir que:

  • solo usa los caracteres "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
  • termina con un  signo '='.

Ahora usaremos cualquier decodificador de base64 que hay online para ver con que nos encontramos:

Al decodificarlo obtenemos el siguiente archivo '.bin':

La cabecera "x49x49x2A" corresponde a la imagen TIFF encargada de explotar el sistema. Hasta aquí llegamos el día de hoy, en el próximo articulo veremos que shellcode ejecuta y como lo hace.

Javier Aguinaga
Malware Analyst