Artículo escrito por David Sánched Lavado

En este post vamos a ver cómo realizar un análisis del código malicioso que se está utilizando en los Exploit Kits actuales.

Hay muchas formas de analizar este tipo de código, incluso hay herramientas que realizan gran parte del análisis de forma automática. Pero, como investigadores, nos gusta ver como funcionan las cosas y por este motivo vamos a analizar este código sin utilizar ninguna herramienta adicional más que un editor de texto y un navegador web.

Mi objetivo es poner las bases para aprender a eliminar las diferentes capas de ofuscación que puede tener un código malicioso programado en JavaScript. Paso a paso iremos eliminando estas capas hasta llegar a la capa final donde se encuentra la lógica para explotar la vulnerabilidad.

IMPORTANTE: Recomiendo realizar este tipo de análisis en una máquina virtual aislada en una red de laboratorio que esté dedicada exclusivamente a este tipo de investigaciones para evitar posibles infecciones no deseadas.

CONCEPTOS BÁSICOS

Generalmente el código malicioso es utilizado para explotar vulnerabilidades en los navegadores web y en lectores de ficheros PDF como Adobe Reader o Foxit. Este código malicioso normalmente está escrito utilizando el lenguaje javascript. Por lo general suele estar ofuscado en una o varias capas. Las técnicas de ofuscación de código se utilizan generalmente para dificultar la comprensión de la funcionalidad del código al investigador, evitar la creación de detecciones por firma o evadir las herramientas de análisis automático. El funcionamiento a grandes rasgos es muy sencillo, cada una de estas capas llama a otras funciones que van desofuscando código que llegara a formar parte de la siguiente capa y así hasta llegar al código final.

Este código final, está divido generalmente en 2 partes. La primera tiene como objetivo detectar la versión del navegador web y los complementos o plugins instalados (como Adobe Reader, Apple Quicktime o la máquina virtual de Java). La segunda parte se encarga de elegir que vulnerabilidad va a ser explotada en base a la información recogida en la primera parte.

ANÁLISIS DEL CÓDIGO

La siguiente imagen es una captura del código malicioso que vamos a analizar en este artículo:

Como vemos, el código esta compuesto por varios objetos  HTML. Pero si ponemos un poco de atención en el mismo, vemos que en el contenido de estos objetos podemos identificar varias cosas: Primero: el valor del atributo id para cada uno de estos objetos tiene el formato “<número>+CytobimusubekUda”, donde “<número>” es un valor entero 0 y 1230 de forma consecutiva. Segundo: el valor de cada uno de estos objetos es una cadena sin aparente significado de más o menos de la misma longitud, donde se puede apreciar repetidas veces la palabra Add en su interior.

Estos detalles que hemos mencionados nos dejan ver que existe la posibilidad de que se utilice el atributo id como índice (debido a los números consecutivos) dentro de un ciclo para poder recorrer todos los objetos HTML y desofuscar el contenido que hay en cada uno de ellos para ir componiendo una nueva capa del código. Comencemos con el análisis.

FORMAT CODE

Lo primero que suelo hacer antes de ponerme a examinar un código javascript es utilizar la opción Format Code de la herramienta Malzilla. Esta opción nos formatea el código como si lo hubiésemos escrito en un programa como Visual Studio. Aunque sencilla, esta fase es muy importante ya que en muchas ocasiones el código no estará bien formateado y se hará difícil su comprensión.

Esta tarea la podemos hacer de forma manual, línea por línea, pero corremos el riesgo de equivocarnos y tardar mucho tiempo, que a mi entender no es necesario invertir en esta primera fase. Por ejemplo el código malicioso que vamos a analizar tiene casi unas 600 líneas entre código script y código HTML.

Malzilla es una excelente herramienta que nos permite realizar muchas cosas de forma automática en este tipo de análisis, no obstante como he mencionado anteriormente, nosotros lo vamos a realizar de forma manual.

Código sin la opción “Format Code”
Código sin la opción “Format Code”

Código bien formateado con la opción  “Format Code” de la herramienta Malzilla
Código bien formateado con la opción “Format Code” de la herramienta Malzilla

LA HERRAMIENTA

El siguiente paso será pasar el código Javascript bien formateado al editor de Texto que vayamos a utilizar en el análisis. Cualquier editor de texto que disponga de las siguientes opciones básicas será suficiente:

  1. Identificación el código JavaScript: Ayuda en la visualización del código y detección de funciones propias del lenguaje de forma rápida.
  2. Opciones de buscar y remplazar cadena: Una forma de evitar errores a la hora de renombrar los nombres de las funciones y variables.
  3. Pestañas: Esto es opcional,  permite trabajar de forma rápida cuando estemos analizando código en diferentes archivos.

LOCALIZANDO LA FUNCION DE INICIO

Actualmente tenemos 96 líneas de código javascript y más de 500 líneas de código HTML las cuales iremos reduciendo según vayamos eliminando las diversas capas de ofuscación. Lo primero que tenemos que hacer es detectar el código javascript que se ejecuta cuando el navegador carga la página web maliciosa y seguir paso a paso analizando las demás funciones en su orden de ejecución.

El primer paso a realizar en cada función será:

  1. Simplificar el código a analizar
  2. Renombrar los nombres de las funciones y variables, para que el código sea más entendible.

Para ello primero revisamos la parte del código HTML y si no hay ningún objeto HTML que llame a alguna función javascript pasaremos directamente a analizar el código localizado entre los tag <script> y </script>. En esta zona tenemos que localizar las instrucciones de  código que no estén dentro de la definición de una función, pues este código será el que se ejecute de forma automática al cargar la página web por el navegador.

En la siguiente captura hemos localizado dicho código entre las líneas 81 y 89 ambas incluidas. También podemos ver que la función HazakeduhaQurenepenus() será la primera en ejecutarse (las 3 anteriores no realizan ninguna acción importante)  y por lo tanto es la primera función con la que comenzaremos nuestro análisis.

Código que se ejecuta al cargar la página (recuadrado en rojo)
Código que se ejecuta al cargar la página (recuadrado en rojo)

SIMPLIFICAR EL CÓDIGO Y HACERLO ENTENDIBLE

Simplificar y hacer entendible el código. Esta es una de las partes más laboriosas y más importantes. En ella tenemos que estudiar el funcionamiento de casi cada una de las instrucciones que hay en del código javascript que vamos a analizar y modificarlas para crear un código más entendible y sencillo para el análisis.

MUY IMPORTANTE: En la modificación del código no hay que cambiar el resultado final que daría el código original.

Como hemos comentado, comenzaremos con la función HazakeduhaQurenepenus() que vemos que tiene el siguiente aspecto.

Función “HazakedubaQurenepenus()” antes del análisis
Función “HazakedubaQurenepenus()” antes del análisis

En el código de la función que se esté analizando hay que prestar especial atención a las funciones que no son propias del API de javascript, es decir, las funciones que habrá programado el usuario. Tenemos que resolver el valor que éstas nos van a devolver para poder continuar con el análisis de la función que estamos investigando.

En el código anterior la incógnita a resolver es la función PypiwIgo() que tiene el siguiente código:

Si le echamos un pequeño vistazo y hemos trabajado con el lenguaje javascript, podemos darnos cuenta que la función va a devolver la cadena getElementById cada vez que se la llame. Con esto en mente y sabiendo que la variable DeqesedaDakonyqev hace referencia al objeto document ya podemos realizar nuestro primer cambio para que el código sea más entendible. El resultado es este:

Función “HazakedubaQurenepenus()” después del análisis
Función “HazakedubaQurenepenus()” después del análisis

También he modificado el nombre de varias variables y el de la porpia función analizada por func_decrypt_01, esto parece atrevido, pero la experiencia analizando este tipo de funciones te da la facilidad de reconocer ciertas estructuras de código  al primer vistazo.

Ahora nuestro siguiente objetivo en este análisis es conseguir el valor que va a devolver dicha función en la variable buffer. Para ello, separamos la función del código original y la ejecutamos de forma aislada. Previo a esta ejecución, debemos revisar si la función que vamos a analizar no va a necesitar ningún valor externo o algún dato calculado por otra función del código asignado en alguna variable global que se use en el código que estamos analizando. Porque de lo contrario, primero tenemos que calcular dicho valor para luego poderlo sustituir dentro del código que vamos a aislar. Esto es muy importante, si no lo hacemos de este forma es muy posible que no podamos ejecutar el código de forma separada, porque el navegador web nos mostrará algún error al cargar la página y no podrá ser ejecutado o simplemente no se comportará de la misma forma que si se hubiese ejecutado con todo el código malicioso.

Veamos este hecho con un ejemplo en el código que estamos analizando. La siguiente instrucción hace referencia a un valor externo que está localizado en el objeto HTML DasuRokyduconiwidy.

string_01 = document.getElementById(“DasuRokyduconiwidy”).innerHTML;

El valor resultante es asignado a la variable string_01. Dado que esta variable se utiliza dentro del código, debemos resolver su valor. En caso contrario, si la variable estuviera para intentar confundir al usuario, entonces la podríamos eliminar de nuestro código.

Esta técnica de utilizar datos en objetos HTML y hacer referencia a ellos desde el código javascript es muy utilizada para ofuscar código separándolo por partes y evitar el análisis automático de ciertas herramientas que no son capaces de interpretar las conexiones entre el código javascript y el código HTML produciendo un fallo en el resultado.

Esta misma técnica de anti-análisis también se utiliza en los ficheros PDF maliciosos, su técnica se basa en realizar llamadas a las propias funciones javascript del API de Adobe PDF que tampoco son interpretadas todavía por muchas herramientas de análisis.

Bien, lo primero que tenemos que hacer es localizar el objeto DasuRokyduconiwidy. Una vez localizado asignaremos su valor a la variable string_01 dentro del código script que hemos creado y sustituiremos la instrucción return buffer por la creación de un objeto TEXTAREA donde vamos a mostrar el contenido de la variable buffer una vez que ejecutemos nuestro nuevo código en el navegador web.

Valor del objeto DasuRokyduconiwidy y linea de código a sustituir
Valor del objeto DasuRokyduconiwidy y linea de código a sustituir

En la siguiente  captura vemos el código ya simplificado incluyendo la modificación de la instrucción “return buffer” por la creación del textarea en tiempo de ejecución.

Nuevo código creado para ver el resultado de la variable buffer
Nuevo código creado para ver el resultado de la variable buffer

Una vez que tenemos el código lo abrimos en el navegador web para ver el resultado de la función.

Valor de la variable buffer
Valor de la variable buffer

Como podemos observar y seguramente hayamos identificado, el resultado devuelto es una cadena compuesta por la concatenación de varios nombres de funciones de la propia API de javascript. Una vez resuelto el valor que se obtiene al llamar a la función func_decrypt_01 renombraremos la variable GuzoZaq que es la variable a la que se le asigna el valor devuelto. Por ejemplo le llamamos concat_func_string, le asignamos el valor obtenido en el textarea quedando el código de la siguiente forma.

Variable concat_func_string con el valor ya resuelto
Variable concat_func_string con el valor ya resuelto

Continuamos analizando el código que se ejecuta al cargar la página web y vemos que la siguiente función que tenemos que analizar es NupUr(). Dentro de ésta se  llama a la función HaynubOguf() que habrá que resolver antes de continuar con el análisis del código. HaynubOguf() es una función muy simple que devuelve la cadena substr, una función javascript que se encarga de obtener una subcadena a partir de otra cadena. Por lo tanto renombramos la función HanynubOguf() a func_substr() y vemos que la función NupUr() queda con el siguiente aspecto.

Función NupUr() a analizar
Función NupUr() a analizar

Ahora que ya tenemos “resueltas” todas las partes del código de la función, pasamos a transformar su código a una anotación más legible. La técnica es ir resolviendo los nombres de las funciones que están entre corchetes desde dentro hacia fuera.

Como vemos en el código se utiliza la variable concat_func_string, si recordamos esta variable hace referencia a una cadena que esta compuesta por múltiples nombres de funciones del API javascript. Junto con ella se está utilizando la variable substr. Esto nos hace ver que se va a extraer parte de la cadena para obtener el nombre de la función que posteriormente va a ser utilizada en el código.

Original Resuelta
[func_substr()](63,14) .substr(63,14)
[concat_func_string.substr(63,14)] getElementById
[func_substr()](1736/56,585/65) [func_substr()][31,9] → .substr(31,9)
[concat_func_string.substr(31,9)] .InnerHTML

Y como resultado obtenemos el siguiente código:

Función NupUr() ya resuelta
Función NupUr() ya resuelta

Según vayamos resolviendo las demás  funciones nos iremos haciendo una idea de las acciones que van a realizar otras funciones, simplemente con observar por encima el código, ya que tendremos muchas incógnitas que habrán sido resueltas al haber analizado otras funciones. Esto nos ayudará a avanzar más rápido en el análisis de nuevas funciones y podremos ir eliminando las capas de ofuscación del código de forma más sencilla.

Como último ejemplo vamos a analizar la función MivoJaqugutec()

Función NivoJaqugutec sin resolver
Función NivoJaqugutec sin resolver

A simple vista, lo primero que podemos identificar en el código, es un ciclo que recorre todos los objetos HTML que va guardando su valor concatenando en la variable PofUhicehofudilysuwe, la cual, después de terminar el ciclo, será devuelta por la función.

Bueno, con lo aprendido hasta entonces ya sabemos lo que tenemos que hacer. Separaremos la función del código original, resolveremos sus incógnitas y renombraremos sus variables para que el código sea más entendible y nos marcaremos como objetivo conocer  el valor de la variable PofUhicehofudilysuwe en la instrucción return.

Codigo para obtener el valor de la variable PofUhicehofudilysuwe renombrada a buffer
Codigo para obtener el valor de la variable PofUhicehofudilysuwe renombrada a buffer

Una vez que ejecutamos el código en el navegador web obtendremos el siguiente resultado:

De la misma forma seguiremos transformando el resto de funciones que hay en el código que nos queda por analizar. El resultado final es bastante interesante, se ha pasado de 96 líneas de código javascript y unas 500 líneas de código HTML a tan sólo 2 líneas de código javascript donde podemos ver la función eval() y unescape().

Estas 2 funciones normalmente están declarando la ejecución de una nueva capa de ofuscación ¿habremos llegado a nuestro objetivo? ¿Será la última capa donde se lanza la vulnerabilidad? Veamos que nos encontramos en ella.

ACCESO AL CÓDIGO FINAL

En las 2 líneas de código a las que finalmente hemos llegado, la variable payload hace referencia una cadena codificada en formato unicode de 55.496 caracteres. Tras la ejecución de su contendido con la instrucción eval( unescape(payload) ) llegamos a la capa final del código malicioso.

En esta última sección del artículo sólo analizaremos las partes genéricas que nos encontraremos en otros códigos maliciosos.

En la siguientes 2 capturas vemos unas instrucciones que son muy utilizadas tanto en código legítimo como en código malicioso, pero ambos con objetivos totalmente diferentes. Mientras que en el código legítimo se utiliza por motivos de diseño, en el código malicioso se utiliza con el objetivo de conocer el entorno del usuario para explotar la vulnerabilidad más adecuada.

En estas 2 capturas que hemos hecho del código malicioso que estamos analizando, vemos como el programador utiliza el método userAgent del objeto navigator. Este objeto representa al navegador web del usuario, para identificar qué navegador está utilizando el usuario. Como vemos (aunque no he puesto todo el código) en el caso de Internet Explorer verifica si la versión es inferior a la 6.

Mas adelante vemos en el código cómo también intenta identificar algún que otro plugin instalado en el navegador.

En este código el usuario decide crear un nuevo objeto identificado por el CLSID CA8A9780-280D-11CF-A24D-444553540000 y lo instancia en la variable Pdf1. Aunque por el nombre de la variable nos podemos hacer una idea del tipo de objeto que desea crear vamos a verificarlo. Para ello utilizaremos la herramienta de regedit.exe para buscar el CLSID en el registro de Windows.

Descubrimos que nuestras suposiciones eran ciertas, el CLSID hace referencia al ActiveX de Adobe Acrobat/Reader.  El programador crea este objeto con la única intención de verificar que el usuario tiene instalado el programa Adobe Acrobat o Adobe Reader y qué versión está utilizando para poder escoger el fichero PDF malicioso creado para explotar alguna vulnerabilidad de la versión detectada.

Para poder determinar la versión del programa de Adobe utiliza el método GetVersions() del objetivo creado como lo podemos en la primera instrucción del siguiente código.

En la parte final del código vemos cómo se selecciona el PDF más adecuado para explotar la vulnerabilidad. Si es valor de la variable lv es superior o igual a 800 (identificando posiblemente la versión 8 ) el código llamará a la función fghjdfgxbz pasándole como parámetro la cadena  “d0456d.pdf”, en caso contrario se pasará como parámetro la cadena “07dd5d.pdf”. La función fghjdfgxbz simplemente crea un objeto IFRAME en tiempo de ejecución que apunta al valor que se le ha pasado como parámetro. En tiempo de ejecución esto se traduce a que el navegador web abrirá el fichero PDF malicioso que ha sido diseñado para explotar una vulnerabilidad que posiblemente no ha sido parcheada en el sistema.

En este artículo hemos puesto los cimientos para analizar y desofuscar paso a paso las diferentes capas de uno de los actuales códigos maliciosos que están siendo utilizados en los actuales kits de explotación utilizando un editor de texto, un navegador web y algunos conocimientos de los lenguajes JavaScript y HTML. Además hemos podido analizar parte del código final con el objetivo de mostrar algunas de las técnicas que se utilizan para detectar las diferentes versiones de los navegadores web y plugins instalados. Happy hunting!!