
Llamadas al sistema indirectas limpias con manipulación de llamadas al sistema.
SyscallRevenant es un nuevo método para realizar llamadas al sistema indirectas limpias.
El componente principal resuelve los System Service Numbers (SSNs) y las direcciones de la instrucción syscall de forma dinámica.
Esto se logra habilitando el trap flag durante la ejecución.
El componente secundario es la manipulación mediante el reemplazo de parámetros antes de una syscall.
Esta combinación está diseñada para eludir los hooks de userland durante la invocación posterior de la syscall, al mismo tiempo que sustituye los parámetros presentados inicialmente.
Aviso: El propósito de esto es únicamente educativo y de pruebas. No lo utilices en máquinas sobre las que no tengas permiso de uso. No lo utilices para aprovechar y comunicarte con máquinas para las que no tengas autorización de uso.
Las llamadas al sistema indirectas son un método para ejecutar instrucciones syscall en espacio de userland confiable.
Si un usuario encuentra una instrucción syscall, puede saltar a ella de forma indirecta.
Un evento habilitado durante una sesión de trazado puede revelar la dirección de retorno inmediatamente después de la instrucción.
Esto no tiene en cuenta los hooks de userland de Endpoint Detection & Response (EDR).
Un EDR puede insertar hooks en ntdll.dll, dejando obsoleto el proceso de búsqueda de SSNs e instrucciones syscall.
Entrar en un hook beneficiará al hilo propietario, sin elevar una puntuación maliciosa.
Observar una entrada en una función y observar la operación resultante son cosas diferentes.
RevenantSyscalls investiga esa brecha.
Las siguientes secciones describen los dos componentes principales del proyecto.
El primer componente resuelve las direcciones de funciones desde ntdll.dll cargada por el proceso.
A continuación, se puede realizar un recorrido por traps si se necesita información de syscall.
El segundo componente realiza un salto indirecto a la información de función guardada.
Leer desde el registro de segmento puede recuperar el Process Environment Block (PEB).
LoaderData es un campo del PEB que contiene datos cargados con cada proceso.
LoaderData contiene información sobre los módulos cargados junto con cada proceso.
Los nombres de módulos y las direcciones base existen en las entradas de módulo.
La información de exportación de una Dynamically Linked Library (DLL) describe los símbolos que exporta. Los metadatos de exportación permiten localizar símbolos exportados. El índice de una función se aplica solo a nombres y ordinales de nombres. Aplicar hash al nombre de una función es lo mejor para entornos con poca memoria.
Un controlador de excepciones vectorizado es un mecanismo de manejo de excepciones que captura excepciones desde cualquier punto dentro de un proceso.
Habilitar el trap flag provoca una excepción EXCEPTION_SINGLE_STEP en la siguiente instrucción ejecutada.
Un controlador de excepciones vectorizado personalizado puede inspeccionar el RIP y comprobar si hay una syscall.
Restableciendo repetidamente el trap flag, se descubrirá la dirección de la syscall y se guardará el SSN.
Búsqueda de syscall
|
Ejecución de syscall
|
Cada syscall tiene la búsqueda inicial de información de la syscall; se entrará en los hooks para recuperar la información de la syscall. A continuación, se realizará un salto indirecto a la syscall. Habrá un RIP spoof asociado (desde la entrada original). Con la reentrada, los parámetros iniciales han sido manipulados.
Desde la perspectiva de Event Tracing for Windows (ETW), los eventos posiblemente emitidos son: SysEnter, SysExit y StackWalk para cualquiera de ellos.
Si un EDR genera eventos similares y comparables, estos se verán casi idénticos.
Las únicas diferencias residirán en marcas de tiempo de Query Performance Counter (QPC) drásticamente diferentes.
src/AsmRevenant.asm REAL_RTN: DQ 0
FAKE_RTN: DQ 0
; If a syscall information lookup is in progress, the
; initial entry return address needs to be preserved.
MOV RAX, QWORD PTR [RSP]
MOV QWORD PTR [FAKE_RTN], RAX
; Once the re-entry is made, the real return is saved,
; and the current is spoofed with initial return.
MOV RAX, QWORD PTR [RSP]
MOV QWORD PTR [REAL_RTN], RAX
MOV RAX, QWORD PTR [FAKE_RTN]
MOV QWORD PTR [RSP], RAX
src/Revenant.cLONG VectoredExceptionHandler(EXCEPTION_POINTERS *BreakPoint) {
...
// If a syscall information lookup is being made, the
// syscall instruction address is saved, the SSN is
// saved, and the return is rerouted.
if (LookupInProgress && *(USHORT*)BreakPoint->Address == 0x050F) {
SyscallInstruction = BreakPoint->Address;
SyscallSSN = BreakPoint->Context->Rax;
BreakPoint->Context->Rip = SyscallExit;
}
// When re-entered, if the previous instruction was
// a syscall, reset return address, and exit.
if (!LookupInProgress && *(USHORT*)(BreakPoint->Address - 2) == 0x050F) {
*(VOID**)BreakPoint->Context->Rsp = REAL_RTN;
BreakPoint->Context->Rip = SyscallExit;
}
...
}