Hace unas semanas analizamos un caso práctico de inyección de código malicioso, pero nos había quedado pendiente entender qué hacía ese código inyectado. En esos detalles nos detendremos hoy, prestando atención a las técnicas de hooking de llamadas a la API de Windows utilizadas por este malware.
Recapitulando, en el Laboratorio de Investigación de ESET Latinoamérica recibimos una muestra que inyectaba código malicioso en todo proceso que hiciera uso de User32.dll, mediante la utilización de la llave de registro AppInit_DLLs. Si debuggeamos cualquier proceso con OllyDbg, podremos observar cómo se carga y ejecuta la DLL maliciosa antes del proceso en sí. Esta DLL se encuentra empaquetada con uPolyX y, si bien no nos detendremos en el análisis de este packer, podemos comentar que parte del proceso de carga del código desempaquetado en memoria se realiza con una llamada a memset y sucesivos memcpy:
En la imagen vemos cómo las llamadas se realizan de manera dinámica, mediante el uso de GetProcAddress. En particular, se observa la copia de datos de una región de memoria a la otra, de contenido que parece estar cifrado. De hecho, si continuamos analizando el código, veremos la presencia de un bucle que descifra el contenido copiado, obteniendo un ejecutable a partir de la dirección de memoria 0x333130. Luego, si bien se realizan varias acciones tendientes a construir el ejecutable en memoria, en algún punto se transfiere el control a este código malicioso. A partir de aquí ya podemos enfocarnos en tratar de determinar qué roba este malware.
Entre las primeras instrucciones veremos que se crea un nuevo thread que ejecutará el código que se muestra en la imagen que sigue. Allí observamos una llamada a la subrutina 0x251084 y la posterior comparación contra una serie de constantes. Esa subrutina recibe como argumento el nombre del proceso en el que se ha inyectado el código y le calcula una función para obtener otra cadena.
Vemos que se está tratando de determinar si el proceso inyectado es un navegador; este malware apunta al robo de datos durante la navegación. Si no es un navegador, se termina la ejecución.
Dado que estamos debuggeando Internet Explorer, la ejecución del código malicioso continúa. Lo próximo que observaremos es que el malware espera hasta que ws2_32.dll sea cargada en memoria. Adicionalmente, se descrifran unas strings en memoria, pero luego volveremos sobre esto. Lo que sí nos interesa ahora es el código que sigue en la imagen:
Primero vemos una llamada a VirtualAlloc para reservar una porción de memoria. Luego, vemos el uso de GetProcAddress para obtener la dirección de cuatro rutinas de ws2_32.dll: getaddrinfo, gethostbyname, send y WSASend. Esas cuatro rutinas serán hookeadas para que, cada vez que sean utilizadas por iexplore.exe, la llamada sea interceptada y se ejecute código malicioso antes de la rutina en sí.
Esto se observa en las instrucciones posteriores, donde se llama a una subrutina que realiza este hooking y que he decidido renombrar como do_the_hook. Si ahora nos preguntamos qué hace do_the_hook, lo vemos en la siguiente imagen:
Si bien lo que vemos es solamente una pequeña parte del código de do_the_hook, quiero resaltar cómo se modifica cada rutina en la dirección que antes se había obtenido con GetProcAddress, de tal modo de construir un salto incondicional hacia otra ubicación. Así, se introduce un JMP en la primera instrucción de la rutina a ser hookeada. Además, vemos el uso de VirtualProtect para otorgar y revocar permisos de escritura sobre esa dirección de memoria, antes y después de realizadas las modificaciones.
En la imagen anterior vemos cómo luce la rutina getaddrinfo antes y después de ser hookeada. Se observa que las primeas 3 instrucciones han sido remplazadas por el salto incondicional. ¿Qué hay en 0x2514CB, destino del salto? Lo vemos en la siguiente imagen:
Si observamos cuidadosamente todas las direcciones de memoria involucradas, notaremos el siguiente flujo de ejecución: cuando se llama desde iexplore.exe a alguna de las rutinas hookeadas, el salto JMP en la primera instrucción nos lleva a la subrutina maliciosa. Ésta tiene dos llamadas: la primera, en 0x2512C9, ejecuta el código malicioso de robo de información; la segunda lleva a una tabla en 0x2930000 que devuelve la ejecución al getaddrinfo luego de la primera instrucción de salto. Puede mencionarse entonces que aquella región de memoria que se había reservado con VirtualAlloc es la que corresponde a esta tabla de saltos en 0x2930000.
Ya sabemos cómo se hookean ciertas llamadas en los navegadores para la ejecución de código malicioso. Sin embargo, aún no hemos contestado qué hace este malware. ¿Qué intenta robar? Si vemos el código malicioso detrás del hook a WSASend, por ejemplo, encontraremos lo siguiente:
Se observa el código que parsea la petición GET enviada por el navegador de tal modo de obtener el host. En el ejemplo vemos que el host es www.bing.com, la página de inicio que teníamos por defecto en Internet Explorer. ¿Y qué hace una vez que conoce el host? Veamos la siguiente imagen:
¿Se acuerdan que en un momento mencionamos que se descifraban unas strings en memoria? Esas strings son las que se observan en la imagen anterior; vemos diversos sitios de Rusia y Ucrania como vk.com, google.ru y google.com.ua. Luego, si el sitio visitado por la víctima se encuentra en la lista, se realiza el robo de información; por ejemplo, de los archivos temporales de la sesión.
Es importante notar que este tipo de ataque a usuarios de habla rusa ya lo hemos visto en nuestro Laboratorio, aunque con una menor complejidad, cuando estuvimos analizando una muestra que recorre Latinoamérica.
Más allá de este ejemplo, es claro que si el atacante logra introducir código aleatorio en un navegador podrá robar casi cualquier tipo de información, incluso antes de que sea cifrada, o alterar las peticiones de manera de conectarse a otros servidores o manipular la comunicación.
SHA-1 de la muestra analizada
1a3ca5b59632768dcb7c68d1b97d09750154bf22 - ctvqzym.exe
4e0f086030d7f5d3b21059bf6f313b879f130b5b - nqtbvce.dll (DLL inyectada)