
P³-Shellcode Loader es un cargador que implementa una técnica de inyección de código que aprovecha la estructura Process Parameters como ubicación de ejecución y almacenamiento intermedio (staging) para la inyección de shellcode en procesos remotos, sin activar mecanismos comunes de detección.
Authors: Max Hirschberger & Ogulcan Ugur
P³-Shellcode Loader es un cargador que implementa una técnica de inyección de código que aprovecha la estructura Process Parameters (Process Parameter Poisoning) como ubicación de ejecución y almacenamiento intermedio para la inyección de shellcode en procesos remotos, sin desencadenar los mecanismos de detección habituales.
Un concepto similar fue descrito por el investigador de seguridad modexp, quien demostró que los argumentos pasados a la API CreateProcess se pueden aprovechar para este propósito [1].
Los atacantes quieren que sus actividades parezcan menos sospechosas. Con la inyección de procesos, los atacantes pueden realizar sus actividades desde un proceso diferente que sea más confiable o del que se espera que realice la actividad específica, reduciendo así las sospechas.
Los siguientes son los pasos típicos necesarios para inyectar código en otro proceso:
OpenProcess / NtOpenProcess o CreateProcess / NtCreateProcess).VirtualAllocEx o NtAllocateVirtualMemory).WriteProcessMemory / NtWriteVirtualMemory).VirtualProtectEx / NtProtectVirtualMemory).CreateRemoteThread o NtCreateThreadEx).Las técnicas de inyección adicionales incluyen, entre otras, las siguientes:
NtSetContextThread)NtQueueApcThread)RtlCreateProcessReflection, que implementa la bifurcación de procesos.
En nuestras pruebas, observamos que la mayoría de los EDR se centran en telemetría específica para detectar la inyección de procesos. Los EDR monitorean principalmente el uso de WriteProcessMemory y VirtualAllocEx, así como sus llamadas al sistema del kernel subyacentes NtWriteVirtualMemory, NtAllocateVirtualMemory y NtAllocateVirtualMemoryEx.Windows proporciona la función de API CreateProcessW para crear nuevos procesos, como se muestra en el Listado 1. Los tres primeros parámetros de dicha función, lpCommandLine, lpEnvironment y lpStartupInfo, son relevantes para la técnica de inyección descrita, ya que se utilizan para transferir datos al nuevo proceso.```c
BOOL CreateProcessW(
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in, optional] LPSECURITY_ATTRIBUTES lpProcessAttributes,
[in, optional] LPSECURITY_ATTRIBUTES lpThreadAttributes,
[in] BOOL bInheritHandles,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
*Listado 1: Definición de la función CreateProcessW de Windows API*
El parámetro `lpCommandLine` especifica la línea de comandos para el nuevo proceso. Está limitado a un máximo de 32,767 caracteres Unicode, incluido el terminador nulo Unicode. Para la variante Unicode, es necesario proporcionar una cadena en la que la función pueda escribir. Si se suministra una cadena constante, cualquier intento de escritura realizado por la función de la API provoca una violación de acceso a memoria. Si el valor es `NULL`, la línea de comandos del proceso se tomará del parámetro `lpApplicationName`. Si `lpApplicationName` es `NULL`, debe proporcionarse en el campo `lpCommandLine` y está limitado a caracteres `MAX_PATH`.
El parámetro `lpEnvironment` proporciona una lista de variables de entorno al proceso. Si el valor es `NULL`, se utilizará el entorno del proceso creador. La lista de variables de entorno consta de cadenas sucesivas terminadas en nulo con el formato `NAME=VALUE` y otro terminador nulo al final.
El parámetro `lpStartupInfo` es una estructura que se muestra en el Listado 2, con campos como estación de ventana, escritorio, identificadores de entrada y salida estándar, así como campos que configuran la ventana principal del nuevo proceso. Según la documentación de Microsoft, el campo `lpReserved` está reservado para uso interno y no se documenta más. Mediante el análisis con el depurador WinDbg, fue posible relacionar este parámetro con la variable `ShellInfo` de tipo `UNICODE_STRING` en el nuevo proceso.```c
typedef struct _STARTUPINFOW {
DWORD cb;
LPWSTR lpReserved; // Copied to ShellInfo (UNICODE_STRING)
LPWSTR lpDesktop;
LPWSTR lpTitle;
DWORD dwX;
DWORD dwY;
DWORD dwXSize;
// (...) additional fields
WORD wShowWindow;
WORD cbReserved2;
LPBYTE lpReserved2;
HANDLE hStdInput;
// (...) additional fields
} STARTUPINFOW, *LPSTARTUPINFOW;
Listado 2: Disposición de la estructura de datos STARTUPINFOW