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:
fingerprint | Nombre |
---|---|
51 68 1b 3c 9e 66 5d d0 b2 9e 25 71 46 d5 39 dc | Materiales de aislamiento Co., Ltd de Foshan Gaoming Kedeyu |
7f 67 15 0f bb 0d 25 4e 47 42 84 c7 f7 81 9c 4f | FEI XIAO |
72 88 1f 10 cd 24 8a 33 e6 12 43 a9 e1 50 ec 1d | Fuzhou Dingxin Comercio Co., Ltd. |
75 e8 e7 b9 04 3b 13 df 60 e7 64 99 66 30 21 c1 | Changsha Hengxiang Tecnología de la Información Co., Ltd. |
03 93 47 e6 1d ec 6f 63 98 d4 d4 6b f7 32 65 6c | Tecnología de red Co., Ltd de Xinjiang Yishilian |
4e fa 7e 7b ba 65 ec 1a b7 74 f2 b3 13 57 d5 99 | Shenzhen 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:
Nombre | Código |
---|---|
Habilitar malware | 0x222080 |
Copiar archivo | 0x222184 |
Eliminar devoluciones de llamadas y dispositivos por nombre de módulo | 0x222400 |
Reemplazar las funciones principales del controlador por el nombre del módulo | 0x222404 |
Matar subprocesos del sistema por nombre de módulo | 0x222408 |
Desmontar los mini dispositivos de filtrado | 0x222440 |
Eliminar archivo | 0x222180 |
Desactivar malware | 0x222084 |
Cargar API | 0x2220c0 |
Disminuir el contador de referencia de todos los controladores | 0x222100 |
Disminuir el contador de referencia de todos los dispositivos | 0x222104 |
Terminar proceso | 0x222144 |
Terminar hilo | 0x222140 |
Eliminación de ganchos de las principales funciones de los controladores Ntfs y Pnp | 0x222444 |
Resetear | 0x222664 |
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.
- Modificación de permisos de directorios y archivos
- Deshabilitar o modificar herramientas
- Firma de código
Mitigaciones
YARA
Elastic Security creó las siguientes reglas YARA relacionadas con esta publicación:
Observaciones
En esta investigación se discutieron los siguientes observables:
Observable | Tipo | Referencia | Fecha |
---|---|---|---|
6a2a0f9c56ee9bf7b62e1d4e1929d13046cd78a93d8c607fe4728cc5b1e8d050 | SHA256 | Muestra de referencia de ABYSSWORKER | VT visto por primera vez: 22/01/2025 |
b7703a59c39a0d2f7ef6422945aaeaaf061431af0533557246397551b8eed505 | SHA256 | Muestra de ABYSSWORKER | VT visto por primera vez: 27/01/2025 |
Referencias
- Google Cloud Mandiant, Inteligencia Mandiant. Juro solemnemente que mi conductor está tramando algo malo: en busca de malware con firma de certificación. https:\/\/cloud.google.com\/blog\/topics\/threat-intelligence\/hunting-attestation-signed-malware\/
- Unidad 42, Jerome Tujague, Daniel Bunce. Corazones encriptados: exposición del funcionamiento del empaquetador como servicio HeartCrypt, diciembre 13, 2024. https:\/\/unit42.paloaltonetworks.com\/packer-as-a-service-heartcrypt-malware\/
- ConnectWise, Blake Eakin. "Atacantes que aprovechan los valores predeterminados de Microsoft Teams y la Asistencia rápida para realizar ataques de ingeniería social", enero 31 2025. https:\/\/www.linkedin.com\/pulse\/attackers-leveraging-microsoft-teams-defaults-quick-assist-p1u5c\/
- wavestone-cdt, agosto 30, 2024. https:\/\/github.com\/wavestone-cdt\/EDRSandblast\/tree\/master
- myzxcg, mayo 24, 2024. https:\/\/github.com\/myzxcg\/RealBlindingEDR