Amenaza Silenciosa III – Hooking (Teoría)

Previously on Amenaza silenciosa… vimos como inyectar una DLL en un proceso. Esto sólo era el primer paso. En el post de hoy veremos cómo hookear una función.
Antes de seguir, recordemos los pasos necesarios para imitar el mecanismo de persistencia de Dridex y para qué necesitamos hookear una función:

  • Ejecución de una DLL.
  • Borrado de la DLL y del valor en la clave del registro (si existe).
  • Inyección de la DLL en el proceso objetivo.
  • Hook de la función que se encarga de terminar el proceso.
  • Cuando se cierra el proceso, guardarse en disco y persistir en una clave de registro.

Marcados en negrita están la partes que ya vimos en el post anterior, hoy nos centraremos en como hookear la función que se encarga de terminar el proceso.
La idea detrás de esto es modificar el comportamiento de la función que se encarga de terminar un proceso y hacer que antes de terminar el proceso guarde nuestra DLL en el disco y escriba una clave en el registro para que se ejecute cuando el sistema se reinicie. Una vez hecho esto, ya puede proceder a cerrar el proceso.

¿Qué es el hooking?

El hooking es una técnica de intercepción de llamadas a funciones muy extendida en el mundo de la informática. En realidad, el hooking vale para modificar el comportamiento de una función, esto, como todo en la vida, se puede usar con fines más o menos legítimos. Algunos ejemplos de los posibles usos son: instrumentación de binarios, ingeniería inversa, protección de sistemas, ocultación de procesos (rootkit), etc.
Veamos como funciona:
funct call

Pre-hook

Cuando un proceso llama a una función, lo normal es que se pase el flujo de ejecución directamente a esta función y, cuando esta función se termine de ejecutar, la función devolverá el flujo de la ejecución justo después de donde se realizó llamada.
Hook

Post-hook

Cuando se hookea esta función, lo que estamos haciendo es redirigir la llamada de esa función a nuestra propia función, de esta forma podemos, modificar ligeramente el comportamiento de esa función o incluso hacer que haga cosas completamente distintas.
A continuación os dejo un pequeño video para que veáis un ejemplo de las cosas que se podrían hacer con técnicas de hooking.

Técnicas de hooking en Windows

Hay tres maneras de hookear una función en Windows:

  • Usando la función SetWindowHook.
  • In-line hooking.
  • IAT hooking

SetWindowHookEx
La manera más simple para mi de hookear es utilizando la función que provee la API de Windows SetWindowHookEx. Esta función permite la monitorización de distintos eventos del sistema y permite muy fácilmente poner un hook en todos los procesos del escritorio.
Si estáis analizando un fichero sospechoso y veis esta función en la Import Table, es muy posible que se trate de un keylogger, unos de los usos más extendidos del uso de esta técnica de hooking en malware.

In line hooking
Esta técnica modifica el código de la función hookeada introduciendo un jmp al principio de la función. Es decir cuando el programa llama a la función, esta se ejecuta y, antes de procesar nada, salta a donde tengamos nuestra función modificada y prosigue su ejecución en nuestra función.
prehook

Pre-hook

Posthook

Post-hook

IAT hooking
IAT hooking es una técnica similar a la anterior, pero en lugar de sobrescribir el código de la función, lo que se hace es modificar la dirección de la función en la Import Address Table (IAT) del proceso. A continuación continuaremos con una explicación más en profundidad de esta técnica, ya que es la que he elegido para usar en la DLL.

¿Qué es la IAT?

Los ficheros ejecutables de Windows, o PE (Portable Executable), tienen una estructura que permite al sistema operativo entender estos programas. Esta estructura contiene todo lo que se necesita para ejecutar el binario e información sobre el fichero: dirección del entry point, imágenes y otros recursos que el programa puede necesitar, fecha de compilación y muchas cosas más. Estos datos se encuentran almacenados en las cabeceras del fichero PE.
Cuando un programador incluye una DLL del sistema en su programa, normalmente esa DLL no es parte del binario pero aun así el programa utiliza las funciones de estas bibliotecas enlazadas dinámicamente.

#include 

En lugar de llevar todas bibliotecas incluidas el binario, el cargador de procesos de Windows (Windows Loader), al ejecutar un PE, mapea el ejecutable en memoria y carga en el espacio de memoria del proceso todas las DLL que este utiliza, entre otras cosas.
El proceso además crea una lista de la funciones y su posición en la memoria tiempo de ejecución. Esta lista es conocida como Import Address Table (IAT).

Si se sigue el esquema en este documento, se puede encontrar la IAT donde marca la siguiente imagen:
PE Extructure
Será importante saber donde se encuentra exactamente porque en el futuro necesitaremos recorrer esta estructura en nuestra DLL para poder llegar a la IAT.

Hookeando la IAT

Cuando llamamos a una función desde cualquier lenguaje de programación, lo que pasa es que se está ejecutando la instrucción call en ensamblador. Cuando pasamos un binario por IDA, radare2 o cualquier otro desensamblador en las llamadas a funciones veremos algo parecido a esto:

.text:010031E2                 lea     eax, [ebp-68h]
.text:010031E5                 push    eax
.text:010031E6                 call    ds:GetStartupInfoA

IDA

0x1000010ca   je 0x1000010d6
0x1000010cc   mov rdi, rax      
0x1000010cf   call sym.imp.atoi

Radare2

O a esto si la función no es parte de API de Windows y el programa ha sido compilado sin símbolos:

.text:010016AF                 call    sub_10016C6

IDA

0x100001085   call 0x100004401

Radare2

Cuando se ejecuta la función call, lo que está pasando en realidad es que el procesador salva una serie de datos que le permitirán devolver el flujo de ejecución al punto en que lo dejó, y salta a la dirección de memoria donde se encuentran las instrucciones de esta función .
Cuando un PE invoca a una función, este va a buscar esa función a la IAT, que se ha cargado con las direcciones de las funciones en el espacio de memoria del proceso al comienzo de la ejecución, y saltará a ejecutar la función en la dirección en la que la IAT le diga que está esta función mapeada. Si somos capaces de modificar la dirección de la función que queremos hookear en la IAT y cambiarla por la de nuestra función, estaríamos tomando control sobre la ejecución de esa función. La siguiente imagen ilustra esta idea.
Prehook

Pre-hook

Cuando el cargador de procesos de Windows ejecuta el proceso, la IAT se popula con las direcciones de las funciones y la función Foo se encuentra en la dirección de memoria 0x22222222.
Posthook

Post-hook

Tras hookear la función Foo y modificar su dirección en la IAT haciendo que Foo en realidad apunte a MyFoo, podremos modificar el comportamiento de las llamadas a Foo. Si además hemos guardado la dirección de Foo en una variable, luego podremos ejecutar Foo si queremos invocando directamente su dirección de memoria, que es lo que queremos hacer con la función encargada de finalizar el proceso.

Hasta aquí la parte de teoría de este artículo, en el siguiente continuaremos con la práctica. Como siempre, aquí os dejo algunas referencias y nos vemos en la siguiente entrega de Amenaza Silenciosa.

Referencias

PE:
Esquema de la estructura de un PE [PDF]
PE Walkthrough
An In-Depth Look into the Win32 Portable Executable File Format (Matt Pietrek) [PDF]
PE @ wiki.osdev.org

Hooking
API Hooking and DLL Injection on Windows @ infosecinstitute.com
API hooking revealed @ codeproject.com

IAT Hooking
Understanding Imports @ sandsprite.com
Userland rootkits: Part 1, IAT hooks @ adlice.com
Injective Code inside Import Table @ ntcore.com
IAT Hooking explained @ guidedhacking.com

Inline hooking
Inline hooking for programmers @ malwaretech.com [part 1] [part 2]
http://www.malwaretech.com/2015/01/inline-hooking-for-programmers-part-2.html

Otros
Understanding RVAs and Import Tables @ sunshine2k.de
SetWindowsHookEx @ MSDN

Amenaza Silenciosa II – Inyección de DLL

En el capitulo anterior… vimos algunas formas de hacer que la persistencia de las amenazas pase algo más desapercibida. La primera propuesta de la que hablé estaba basada en el malware Dridex. Esta segunda entrega de la saga cubrirá la primera parte del mecanismo de persistencia de Dridex: Inyección de DLL.

¿Qué hace Dridex?

En el artículo anterior hablé sobre el mecanismo de persistencia de Dridex. Ese mecanismo que describí, se puede resumir en los siguientes pasos:

  • Ejecución de una DLL.
  • Borrado de la DLL y del valor en la clave del registro (si existe).
  • Inyección de la DLL en el proceso objetivo.
  • Hook de la función que se encarga de terminar el proceso.
  • Cuando se cierra el proceso, guardarse en disco y persistir en una clave de registro.

En este post me centraré en la parte de la inyección de una DLL en otro proceso. Esta parte es la más interesante del proceso para mi y, aunque no es especialmente compleja, hay pequeños detalles que pueden hacer fallar la inyección y hacerte perder horas dándote con la cabeza contra un muro.

¿Qué es una DLL?

DLL son las siglas en inglés de Biblioteca de Enlace Dinámico (Dynamic-Link Library). Este es el nombre con el que se conocen a los archivos de los sistemas Windows que contienen código que otros programas cargan bajo demanda para realizar determinadas acciones. Las DLL que más se usan suelen ser las que te permiten interactuar con funciones internas del sistema operativo, por ejemplo la biblioteca Kernel32.dll.
Como los ficheros .exe, las DLL siguen el formato ejecutable de los sistemas Windows conocido como PE (Portable Executable). Ahondaremos en el formato más adelante en esta serie de posts, de momento para entender las DLL basta con saber que dentro de la estructura de los PE hay una tabla de importaciones y otra de exportaciones (import table y export table).
Cuando importamos una biblioteca en un programa ganamos acceso a las funciones que esta exporta, es decir, a las funciones que están en la export table de la DLL. Las funciones que no están en la export table no pueden ser ejecutadas por otros programas, permanecen privadas para la DLL.
exportsdump

Ejemplo de funciones exportadas por la biblioteca actxprxy.dll

Creando una DLL

Lo primero que necesitamos para inyectar una DLL es, obviamente, una DLL. Hay mucha literatura sobre cómo escribir una DLL, por lo que no me voy a extender mucho en los detalles y me voy a centrar en el código en sí.
Lo que he hecho ha sido crear una biblioteca muy simple, a la que he llamado HelloWorldDLL.dll, que exporta sólo una función: HelloWorld. Esta función simplemente muestra un mensaje con el texto Hello World.

extern "C" __declspec (dllexport) void __cdecl HelloWorld()
{
	MessageBox(NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
}

Las DLL tienen una función principal, llamada DllMain, que principalmente se debe usar para inicialización de la DLL y las acciones que se pueden realizar dentro de esta función son limitadas.

Una de las cosas que se pueden hacer es realizar acciones dependiendo de la razón por la que la función ha sido llamada. Para esto sirve el código que aparece en el DllMain de HelloWorldDLL.dll:

switch (ul_reason_for_call) {
	case DLL_PROCESS_ATTACH:
		HelloWorld();
		break;
	case DLL_PROCESS_DETACH:
		HelloWorld();
		break;
	case DLL_THREAD_ATTACH:
		break;
	case DLL_THREAD_DETACH:
		break;
}

Este código llama a la función HelloWorld cuando la DLL se acopla y desacopla de un proceso. Eso significa que por lo menos la función HelloWorld se ejecutará cuando inyectemos la DLL y cuando se cierre el programa.
Al final la DLL quedaría como sigue:

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"

extern "C" __declspec (dllexport) void __cdecl HelloWorld()
{
	//Show a message box with the text "Hello World"
	MessageBox(NULL, TEXT("Hello World"), TEXT("In a DLL"), MB_OK);
}


BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	//Different behaviors depending on the reason why DllMain is called
	switch (ul_reason_for_call) {
		case DLL_PROCESS_ATTACH:
			HelloWorld();
			break;
		case DLL_PROCESS_DETACH:
			HelloWorld();
			break;
		case DLL_THREAD_ATTACH:
			break;
		case DLL_THREAD_DETACH:
			break;
	}

	return TRUE;
}

Como ya dije anteriormente se trata de una DLL muy simple, si se llama a la función HelloWorld saca una caja de texto, al ser esta la única función en la export table (dllexport) esta podrá ser llamada tanto desde fuera como desde dentro de la DLL.

Inyección

Como ya dije en el post que daba inicio a esta serie, la idea de estos post es que haya muchas pruebas de concepto (PoC). Una de las razones por la quería escribir estos post era la posibilidad de utilizar ciertas herramientas o técnicas que llevaba un tiempo queriendo probar. Una de estas técnicas es la inyección de DLLs.
La principal razón por la que quiero probar esta técnica es que su uso en malware está muy extendido y esperaba aprender algo al hacerlo yo en lugar de tan solo analizar cómo lo hacen los escritores de malware.
La idea final de esta técnica consiste en ejecutar el código de una DLL en el contexto de un proceso objetivo.
Para esta PoC voy a utilizar Python y la biblioteca ctypes, la cual permite el acceso a la API de Windows si tener que preocuparnos demasiado de tipos de datos, punteros, etc.
Ctypes es una de esas tecnologías que siempre he querido tocar pero que nunca he tenido la oportunidad, así que aprovecho para usarla ahora que en la siguiente entrega será necesario escribirlo usando C++ para crear la DLL completa.
Para inyectar una biblioteca, queremos ejecutar la función CreateRemoteThread. Esta función se usa para iniciar un hilo en un proceso desde otro proceso distinto. Utilizando esta función, podremos ejecutar la función LoadLibrary en el proceso objetivo y así cargar la DLL en el proceso remoto, consiguiendo así la inyección.
La función LoadLibary recibe como parámetro el nombre de la biblioteca que se tiene que cargar. Para poder usar esa función en el proceso remoto, necesitamos escribir la ruta de nuestra DLL en el espacio de memoria de ese proceso. Para esto se utilizan las funciones VirtualAllocEx y WriteProcessMemory.
VirtualAllocEx se utiliza para reservar memoria en un determinado proceso. Puedes encontrar más detalles sobre esta función en la documentación de la API de Windows en MSDN, en nuestro ejemplo pasamos un handle del proceso objetivo, el tamaño del buffer que necesitamos y algunos flags necesarios:

lpBaseAddress = kernel32.VirtualAllocEx(hProcess, None, len(dllPath), 
	VIRTUAL_MEM, PAGE_READWRITE)

Esto nos guarda la dirección de memoria donde empieza ese buffer en la variable lpBaseAddress.
Esa dirección es lo que necesitamos pasar a la función WriteProcessMemory para escribir la ruta de nuestra DLL en el proceso remoto objetivo. Además de eso le tenemos que pasar el handle del proceso, el buffer a copiar (dllPath) y el tamaño de este:

kernel32.WriteProcessMemory(hProcess, lpBaseAddress, dllPath, len(dllPath), 
	byref(nBytesWritten))

Además de esto, necesitamos la dirección de LoadLibrary para pasársela a CreateRemoteThread como parámetro lpStartAddress. Para conseguir esa dirección, basta con ejecutar las dos funciones que aparecen a continuación:

hModule= kernel32.GetModuleHandleA("Kernel32.dll");
lpStartAddress = kernel32.GetProcAddress( hModule, "LoadLibraryA")

La primera abre un manejador de la biblioteca Kernel32.dll y la segunda utiliza este manejador para buscar la dirección de la función LoadLibrary en esta biblioteca.
Con esto ya tenemos todo lo necesario para inyectar nuestra DLL en el proceso que queramos.
El código final queda como sigue:

from ctypes import *

#Definition of some constants used by the windows API
PROCESS_ALL_ACCESS = ( 0x000F0000 | 0x00100000 | 0xFFF )
VIRTUAL_MEM = ( 0x1000 | 0x2000 )
PAGE_READWRITE = 0x04
INFINITE = 0xFFFFFFFF

#Path to your DLL
dllPath = "C:\\helloWorldDLL.dll"

#Change for the pid of the target process
pid = 3128 

kernel32 = windll.kernel32

#Retrieve handle of the process
hProcess = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
print "[*] Opening process: {}".format(hProcess)

#Allocate space on the target process for dllPath and write i'ts content
lpBaseAddress = kernel32.VirtualAllocEx(hProcess, None, len(dllPath), 
	VIRTUAL_MEM, PAGE_READWRITE)
print "[*] Allocating memory @ {}".format(hex(lpBaseAddress))

nBytesWritten = c_ulong(0) #Variable to pass by reference to the function
						   #and retrive the number of bytes written.
kernel32.WriteProcessMemory(hProcess, lpBaseAddress, dllPath, len(dllPath), 
	byref(nBytesWritten))
print "[*] Writing path: {} bytes writen".format(nBytesWritten.value)

#Get info needed to execute LoadLibrary in the target process
hModule= kernel32.GetModuleHandleA("Kernel32.dll");
print "[*] hModule: {}".format(hex(hModule))

lpStartAddress = kernel32.GetProcAddress( hModule, "LoadLibraryA")
print "[*] Address of function \"LoadLibraryA\" @ {}".format(hex(address))

#Injection of the DLL in the target process
threadID = c_ulong(0)
hThread = kernel32.CreateRemoteThread(hProcess, None, 0, lpStartAddress, 
	lpBaseAddress, 0, byref(threadID))
print "[*] Starting thread: {}".format(threadID.value)

#Close handle when injection is finished
kernel32.CloseHandle( hThread ); 

La variable pid contiene el identificador del proceso notepad.exe que ejecuté para la realización de estas pruebas.

Ejecución

 

C:>python injector.py
[*] Opening process: 116
[*] Allocating memory @ 0x1d0000
[*] Writing path: c_ulong(20L) bytes writen
[*] hModule: 0x77650000
[*] Address of function «LoadLibraryA» @ 0x77666590
[*] Starting thread: 2140

De acuerdo a este resultado, el script se ha ejecutado con éxito creando un hilo en el proceso remoto notepad.exe.

Comprobación

El programa nos dice que ha tenido éxito, ¿pero cómo podemos estar seguros de que la inyección se ha realizado con éxito?
Hay muchas maneras de comprobar si la inyección ha tenido éxito, os voy a mostrar un par de ellas: usando Process Hacker y usando un debugger.

Process Hacker

Process Hacker (PH)es una herramienta open source que permite la monitorización de los procesos que se están ejecutando en un sistema.
Cuando ejecutamos PH, aparece una lista de los procesos siendo ejecutados en el sistema en forma de árbol donde los procesos hijos cuelgan de los padres.
ph0
Desplegando el menú contextual haciendo click derecho sobre el proceso notepad.exe, PH nos permite realizar distintas acciones sobre el proceso. En este caso no nos interesa más que hacer doble click sobre notepad.exe para abrir la ventana de propiedades y luego click en la pestaña «Modules». Esto nos muestra las DLL cargadas en el proceso notepad.exe. En la imagen que aparece a continuación a la izquierda, se pueden ver las DLL antes de la inyección, helloWorldDLL.dll no aparece por ningún sitio. A la derecha lo que pasa tras ejecutar el programa.
ph
A wild DLL appeared!!
Como veis, la DLL es ahora uno de los módulos dentro de notepad.exe, lo que demuestra que la biblioteca se ha inyectado correctamente.

Debugger

La idea al usar el debugger es acoplar el debbuger al proceso y comprobar el mapa de memoria.
Para realizar este proceso me decidí por usar x64dbg como debugger. La razón de usar este debugger en lugar de Windbg es porque visualmente es un clon de Ollydbg, un debugger que me gusta mucho pero por desgracia no tiene soporte para arquitecturas x64 (y, viendo en su web que la última actualización es de febrero de 2014, probablemente nunca lo tenga :_( ).
Me acoplo a notepad.exe con el debugger:
attach
El mapa de memoria se puede encontrar en la pestaña «Memory map». A la izquierda de la imagen bajo estas líneas, se puede ver un extracto del mapa de memoria de notepad.exe antes de la inyección de la DLL. A la derecha se puede ver la biblioteca helloWorldDLL.dll dentro de la memoria del proceso.
dbg

helloworldAdemás de estas pruebas, en el caso de helloWorldDLL.dll, se puede ver que al inyectar la HelloWorldDLL.dll salta la caja de texto definida en la función “HelloWorld”.
Esta caja salta porque al inyectar la biblioteca, esta ejecuta DllMain y sigue la ejecución a través de la opción DLL_PROCESS_ATTACH, donde se llama a la función HelloWorld().
Si miramos la barra de tareas de Windows, vemos que este mensaje se ejecuta en el contexto de notepad.exe:
helloworld2
Aún así, no se como de fiable es este ultimo método así que mejor mirar el mapeo de la memoria en un debugger o usar Process Hacker o alguna otra herramienta similar.

NOTA: Es importante que todo lo que forma parte del proceso de inyección (DLL, Python y proceso objetivo) comparta arquitectura. Es decir, si el proceso está compilado para una arquitectura de 64 bits, la DLL y la versión de Python instalada en el SO debe ser de 64 bits.
Digo esto porque me hizo perder más de 4 horas hasta que un amigo me sugirió que podía ser un problema de compatibilidad de arquitecturas… tenía razón.

Conclusiones

Hasta aquí esta entrega de la serie Amenaza Silenciosa. Es muy pronto para sacar conclusiones pero os dejo un par de cosas que he sacado en claro:
Cuando se trabaja realizando este tipo de proyectos, es muy importante saber en que arquitectura están trabajando todos y cada uno de los componentes de la ecuación. Cuando estuve haciendo las pruebas todo parecía que funcionaba bien, pero al ejecutar el script, la función CreateRemoteProcess fallaba. En principio pensé que estaba haciendo algo mal, pero toda lo que hacía tenía sentido. Utilizando la función GetLastError(), para ver donde fallaba, el resultado era “Access is denied”. “¿Un problema de permisos?” pensé yo.
La consola era de administrador, el proceso lo ejecutaba mi usuario, no debería de haber problemas. Miré las compatibilidades: tanto la DLL, como el proceso notepad.exe estaban compilados en 64 bits… Tras horas dándome cabezazos contra un muro, un amigo me sugirió que mirase a ver si el Python.exe era de 32 o 64 bits. Debido a que el programa que ejecutaba todo estaba en 32 bits (es el que te descarga de la web de Python por defecto) el resto fallaba. Por lo tanto, si juegas con accesos a memoria, inyecciones, etc. es importante que tengas conocimiento de todos los elementos envueltos en tu experimento.
La otra conclusión es más a nivel personal que a nivel técnico. Me lo estoy pasando en grande toqueteando y probando herramientas que llevaba mucho tiempo esperando poder usar.
Ahora que ya sabemos como inyectar una DLL desde un programa, para conseguir imitar a Dridex nos queda hacer que la inyección ocurra desde la propia DLL e imitar el mecanismo de persistencia.
Por último, aquí os dejo material de referencia para que podáis completar las cosas que he dejado más en el aire y ampliar el contenido que aquí aparece. No olvidéis de dejar en los comentarios vuestras opiniones, correcciones, etc.

Referencias

Recursos:
Ctypes @ python.org
Grey Hat Python @ nostarch.com

Dridex:
Dridex dropper analysis @ christophe.rieunier.name
Analysis of Dridex / Cridex / Feodo / Bugat @ stopmalvertising.com

DLL:
DLLs in Visual C++ @ MSDN
Walkthrough: Creating and Using a Dynamic Link Library (C++) @ MSDN
Implementing DllMain @ MSDN
Compilar en x64 con visual studio @ MSDN
Using RUNDLL32.exe to call a function within a dll @ adp-gmbh.ch
Difference between DllMain and DllEntryPoint @ reverseengineering.stackexchange.com

Inyección:
Three Ways to Inject Your Code into Another Process @ codeproject.com
Using CreateRemoteThread for DLL Injection on Windows: http://resources.infosecinstitute.com/using-createremotethread-for-dll-injection-on-windows/

Software:
Process Hacker @ sourceforge.net
X64dbg @ x64dbg.com
Ollydbg @ ollydbg.de

Windows API:
VirtualAllocEx @ MSDN
CreateRemoteThread @ MSDN
LoadLibrary @ MSDN
WriteProcessMemory @ MSDN
GetModuleHandle @ MSDN
GetProcAddress @ MSDN
GetLastError @ MSDN

Amenaza Silenciosa I

Cuando trabajo cazando malware, una de las cosas que suelen cantar a la hora de encontrar artefactos maliciosos es la aparición de ejecutables extraños en los sistemas de persistencia más comunes, como, por ejemplo, en algunas claves de registro. Un día me pregunté, ¿es posible generar una amenaza silenciosa, que no cante mucho en los sistemas de persistencia, sin utilizar técnicas extrañas? Veamos como de fácil o difícil sería.

Dridex

No es la primera vez que hablo de temas relacionados con Dridex en este blog. En este caso lo hablaré de su mecanismo de persistencia. Es un sistema simple pero efectivo que da muchos dolores de cabeza a los administradores de sistemas a la hora de eliminarlo de una red.
Una vez infectado con Dridex, al ejecutarse, este se inyecta en el proceso Explorer.exe y se borra del sistema. Pero, ¿cómo logra entonces persistir?
Cuando Dridex detecta que Windows se va a cerrar se escribe a si mismo con la estructura <nombre aleatorio>.TMP y añade a la clave de registro HKEY_CURRENT_USER\ Software\Microsoft\Windows\CurrentVersion\Run el valor:

"rundll32.exe C:\DOCUME~1\\APPLIC~1\.tmp NfInitialize"

Cuando se vuelve a ejecutar el reiniciar el sistema, el fichero .TMP se vuelve a borrar y la clave del registro desaparece.
Esto no sólo hace su detección muy complicada, ya que la mayoría de los antivirus funcionan analizando los ficheros en disco y los que analizan la memoria no analizan todas la páginas, si no que la manera más fácil y barata de desinfectar las maquinas es desenchufándolas y quitándoles la batería si son ordenadores portátiles, lo cual complica la desinfección. ¿Os imagináis que gracia le hará al que le toque ir desenchufando dos mil ordenadores?
Sin utilizar ninguna técnica nueva, esto consigue que la detección en base a la aparición de artefactos sospechosos en sistemas de persistencia de la que hablaba en la introducción sea imposible una vez Windows ha arrancado: ni vamos a encontrar un ejecutable en %TMP% o %APPDATA% , ni vamos a ver nada en las claves del registro.

Alternate Data Streams

Alternate Data Stream (ADS) es una característica de NTFS en principio diseñada para almacenar información sobre un ficheros sin tener que utilizar otros ficheros. Estos metadatos se escriben en el disco duro a continuación de los datos del fichero.
Si miramos un registro de la Master File Table (MFT) de NTFS, se puede ver la diferencia entre un fichero sin ADS y uno con ADS.
Registro de fichero en MFT:
Screen Shot 2015-08-12 at 10.44.54 PM
Registro de fichero en MFT con ADS:
Screen Shot 2015-08-12 at 10.44.38 PM

Images extraídas del documento: Alternate Data Streams: Out of the Shadows and into the Light de Ryan L. Means (2003).

Como se puede ver, en el registro con ADS aparece un segundo stream de datos después de los datos del fichero.
En el pasado se han utilizado ADS para ocultar malware y ejecutarlo desde ahí.
Con la llegada de Windows 7, Microsoft deshabilitó la posibilidad de ejecutar directamente nada que estuviera almacenado en ADS. Aun así, hay formas indirectas de ejecutar estos binarios.

Infección de ficheros

Una de las cosas que me lleva a escribir esta serie de artículos es la siguiente hipótesis: ¿y si en lugar de añadir un nuevo binario a cualquiera de los sistemas de persistencia infectamos un binario que ya esté en uno de estos mecanismos?
Es decir, aprovechando la estructura de los ficheros PE, ¿puedo inyectar mi programa en un ejecutable que previamente he detectado que persiste?
La respuesta es, en principio, que sí, puedo. La realidad es que no sé cual será la dificultad de realizar esto en sistemas operativos modernos, pero lo que sí que sé es que en muchos proyectos de “compromise discovery” * pasaría desapercibido.

Objetivos

Este post es sólo la introducción a un viaje en el que sólo he empezado a dar los primeros pasos en el que voy a tratar de replicar las técnicas comentadas en el post y del que espero volver con los siguientes resultados:

  • Aumentar mi conocimiento de inyección de procesos en Windows.
  • Mejorar y terminar de comprender cómo funcionan el hooking de funciones en Windows.
  • Conocimiento profundo de los diferentes métodos de persistencia en sistemas Windows.
  • Comprender el sistema de ficheros NTFS.
  • Ver como funciona la infección de ficheros a nivel práctico.
  • Aplicación de las técnicas clásicas de infección en un entorno moderno.
  • Profundizar en la API de Windows.

¿Qué puede esperar el lector?

  • Un montón de referencias y enlaces a recursos que utilice.
  • Pruebas de concepto (al menos de las partes relevantes).
  • Los resultados explicados tan bien como pueda.
  • Largas esperas y poca periodicidad :P.

Mientras sigo pasito a pasito, ¿se os ocurre alguna otra técnica o forma de hacer que un bicho pase desapercibido y se me haya pasado?

* Compromise discovery es el nombre que reciben los proyectos en los que un equipo con conocimiento en respuesta ante incidentes se presenta en una compañía, toma un “snapshot” de los sistemas de la compañía y analiza esa información en busca de evidencias de compromiso.

Archivos poliglotas: No es pdf todo lo que parece

Generalmente la forma más usual que utilizamos para reconocer el formato de un archivo es fijándonos en su extensión. En un sistema informático la aplicación empleada para abrir el fichero también se asocia (en primera instancia) con la extensión. Otro método, ampliamente utilizado en protocolos de internet como HTTP o SMTP es MIME, Multipurpose Internet Mail Extensions, que asocia un identificador tipo/subtipo para determinar la naturaleza de los datos transmitidos. Así por ejemplo, «image/jpeg» indicaría que una imagen en formato jpeg se adjunta en el mensaje. Este estándar de notación está regulado por el IANA . La fundación Apache también aporta un intesante listado con la correspondencia entre MIME y extensión de fichero.

No obstante, esta aproximación inicial para identificar un fichero de ninguna manera puede asegurarnos el contenido real del mismo. Por ejemplo, bastaría cambiar la extensión de «.pdf» por «.jpeg» en un archivo para que el sistema, en lugar de abrir el archivo con Adobe Reader, lo intentase con un visualizador de imágenes. Este comportamiento puede ser problemático desde el punto de vista de la seguridad, en el sentido que se se malinterpreta un contenido y que podría utilizarse de manera no esperada para realizar acciones maliciosas.

Cabeceras de fichero y números mágicos

Una forma más precisa para determinar el tipo de fichero es observando el contenido del mismo. Existen múltiples estándares de formato que utilizan unos pocos bytes (en binarios) o caracteres alfanuméricos (en ficheros de texto) del comienzo del archivopara identificar el contenido. Esta convención está estandarizada y se conoce como números mágicos. Un listado puede encontrarse en el siguiente enlace: https://en.wikipedia.org/wiki/List_of_file_signatures.

De este modo, una aplicación que trate de identificar de forma segura un archivo antes de abrirlo, comprobaría la cabecera del mismo para determinar el tipo de contenido. Esta estrategia que en principio podría parecer ideal, tampoco proporciona un método infalible debido a la «flexibilidad» de algunos formatos y la poca rigurosidad de ciertas aplicaciones a la hora de parsear y comprobar las cabeceras y opciones de los mismos. Este problema se pone de manifiesto cuando un mismo fichero puede ser interpretado de distintas formas, dependiendo de la aplicación que lo procese y de las opciones de formato que verifica. Este tipo de archivo se conoce con el nombre de archivo poliglota.

Archivos poliglotas: varios en uno

¿Que es un archivo poliglota?

Un archivo poliglota es un fichero con múltiples formatos válidos, es decir, que tiene una estructura que lo hace interpretable por distintas aplicaciones ya que cumple con el formato esperado por las mismas. Así por ejemplo, un mismo fichero de estas características podría ser abierto como una imagen por un visor de imágenes o ejecutar un script al abrirse con un navegador o un intérprete de comandos.

¿Por qué existen archivos poliglotas? ¿Que riesgos existen?

En general,  podemos decir que se debe a una excesiva flexibilidad a la hora de definir los formatos. Por ejemplo, un archivo PDF permite posicionar su «número mágico» ( 25 50 44 46 en hexadecimal o %PDF en ascii) dentro de los primeros 1024 bytes del archivo, mientras que otros (JPG,GIF, ELF, etc) son menos flexibles y obligan un «offset 0» es decir, a posicionar el número mágico justo al principio del archivo.

El riesgo proviene del hecho de que un mismo fichero puede ser interpretado de distintas formas y, aprovechando esta circunstancia, se  pueden realizar tareas no deseadas. Así, en un archivo con extensión .pdf podría incrustarse código javascript, php o shell script y ejecutarse en un cliente, en un servidor web o en un intérprete de comandos, si la organización de los datos dentro del fichero conserva una estructura válida para todos los formatos pretendidos.

Ejemplos de achivos poliglotas

Veamos un ejemplo muy sencillo (e inofensivo) donde se ha incrustado un comando linux (xeyes) en un pdf y, sin alterar su validez, comprobamos como puede abrirse con un visor de pdf y ejecutarse como un script bash:

bash_pdf

Obsérvese en el volcado hexadecimal, como en la cabecera justo al comienzo del archivo, aparece el comando xeyes. Unos pocos bytes más adelante aparece el identificador del PDF, resultando un archivo válido puesto que este formato permite un offset de hasta 1024 bytes para posicionar la cabecera (Adobe Reader).

Otro ejemplo: un archivo de imagen bmp que a la vez contiene un comando ejecutable windows (calc.exe):

calc2

 

Ataques poliglotas

Este tipo de archivo constituye en sí un problema de seguridad y, es responsabilidad del usuario o una aplicación establecer las comprobaciones oportunas que eviten situaciones de peligro en caso de un uso malintencionado. En esta materia Ange Albertini (@angealbertini) es un reconocido investigador que ha publicado numerosos trabajos relacionados con los formatos de archivo con muchos ejemplos y métodos para construir archivos poliglotas. En su repositorio de Github ( https://github.com/corkami ) encontraréis gran cantidad de información para profundizar en este interesante campo.

Conclusiones:

Como el propio Ange dice: No olvides abrir tu pdf en un editor hexadecimal , cargar una imagen en un reproductor de sonido… o ejecutar un documento en intérprete de comandos. Eso sí, siempre desconfiando de las apariencias.

Bola extra

En este enlace  se proporciona un pdf. Échale un vistazo… y reprodúcelo con VLC player 😉

 

Video: Funky File Formats  (Ange Albertini)

 

 

 

sandbox-caja-magica

Sandbox «La Caja Mágica»

¿Que es SandBox?

Sandbox viene del anglicismo «caja de arena» que se utiliza mucho en países americanos para que los niños jueguen sobre todo en época de verano, en el término de seguridad un SandBox es una máquina virtual donde se corren los procesos maliciosos antes de que lleguen al usuario final.

En la actualidad existen en el mercado varias soluciones de SandBoxing que nos dan un gran abanico de opciones y de sabores.

¿Porqué implementar un SandBox en mi organización?

Es una de las preguntas más complejas de responder pero más fáciles de explicar.

Recientemente se ha venido incrementando los códigos maliciosos específicamente el «malware» que busca sacar dinero a los usuarios de la organización ejecutando programas de procedencia «no confiable», un ejemplo palpable lo tenemos recientemente con el Cryptolocker que cifraba los datos del afectado y pedía un rescate para enviarte la llave para descifrar los datos.

Si tenemos un solución de SandBoxing permitirá que antes de que le demos clic a una imagen, url, fichero o cualquier tipo de información adjunta al correo electronico se ejecute en una máquina virtual comprueba si es de fuente confiable y que no venga codificado (código malicioso), luego de verificar que el correo electronico es confiable o legítimo le permite al usuario abrir el contenido anexado sin ningún tipo de riesgo a infecciones o robo de información.

¿Cuanto tiempo me lleva implementar una solución de SandBoxing?

Dependiendo de la casa fabricante que elijamos podremos tener un tiempo de implementación corto y que se reduce en complejidad del proyecto y dedicación de recursos.

Existen soluciones que se integrarán nativamente con las demás soluciones que tenemos en nuestro entorno corporativo como por ejemplo las consolas antivirus o los servidores de parcheo de sistemas corporativos, teniendo como especial punto que en estos últimos sistemas se aloja el core business es decir, los sistemas que mantienen el negocio y que deben de funcionar las 24 horas los 365 días del año con un porcentaje superior al 99.9999% de disponibilidad.

En este sentido lo más lógico sino queremos tener recursos dedicados al proyecto o evitarnos la complejidad de una implementación podemos contratar servicios en la nube (cloud) que hoy en día ofrecen la mayoría de los fabricantes.

¿Cuanto cuesta una solución de SandBoxing?

No te cuestiones ni de vueltas a la hora de invertir en este tipo de soluciones, la respuesta seria la siguiente: «¿Cuánto dinero pierdes si un código malicioso te bloquea o roba la información?»

Muchas veces lo primero que nos preguntamos es cuanto cuesta pero nunca hemos realizado un ejercicio de riesgo tecnologico o una matriz de riesgo que nos plantee en dinero $$$$ €€€€ cuánto perdemos hora/hombre hora/negocio si tenemos por ejemplo «Cryptolocker acechandonos», cuando una verdad es cierta cada dia las mafias mejoran mas y mas el codigo haciendo que sea una lucha de hormiguitas o que la labor de bloqueo de URL en los Firewalls sea prácticamente imposible.

¿Quién nos puede asesorar en este tipo de soluciones?

Más que vendernos una solución lo clave es buscar la persona o la consultora que nos de no solo una consultoría experta porque instalar «facil» pero tunear una solución de SandBoxing es donde está el secreto.

Por eso es preferible si no somos expertos contratar horas de servicio del propio fabricante que nos sirva para llevar a cabo el proyecto sin ningún tipo de contratiempos.

Finalmente les dejo algunos URL que les servirán para ampliar esta información.

Hasta la próxima……

https://blogs.mcafee.com/business/security-connected/thinking-outside-of-the-sandbox-mcafee-advanced-threat-defense-unveiled

https://blogs.mcafee.com/business/developing-the-ultimate-defense-against-advanced-malware

http://blog.trendmicro.com/trendlabs-security-intelligence/deploying-a-smart-sandbox-for-unknown-threats-and-zero-day-attacks/

https://support.symantec.com/en_US/defaultProductLanding.63070.html

http://docs-legacy.fortinet.com/fos50hlp/50/index.html#page/FortiOS%205.0%20Help/antivirus_chapter.150.25.html