
Implementação de PoC de um spoofer de pilha de chamadas totalmente dinâmico
Implementação de Prova de Conceito de um spoofing de pilha de chamadas totalmente dinâmico
SilentMoonwalk é uma implementação PoC de um spoofing de pilha de chamadas totalmente dinâmico, implementando uma técnica para remover o chamador original da pilha de chamadas, usando ROP para dessincronizar o desenrolamento do fluxo de controle.
Este PoC é o resultado de uma pesquisa conjunta sobre o tópico de spoofing de pilha. Os autores da pesquisa são:
Quero enfatizar que este trabalho teria sido impossível sem o trabalho de Waldo-IRC e Trickster0, que ambos contribuíram para os estágios iniciais do PoC, e para a pesquisa por trás do PoC.
Este repositório demonstra uma implementação PoC para falsificar a pilha de chamadas ao chamar APIs arbitrárias do Windows.
Esta tentativa foi inspirada por este tópico do Twitter e este tópico do Twitter, onde o sensei namazso mostrou e sugeriu estender a abordagem de desenrolamento de pilha com uma cadeia ROP para dessincronizar o desenrolamento do fluxo de controle real e restaurar a pilha original posteriormente.
Este PoC tenta fazer algo semelhante ao acima, e usa uma pilha de dessincronização para ocultar completamente a pilha de chamadas original, além de remover a base da imagem EXE dela. Ao retornar, um gadget ROP é invocado para restaurar a pilha original. No código, esse processo é repetido 10 vezes em um loop, usando diferentes quadros a cada iteração, para provar estabilidade.
A ferramenta atualmente suporta 2 modos, onde um é na verdade um patch incorreto para um quadro pop RBP não funcional identificado, que opera deslocando o RSP atual e adicionando dois quadros falsos à pilha de chamadas. Como opera usando quadros sintéticos, refiro-me a este modo como "SYNTHETIC".
Ao selecionar o quadro que se desenrola ao retirar o registrador RBP da pilha, a ferramenta pode selecionar um quadro inadequado, resultando em uma pilha de chamadas abruptamente cortada, como observável abaixo.

Uma solução boba para o problema seria criar dois quadros falsos e vinculá-los de volta à pilha de chamadas cortada. Isso criaria uma espécie de pilha de chamadas aparentemente legítima, mesmo sem um quadro adequado que se desenrole chamando POP RBP, mas:
O resultado do spoof sintético pode ser observado na imagem abaixo:

Figura 1: Windows 10 - Pilha de chamadas aparentemente legítima, não desenrolável, na qual o módulo EXE foi completamente removido (chamando a função getchar sem parâmetros)
Nota: Este modo de operação está desabilitado por padrão. Para habilitar este modo, altere CALLSTACK_TYPE para 1
Este modo é a solução correta para o problema acima, onde o quadro inadequado é simplesmente substituído por outro, adequado.

Figura 2: Windows 10 - Pilha de chamadas legítima, desenrolável, na qual o módulo EXE foi completamente removido (chamando a função MessageBoxA com 4 parâmetros)
No repositório, você também pode encontrar um pequeno utilitário para inspecionar funções de tempo de execução, que pode ser útil para analisar entradas de funções de tempo de execução.
UnwindInspector.exe -h
Unwind Inspector v0.100000
Mandatory args:
-m <module>: Target DLL
-f <function>: Target Function
-a <function-address>: Target Function Address
Saída de Exemplo:
UnwindInspector.exe -m kernelbase -a 0x7FFAAE12182C
[*] Using function address 0x7ffaae12182c
Runtime Function (0x000000000000182C, 0x00000000000019ED)
Unwind Info Address: 0x000000000026AA88
Version: 0
Ver + Flags: 00000000
SizeOfProlog: 0x1f
CountOfCodes: 0xc
FrameRegister: 0x0
FrameOffset: 0x0
UnwindCodes:
[00h] Frame: 0x741f - 0x04 - UWOP_SAVE_NONVOL (RDI, 0x001f)
[01h] Frame: 0x0015 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0015)
[02h] Frame: 0x641f - 0x04 - UWOP_SAVE_NONVOL (RSI, 0x001f)
[03h] Frame: 0x0014 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0014)
[04h] Frame: 0x341f - 0x04 - UWOP_SAVE_NONVOL (RBX, 0x001f)
[05h] Frame: 0x0012 - 0x00 - UWOP_PUSH_NONVOL (RAX, 0x0012)
[06h] Frame: 0xb21f - 0x02 - UWOP_ALLOC_SMALL (R11, 0x001f)
[07h] Frame: 0xf018 - 0x00 - UWOP_PUSH_NONVOL (R15, 0x0018)
[08h] Frame: 0xe016 - 0x00 - UWOP_PUSH_NONVOL (R14, 0x0016)
[09h] Frame: 0xd014 - 0x00 - UWOP_PUSH_NONVOL (R13, 0x0014)
[0ah] Frame: 0xc012 - 0x00 - UWOP_PUSH_NONVOL (R12, 0x0012)
[0bh] Frame: 0x5010 - 0x00 - UWOP_PUSH_NONVOL (RBP, 0x0010)
Para compilar o PoC e observar um comportamento semelhante ao da imagem, certifique-se de:
/GS-)/Od)/GL)/Os, /Ot)/Oi)Vale mencionar trabalhos anteriores neste tópico, que construíram a base deste trabalho.