DLL Hijacking - técnica simple que da mayor sigilo al ataque; entender - ISH Tecnologia

DLL Hijacking - técnica sencilla, que confiere mayor sigilo al ataque; entiéndase

Escrito por: Alexandre Siviero

El reciente ataque del ransomware REvil a través de la infraestructura de Kaseya es el último de una serie de ataques que han incorporado una técnica conocida como DLL Side-Loading. Según el marco ATT&CK de MITRE, se trata de una técnica para secuestrar el flujo de ejecución de un proceso (por lo que también se denomina DLL hijacking). Su aplicación es sencilla, más aún teniendo en cuenta otros exploits de DLL como la inyección reflejada, y proporciona mayor sigilo al ataque. Para entenderlo, primero hay que comprender qué son las DLL y cómo se cargan mediante un archivo.

Bibliotecas de enlace dinámico

Según la documentación de Microsoft, una DLL es un módulo que contiene funciones y datos que pueden ser utilizados por otros módulos. Para simplificarlo aún más, es un ejecutable igual que un PE, pero no se ejecuta por sí mismo. Su propósito es aportar un funcionamiento modular a las aplicaciones, por ejemplo ofreciendo funciones nativas de Windows a través de APIs para que los programadores no tengan que reinventar la rueda. Si tu programa va a utilizar comunicación TCP/IP, por ejemplo, no necesitas programar todo esto; basta con importar la DLL que tiene las API que necesitas (como el uso de sockets para conexiones de red) y seguir adelante.

El término dynamic-link también sugiere que existen otros tipos de enlace posibles para las aplicaciones: static-link y runtime-link.

Enlace estático

Consiste en incluir dentro del código de una aplicación absolutamente todas las funciones necesarias para que funcione. No es necesario importarlas durante la ejecución, pero esto da lugar a un software compilado de mayor tamaño y más difícil de actualizar y ajustar. ¿Por qué? Porque en lugar de arreglar sólo un módulo auxiliar que utiliza tu programa, necesitas trastear con el código fuente y recompilar para cualquier cambio.

Enlace dinámico

Las DLL se importan a la memoria de un proceso durante su inicio. Esto significa que el ejecutable en disco enumera todos los módulos y funciones correspondientes en una tabla de importación. Durante las operaciones que transfieren un ejecutable a la memoria y lo convierten en un proceso, Windows leerá esta tabla, buscará el código de las funciones solicitadas en las DLL asociadas y lo copiará en la memoria de ese proceso. Es esta tabla de importación la que lee el software que analiza ejecutables.

Enlace en tiempo de ejecución

Una alternativa al dynamic-link, o importar DLLs y funciones durante el inicio del proceso, es hacerlo durante la ejecución de la aplicación (de ahí el término runtime). Hay usos legítimos para este enfoque, como no gastar tiempo o memoria importando funciones que raramente serán utilizadas por el proceso - piensa en ello como un modelo de importación "bajo demanda". Los autores de malware son muy aficionados a este tipo de importación por otra razón: para ocultar la funcionalidad de su software malicioso. Cuando conoces suficientes DLLs del sistema, leer la tabla de importación de un ejecutable de disco te da mucha información sobre lo que hará ese programa cuando se ejecute. Nadie pone DLLs porque sí, así que si el software importa algo para interactuar con el registro de Windows, interactuará con el registro de Windows.

Para evitar que este simple tipo de análisis estático muestre lo que el malware se propone hacer, los autores sólo importan las DLL estrictamente necesarias para el funcionamiento del proceso mediante dynamic-link. Todas las funciones realmente interesantes serán enumeradas e importadas durante la ejecución.

Secuestro de DLL

Vale, hemos hablado innumerables veces de la importación, pero hasta ahora sin explicar cómo funciona realmente. Antes hemos mencionado DLLs estrictamente necesarias; una de ellas es Kernel32.dll, que proporciona una serie de APIs utilizadas para inicializar correctamente un proceso, entre ellas LoadLibraryA y LoadLibraryEx. Ambas se utilizan para importar una DLL, tanto en casos de enlace dinámico como de enlace en tiempo de ejecución (las diferencias entre ambas APIs son pequeñas e irrelevantes para el tema que nos ocupa).

Ambas APIs tienen como parámetro lpLibFileName, que puede proporcionar un PE (.exe) o una DLL (.dll) para ser cargado en el proceso. El nombre de archivo pasado a este parámetro puede o no contener su ruta completa (ubicación en disco). Si es así, el archivo de destino se leerá del directorio proporcionado y se asignará a la memoria. Pero, ¿qué ocurre si sólo se proporciona el nombre del archivo, sin su ubicación?

En estos casos, Windows buscará el archivo en el disco siguiendo un orden predeterminado, que está disponible en la documentación de Microsoft. El Modo de Búsqueda Segura de Dll está activado por defecto y afecta al orden de los lugares donde se buscará el ejecutable a importar. Con él activado, el orden es:

  1. El directorio desde el que se lanzó la aplicación
  2. El directorio del sistema (C:³³Windows³System32)
  3. La versión de 16 bits del directorio del sistema
  4. El directorio de Windows (C:³³)
  5. El directorio actual

Con el modo de búsqueda segura de Dll desactivado, el orden cambia a:

  1. El directorio desde el que se lanzó la aplicación
  2. El directorio actual
  3. El directorio del sistema (C:³³Windows³System32)
  4. La versión de 16 bits del directorio del sistema
  5. El directorio de Windows (C:³³)

PD: He omitido la 6ª entrada de la lista en aras de la brevedad y porque es irrelevante para la técnica que vamos a tratar, pero la lista completa está disponible en el enlace a la documentación que figura en el párrafo anterior.

"¡Ajá! Por la diferencia entre ambos, apuesto a que el secuestro de DLL utiliza el directorio actual". Buena suposición, pero no. De hecho, para esta técnica, el estado de la búsqueda segura es completamente irrelevante. La explotación ocurre en el primer lugar de búsqueda, el directorio desde el que se lanzó la aplicación.

En el caso concreto de REvil, Sophos mostró cómo el dropper de este ataque guarda un antiguo (y legítimo) binario de Microsoft Defender en el disco y lo utiliza como objetivo para el secuestro de DLL. A continuación, observe que normalmente la DLL MpSvc legítima (seleccionada) reside en el mismo directorio que MsMpEng.exe, uno de los binarios de Defender:

 

Así que, siguiendo el orden de búsqueda de DLL importadas sin la ruta completa del disco, está en el primer lugar donde Windows buscaría. Aprovechándose de esto, el grupo simplemente llamó a su DLL maliciosa MpSvc.dll y la guardó en el mismo directorio que el antiguo binario de Defender.

¿Por qué hacerlo así en lugar de escribir software malicioso y ejecutarlo como un proceso? Porque Defender ejecutándose en una máquina llama menos la atención.

Sigiloso, pero ¿cuánto?

Cualquier técnica que se desvíe del comportamiento normal del sistema operativo dejará huellas, incluso las sigilosas. Puedes ser discreto en un frente, pero acabar siendo ruidoso en otro. En el caso de REvil, la versión antigua de Windows Defender (msmpeng.exe) utilizada como vehículo para la carga lateral de una DLL maliciosa se guarda en C:\windows\msmpeng.exe. Esta es la primera pista de que algo no va bien: el ejecutable de Defender siempre ha residido dentro del directorio "Archivos de programa", en la carpeta Windows Defender. En Windows 10, ese directorio ha migrado a ProgramData; aunque diferentes, ninguna de las dos rutas trajo msmpeng.exe guardado directamente en el directorio de Windows.

El proceso padre de Defender también sería motivo de sospecha. El dropper usado por el grupo fue guardado en una carpeta de Kaseya (C:\KWORKING\AGENT.EXE), así que el árbol de procesos mostraría que Defender fue iniciado por... ¿un ejecutable de Kaseya? No tiene ningún sentido.

Por supuesto, hay varios matices en la detección en tiempo real de un ataque de este tipo. El análisis forense mostraría trivialmente un comportamiento sospechoso, pero en los casos de ransomware analizar después del ataque significa que el daño ya está hecho. Para echar más leña al fuego, la propia Kaseya recomendó a sus clientes que exceptuaran sus directorios de aplicaciones en antivirus de máquina. Para ser lo más claro posible: el secuestro/carga lateral de DLL es fácil de entender; no significa que sea igual de fácil de detectar y/o prevenir.

Bibliografía:

https://docs.microsoft.com/en-us/troubleshoot/windows-client/deployment/dynamic-link-library

https://news.sophos.com/en-us/2021/07/04/independence-day-revil-uses-supply-chain-exploit-to-attack-hundreds-of-businesses/

https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order#standard-search-order-for-desktop-applications

https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexa

https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya

https://github.com/sophoslabs/IoCs/blob/master/Ransomware-REvil-Kaseya.csv

https://attack.mitre.org/techniques/T1574/002/

https://news.thewindowsclub.com/new-path-windows-defender-installation-windows-10-91061/

https://www.ghacks.net/2017/12/18/microsoft-changes-windows-defender-path-on-windows-10/