
Implementación PoC de un spoofing de pila de llamadas completamente dinámico
Implementación de PoC de un spoofeador de pila de llamadas completamente dinámico
SilentMoonwalk es una implementación de PoC de un spoofeador de pila de llamadas completamente dinámico, que implementa una técnica para eliminar el llamante original de la pila de llamadas, usando ROP para desincronizar el desenrollado del flujo de control.
Esta PoC es el resultado de una investigación conjunta realizada sobre el tema del spoofing de pila. Los autores de la investigación son:
Quiero enfatizar que este trabajo habría sido imposible sin el trabajo de Waldo-IRC y Trickster0, quienes ambos contribuyeron en las primeras etapas de la PoC y en la investigación detrás de la PoC.
Este repositorio demuestra una implementación de PoC para falsificar la pila de llamadas al invocar APIs arbitrarias de Windows.
Este intento fue inspirado por este hilo de Twitter y este hilo de Twitter, donde el sensei namazso mostró y sugirió extender el enfoque de desenrollado de pila con una cadena ROP para desincronizar el desenrollado del flujo de control real y restaurar la pila original después.
Esta PoC intenta hacer algo similar a lo anterior y utiliza una pila desincronizada para ocultar completamente la pila de llamadas original, eliminando también la imagen base del EXE de la misma. Al regresar, se invoca un gadget ROP para restaurar la pila original. En el código, este proceso se repite 10 veces en un bucle, usando diferentes marcos en cada iteración, para demostrar estabilidad.
La herramienta actualmente admite 2 modos, donde uno es en realidad un parche incorrecto a un marco POP RBP no funcional identificado, que opera desplazando el RSP actual y añadiendo dos marcos ficticios a la pila de llamadas. Como opera usando marcos sintéticos, me refiero a este modo como "SYNTHETIC".
Al seleccionar el marco que se desenrolla extrayendo el registro RBP de la pila, la herramienta podría seleccionar un marco inadecuado, terminando en una pila de llamadas cortada abruptamente, como se observa a continuación.

Una solución tonta al problema sería crear dos marcos ficticios y vincularlos de vuelta a la pila de llamadas cortada. Esto crearía una especie de pila de llamadas aparentemente legítima, incluso sin un marco adecuado que se desenrolle llamando a POP RBP, pero:
El resultado del _spoof sintético se puede observar en la imagen a continuación:

Figura 1: Windows 10 - Pila de llamadas aparentemente legítima, no desenrollable, donde el módulo EXE fue completamente eliminado (llamando a la función sin parámetros getchar)
Nota: Este modo de operación está deshabilitado por defecto. Para habilitarlo, cambie CALLSTACK_TYPE a 1
Este modo es la solución correcta al problema anterior, donde el marco no adecuado es simplemente reemplazado por otro adecuado.

Figura 2: Windows 10 - Pila de llamadas legítima, desenrollable, donde el módulo EXE fue completamente eliminado (llamando a la función de 4 parámetros MessageBoxA)
En el repositorio también puedes encontrar una pequeña utilidad para inspeccionar funciones en tiempo de ejecución, que podría ser útil para analizar entradas de funciones en tiempo de ejecución.
UnwindInspector.exe -h
Unwind Inspector v0.100000
Argumentos obligatorios:
-m <módulo>: DLL objetivo
-f <función>: Función objetivo
-a <dirección-función>: Dirección de la función objetivo
Ejemplo de salida:
UnwindInspector.exe -m kernelbase -a 0x7FFAAE12182C
[*] Usando dirección de función 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 construir la PoC y observar un comportamiento similar al de la imagen, asegúrate de:
/GS-)/Od)/GL)/Os, /Ot)/Oi)Vale la pena mencionar trabajos previos sobre este tema, que sentaron las bases de este trabajo.