Cyril François

Arrojando luz sobre el conductor de ABYSSWORKER

Elastic Security Labs describe ABYSSWORKER, un controlador malicioso empleado con la cadena de ataque del ransomware MEDUSA para deshabilitar las herramientas antimalware.

Arrojando luz sobre el conductor de ABYSSWORKER

Resumen

Los cibercriminales emplean cada vez más sus propios controladores, ya sea explotando un controlador legítimo vulnerable o empleando un controlador personalizado para desactivar los sistemas de detección y respuesta de puntos finales (EDR) y evadir las capacidades de detección o prevención.

Elastic Security Labs ha monitoreado una campaña con motivaciones financieras que implementa el ransomware MEDUSA mediante el uso de un cargador lleno de HEARTCRYPT . Este cargador se implementó junto con un controlador firmado con certificado revocado de un proveedor chino llamado ABYSSWORKER, que se instala en la máquina víctima y luego emplea para atacar y silenciar a diferentes proveedores de EDR. Este controlador EDR-killer fue reportado recientemente por ConnectWise en otra campaña, usando un certificado diferente y códigos de control de E/S, momento en el que se discutieron algunas de sus capacidades. En 2022, Google Cloud Mandiant reveló un controlador malicioso llamado POORTRY , que creemos que es la primera mención de este controlador.

En este artículo, analizamos en profundidad este controlador y examinamos sus distintas características y técnicas. También proporcionamos direcciones virtuales relativas (RVA) debajo de cada captura de pantalla de código invertido para vincular la investigación con la muestra de referencia, junto con un pequeño ejemplo de cliente que puede usar para experimentar más con este malware.

Análisis técnico

Encabezado PE

El binario es un controlador de Windows PE de 64 bits llamado smuol.sys e imita un controlador CrowdStrike Falcon legítimo.

En el momento del análisis, encontramos una docena de muestras en VirusTotal, datadas desde el 08/08/2024 hasta el 24/02/2025. La mayoría estaban empaquetados con VMProtect, pero dos (a los que se hace referencia en las tablas observables a continuación) no estaban protegidos.

Todas las muestras están firmadas empleando certificados probablemente robados y revocados de empresas chinas. Estos certificados son ampliamente conocidos y compartidos entre diferentes muestras y campañas de malware, pero no son específicos de este controlador. Las huellas dactilares del certificado se enumeran a continuación:

fingerprintNombre
51 68 1b 3c 9e 66 5d d0 b2 9e 25 71 46 d5 39 dcMateriales de aislamiento Co., Ltd de Foshan Gaoming Kedeyu
7f 67 15 0f bb 0d 25 4e 47 42 84 c7 f7 81 9c 4fFEI XIAO
72 88 1f 10 cd 24 8a 33 e6 12 43 a9 e1 50 ec 1dFuzhou Dingxin Comercio Co., Ltd.
75 e8 e7 b9 04 3b 13 df 60 e7 64 99 66 30 21 c1Changsha Hengxiang Tecnología de la Información Co., Ltd.
03 93 47 e6 1d ec 6f 63 98 d4 d4 6b f7 32 65 6cTecnología de red Co., Ltd de Xinjiang Yishilian
4e fa 7e 7b ba 65 ec 1a b7 74 f2 b3 13 57 d5 99Shenzhen Yundian Technology Co., Ltd

Ofuscación

ABYSSWORKER emplea funciones que siempre devuelven el mismo valor, basar en una combinación de predicados opacos y otras funciones de derivación. Por ejemplo, la función que retorna a cero a continuación siempre devuelve un 0 en función de los valores derivados codificados.

A continuación se muestra una de las funciones de derivación:

Estas funciones de retorno constante se llaman repetidamente a lo largo del binario para dificultar el análisis estático. Sin embargo, sólo hay tres funciones de este tipo y no se emplean en ningún predicado, sino que simplemente se llaman. Podemos identificarlos fácilmente, lo que hace que este sea un esquema de ofuscación ineficiente.

Inicialización

Tras la inicialización, el controlador comienza obteniendo avanzados a varios módulos del kernel y a su función de protección del cliente, que se analizará en las siguientes secciones.

Luego, crea un dispositivo con la ruta \\device\\czx9umpTReqbOOKF y un enlace simbólico con la ruta \\??\\fqg0Et4KlNt4s1JT.

Completa la inicialización registrando devoluciones de llamadas para sus funciones principales.

Protección del cliente al abrir el dispositivo

Cuando se abre el dispositivo del controlador, se llama a la devolución de llamada principal IRP_MJ_CREATE . Esta función es responsable de agregar el ID del proceso a la lista de procesos a proteger y de eliminar cualquier identificador preexistente para el proceso de destino de la lista de procesos en ejecución.

La función recupera el ID del proceso del hilo del kernel actual ya que la devolución de llamada del kernel se ejecuta en el contexto del proceso del cliente cuando se abre el dispositivo.

Antes de agregar el ID del proceso a la lista de protección, ABYSSWORKER busca y elimina cualquier identificador existente para el proceso del cliente en otros procesos en ejecución.

Para lograrlo, el malware itera sobre los procesos existentes forzando brutamente sus identificadores de proceso (PID) para evitar depender de cualquier API. Para cada proceso, itera sobre sus controladores, también usando fuerza bruta, y verifica si el objeto subyacente corresponde al proceso del cliente. Si se encuentra una coincidencia, elimina los derechos de acceso empleando el valor pasado como parámetro (0x8bb).

Finalmente, agrega el PID a la lista global de procesos protegidos.

Como se mencionó anteriormente, el controlador configura su función de protección durante la fase de inicialización. Esta protección se basa en el registro de dos devoluciones de llamadas pre-operation mediante la API ObRegisterCallback : una para detectar la apertura de controladores a sus procesos protegidos y otra para detectar la apertura de controladores a los subprocesos de esos procesos protegidos.

Las dos devoluciones de llamada funcionan de la misma manera: establecen el acceso deseado para el identificador en cero, negando efectivamente la creación del identificador.

Controladores de DeviceIoControl

Al recibir una solicitud de control de E/S del dispositivo, ABYSSWORKER envía la solicitud a los controladores según el código de control de E/S. Estos controladores cubren una amplia gama de operaciones, desde la manipulación de archivos hasta la terminación de procesos y controladores, proporcionando un conjunto de herramientas integral que puede usar para terminar o deshabilitar permanentemente los sistemas EDR.

Detallamos los diferentes controles IO en la siguiente tabla:

NombreCódigo
Habilitar malware0x222080
Copiar archivo0x222184
Eliminar devoluciones de llamadas y dispositivos por nombre de módulo0x222400
Reemplazar las funciones principales del controlador por el nombre del módulo0x222404
Matar subprocesos del sistema por nombre de módulo0x222408
Desmontar los mini dispositivos de filtrado0x222440
Eliminar archivo0x222180
Desactivar malware0x222084
Cargar API0x2220c0
Disminuir el contador de referencia de todos los controladores0x222100
Disminuir el contador de referencia de todos los dispositivos0x222104
Terminar proceso0x222144
Terminar hilo0x222140
Eliminación de ganchos de las principales funciones de los controladores Ntfs y Pnp0x222444
Resetear0x222664

Habilitación del malware (0x222080)

Como se analiza en esta publicación del blog, el cliente debe habilitar el controlador enviando una contraseña (7N6bCAoECbItsUR5-h4Rp2nkQxybfKb0F-wgbJGHGh20pWUuN1-ZxfXdiOYps6HTp0X) al controlador, en nuestro caso es a través del control de E/S 0x222080 .

El controlador simplemente compara la entrada del usuario con la contraseña codificada. Si es correcto, establece un indicador global en verdadero (1). Esta bandera se marca en todos los demás controladores para permitir o denegar la ejecución.

Cargando la API (0x2220c0)

La mayoría de los controladores del malware dependen de las API del kernel que deben cargar mediante este controlador. Este controlador carga estos globales junto con varias estructuras, empleando los punteros del módulo del kernel cargados previamente durante la inicialización. Una vez que se completa la carga, se establece una bandera global para señalar la disponibilidad de estas API.

Este controlador tiene dos modos de funcionamiento: un modo completo y un modo parcial. En el modo completo, carga las API empleando una estructura de mapeo de nombres de funciones y RVA proporcionados por el usuario como entrada al control IO. En el modo parcial, busca algunas de las API por sí solo, pero no carga todas las API que se cargan en el modo completo, de ahí el término modo parcial. Si el usuario opta por el modo parcial debido a la imposibilidad de proporcionar esta estructura de mapeo, algunos controladores no se ejecutarán. En este capítulo solo cubrimos el modo de operación completo.

A continuación detallamos las estructuras empleadas:

#define AM_NAME_LENGTH 256
typedef struct _struct_435
{
   uint64_t rva;
   char name[AM_NAME_LENGTH];
} struct_435_t;

#define AM_ARRAY_LENGTH 1024
typedef struct _struct_433
{
   struct_435_t array[AM_ARRAY_LENGTH];
   uint32_t length;
} struct_433_t;

A continuación ofrecemos un breve ejemplo de uso:

struct_433_t api_mapping = {
    .length = 25,
    .array = {
        [0] = {.rva = 0xcec620, .name = "PspLoadImageNotifyRoutine"},
        [1] = {.rva = 0xcec220, .name = "PspCreateThreadNotifyRoutine"},
        [2] = {.rva = 0xcec420, .name = "PspCreateProcessNotifyRoutine"},
        // (...)
        [24] = {.rva = 0x250060, .name = "NtfsFsdShutdown"},
}};

uint32_t malware_load_api(HANDLE device)
{
    return send_ioctrl(device, IOCTRL_LOAD_API, &api_mapping, sizeof(struct_433_t), NULL, 0);
}

Para cargar su API, la función comienza cargando tres 'listas de devolución de llamadas' de diferentes tipos de objetos del kernel. Estos son empleados por el controlador que elimina las devoluciones de llamadas de notificación registradas que pertenecen a un módulo específico.

Luego, carga punteros a funciones empleando la estructura proporcionada, simplemente buscando el nombre de la función y agregando el RVA asociado a la dirección base del módulo.

Esto se hace para las siguientes 25 funciones:

  • PspLoadImageNotifyRoutine
  • PspCreateThreadNotifyRoutine
  • PspCreateProcessNotifyRoutine
  • CallbackListHead
  • PspSetCreateProcessNotifyRoutine
  • PspTerminateThreadByPointer
  • PsTerminateProcess
  • IopInvalidDeviceRequest
  • ClassGlobalDispatch
  • NtfsFsdRead
  • NtfsFsdWrite
  • NtfsFsdLockControl
  • NtfsFsdDirectoryControl
  • NtfsFsdClose
  • NtfsFsdCleanup
  • NtfsFsdCreate
  • NtfsFsdDispatchWait
  • NtfsFsdDispatchSwitch
  • NtfsFsdDispatch
  • NtfsFsdFlushBuffers
  • NtfsFsdDeviceControl
  • NtfsFsdFileSystemControl
  • NtfsFsdSetInformation
  • NtfsFsdPnp
  • NtfsFsdShutdown

Copia y eliminación de archivos (0x222184, 0x222180)

Para copiar o eliminar archivos, ABYSSWORKER se basa en una estrategia que, aunque no es nueva, sigue siendo interesante. En lugar de emplear una API común como NtCreateFile, se crea un paquete de solicitud de E/S (IRP) desde cero y se envía directamente al dispositivo de unidad correspondiente que contiene el archivo de destino.

Creando un archivo

La función de creación de archivos se emplea para mostrar cómo funciona este mecanismo. La función comienza obteniendo el dispositivo de unidad de la ruta del archivo. Luego, se crea un nuevo objeto de archivo y se vincula al dispositivo de unidad de destino, lo que garantiza que el nuevo objeto esté vinculado correctamente a la unidad.

Luego, crea un nuevo objeto IRP y establece todos los datos necesarios para realizar la operación de creación de archivo. La función principal a la que se dirige este IRP se especifica en la propiedad MajorFunction , que, en este caso, se establece en IRP_MJ_CREATE, como se espera para la creación de archivos.

Luego, el malware envía el IRP al dispositivo de disco de destino. Si bien podría emplear la API IoCallDriver para hacerlo, en su lugar envía el IRP manualmente llamando a la función principal del dispositivo correspondiente.

En este punto, el objeto de archivo es válido para su uso posterior. El controlador finaliza su trabajo incrementando el contador de referencia del objeto de archivo y asignándolo a su parámetro de salida para su uso posterior.

Copiar un archivo

Para copiar un archivo, ABYSSWORKER abre los archivos de origen y de destino, luego lee (IRP_MJ_READ) desde el origen y escribe (IRP_MJ_WRITE) en el destino.

Eliminar un archivo

El controlador de eliminación establece el atributo de archivo en ATTRIBUTE_NORMAL para desproteger cualquier archivo de solo lectura y establece la disposición del archivo en eliminar (disposition_info.DeleteFile = 1) para eliminar el archivo usando el IRP IRP_MJ_SET_INFORMATION .

Eliminación de devoluciones de notificaciones por nombre de módulo (0x222400)

Los clientes de malware pueden usar este controlador para cegar los productos EDR y su visibilidad. Busca y elimina todas las devoluciones de llamadas de notificación registradas. Las devoluciones de llamadas específicas son aquellas registradas con las siguientes API:

  • PsSetCreateProcessNotifyRoutine
  • PsSetLoadImageNotifyRoutine
  • PsSetCreateThreadNotifyRoutine
  • ObRegisterCallbacks
  • CmRegisterCallback

Además, elimina las devoluciones de llamadas registradas a través de un controlador MiniFilter y, opcionalmente, elimina los dispositivos que pertenecen a un módulo específico.

Para eliminar esas devoluciones de llamadas de notificación, el controlador las ubica empleando varios métodos, como las tres listas de devoluciones de llamadas globales cargadas previamente en el controlador de API de carga, que contienen devoluciones de llamadas registradas con ObRegisterCallbacks y CmRegisterCallback. Luego los elimina empleando las API correspondientes, como ObUnRegisterCallbacks y CmUnRegisterCallbacks.

El cegamiento del EDR mediante estos métodos merece una entrada de blog entera. Para mantener esta publicación concisa, no proporcionaremos más detalles aquí, pero invitamos al lector a explorar estos métodos en dos proyectos bien documentados que implementan estas técnicas:

Reemplazar las funciones principales del controlador por el nombre del módulo 0x222404

Otra forma de interferir con un controlador es usar este controlador para reemplazar todas sus funciones principales con una función ficticia, deshabilitando así cualquier interacción con el controlador, dado un nombre de módulo de destino.

Para lograr esto, ABYSSWORKER itera a través de los objetos del controlador en los directorios de objetos Driver y Filesystem . Para cada objeto controlador, compara el nombre del módulo subyacente con el módulo de destino y, si coinciden, reemplaza todas sus funciones principales con IopInvalidDeviceRequest.

Desconectar dispositivos de minifiltro (0x222440)

Este controlador itera sobre todos los objetos de controlador que se encuentran en los directorios de objetos Driver y FileSystem . Para cada controlador, explora su árbol de dispositivos y separa todos los dispositivos asociados con el controlador de minifiltro: FltMgr.sys.

La función funciona iterando sobre los dispositivos del controlador a través de los punteros AttachedDevice y NextDevice , recuperando el nombre del módulo del controlador asociado a cada dispositivo y comparándolo con el nombre del módulo de destino pasado como parámetro (”FltMgr.sys”). Si los nombres coinciden, emplea la función IoDetachDevice para desvincular el dispositivo.

Matar subprocesos del sistema por nombre de módulo (0x222408)

Este controlador itera sobre los subprocesos mediante la fuerza bruta de sus identificadores de subproceso y los elimina si el subproceso es un subproceso del sistema y su dirección de inicio pertenece al módulo de destino.

Para finalizar el hilo, el malware pone en cola una APC (llamada a procedimiento asincrónico) para ejecutar código en el contexto del hilo objetivo. Una vez ejecutado, este código, a su vez, llamará PsTerminateSystemThread.

Terminar proceso y terminar hilo (0x222144, 0x222140)

Con estos dos controladores puedes finalizar cualquier proceso o hilo mediante su PID o ID de hilo (TID) usando PsTerminateProcess y PsTerminateThread.

Eliminación de ganchos de las funciones principales de los controladores Ntfs y Pnp (0x222444)

Además de registrar devoluciones de llamadas de notificación, algunos EDR prefieren enganchar funciones principales de los controladores NTFS y PNP . Para eliminar esos problemas, el malware puede llamar a este controlador para restaurar las funciones principales originales de esos controladores.

ABYSSWORKER simplemente itera sobre cada función principal registrada, verifica si la función pertenece al módulo del controlador y, si no, significa que la función fue enganchada, por lo que la reemplaza con las funciones originales.

Resetear 0x222664

Para resetear la máquina, este controlador emplea la función no documentada HalReturnToFirmware.

Ejemplo de implementación del cliente

En esta publicación de blog proporcionamos un pequeño ejemplo de implementación de un cliente. Este ejemplo funciona con la muestra de referencia y se empleó para depurarlo, pero no implementa todos los IOCTRL para el controlador y es poco probable que se actualice en el futuro.

Sin embargo, contiene todas las funciones para habilitarlo y cargar su API, por lo que esperamos que cualquier lector motivado, con la ayuda de la información de este artículo, pueda ampliarlo y experimentar más con este malware.

El repositorio del proyecto está disponible aquí.

Malware y MITRE ATT&CK

Elastic usa el marco MITRE ATT&CK para documentar tácticas, técnicas y procedimientos comunes que las amenazas emplean contra las redes empresariales.

Táctica

Técnicas

Las técnicas representan cómo un adversario logra un objetivo táctico mediante la realización de una acción.

Mitigaciones

YARA

Elastic Security creó las siguientes reglas YARA relacionadas con esta publicación:

Observaciones

En esta investigación se discutieron los siguientes observables:

ObservableTipoReferenciaFecha
6a2a0f9c56ee9bf7b62e1d4e1929d13046cd78a93d8c607fe4728cc5b1e8d050SHA256Muestra de referencia de ABYSSWORKERVT visto por primera vez: 22/01/2025
b7703a59c39a0d2f7ef6422945aaeaaf061431af0533557246397551b8eed505SHA256Muestra de ABYSSWORKERVT visto por primera vez: 27/01/2025

Referencias