
P³-Shellcode Loader é um loader que implementa uma técnica de injeção de código que utiliza a estrutura Process Parameters como local de execução e preparação para injeção de shellcode em processos remotos, sem acionar mecanismos comuns de detecção.
Autores: Max Hirschberger & Ogulcan Ugur
O P³-Shellcode Loader é um carregador que implementa uma técnica de injeção de código que aproveita a estrutura Process Parameters (Process Parameter Poisoning) como local de execução e staging para injeção de shellcode em processos remotos, sem acionar mecanismos comuns de detecção.
Um conceito semelhante foi descrito pelo pesquisador de segurança modexp, que demonstrou que os argumentos passados à API CreateProcess podem ser aproveitados para esse fim [1].
Os invasores querem tornar suas atividades menos suspeitas. Com a injeção de processos, os invasores conseguem realizar suas atividades a partir de um processo diferente, que é mais confiável ou do qual se espera que execute a atividade específica, reduzindo assim a suspeita.
As etapas típicas a seguir são necessárias para injetar código em outro processo:
OpenProcess / NtOpenProcess ou CreateProcess / NtCreateProcess).VirtualAllocEx ou NtAllocateVirtualMemory).WriteProcessMemory / NtWriteVirtualMemory).VirtualProtectEx / NtProtectVirtualMemory).CreateRemoteThread ou NtCreateThreadEx).Técnicas adicionais de injeção incluem, mas não se limitam a:
NtSetContextThread)NtQueueApcThread)RtlCreateProcessReflection, que implementa o fork de processos.
Em nossos testes, observamos que a maioria dos EDRs se concentra em telemetria específica para detectar injeção de processos. Os EDRs monitoram principalmente o uso de WriteProcessMemory e VirtualAllocEx, bem como suas chamadas de sistema do kernel subjacentes NtWriteVirtualMemory, NtAllocateVirtualMemory e NtAllocateVirtualMemoryEx.O Windows fornece a função de API CreateProcessW para criar novos processos, mostrada na Listagem 1. Os três primeiros parâmetros dela — lpCommandLine, lpEnvironment e lpStartupInfo — são relevantes para a técnica de injeção descrita, pois são usados para transferir dados ao novo processo.```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
);
*Listagem 1: Definição da função CreateProcessW da API do Windows*
O parâmetro `lpCommandLine` especifica a linha de comando para o novo processo. Ele é limitado a um máximo de 32.767 caracteres Unicode, incluindo o terminador nulo Unicode. Para a variante Unicode, é necessário fornecer uma string na qual a função possa gravar. Se uma string constante for fornecida, qualquer tentativa de gravação feita pela função da API resulta em uma violação de acesso à memória. Se o valor for `NULL`, a linha de comando do processo será obtida do parâmetro `lpApplicationName`. Se `lpApplicationName` for `NULL`, ele deverá ser fornecido no campo `lpCommandLine` e é limitado a `MAX_PATH` caracteres.
O parâmetro `lpEnvironment` fornece uma lista de variáveis de ambiente para o processo. Se o valor for `NULL`, o ambiente do processo criador será usado. A lista de variáveis de ambiente consiste em strings sucessivas terminadas em nulo, no formato `NAME=VALUE`, com outro terminador nulo no final.
O parâmetro `lpStartupInfo` é uma estrutura mostrada na Listagem 2, com campos como estação de janela, desktop, handles de entrada e saída padrão, bem como campos que configuram a janela principal do novo processo. De acordo com a documentação da Microsoft, o campo `lpReserved` é reservado para uso interno, sem documentação adicional. Por meio de análise com o depurador WinDbg, foi possível relacionar esse parâmetro à variável `ShellInfo` do tipo `UNICODE_STRING` no novo processo.```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;
Listagem 2: Layout da estrutura de dados STARTUPINFOW