Un stager, a diferencia de las técnicas mostradas en shellcode execution, es un payload que no contiene el shellcode en sí, sino que se encarga de descargar el shellcode desde un servidor y ejecutarlo posteriormente en la máquina víctima. Esto trae diversas ventajas, ya que el peso del payload es muy inferior al de un stageless. También ayuda a evitar la detección de antivirus y sistemas de detección.
El código empieza declarando una estructura Shellcode que contiene un arreglo de bytes junto a la longitud del mismo.
Después se definen dos prototipos de funciones, Download que devuelve una estructura shellcode y otra función Execute que no devuelve nada pero acepta como parámetros esta estructura. Los prototipos de función permiten su uso en el bloque main() antes de su declaración.
Bloque Main
En esta parte es cuando se utilizan las funciones previamente declaradas, y antes de eso se coloca ::ShowWindow(::GetConsoleWindow(), SW_HIDE) para ocultar la consola. En la función Download() se especifica la dirección ip o nombre de dominio del server de donde se descargará el shellcode junto a su puerto.
Función Download
Las principales funciones que componen a Download son las siguientes:
InternetOpen se encarga de crear un handle HTTP definiendo un User-Agent , este nos va a servir para crear una conexión.
Como en primaria instancia puede fallar el realizar la conexión se puede intentar varias veces, esta porción de código se encarga de evaluar si no se envió la solicitud http el reintentar, en este caso hasta 3 veces.
Con el siguiente código vamos a leer el contenido del shellcode hosteado por el server, y para almacenar el resultado en la variable payload, como no sabemos el tamaño del shellcode le vamos a asignar BUFSIZE, con esto le decimos al compilador que decida cual será el tamaño.
El primer condicional sirve para evaluar si InternetReadFile pudo leer data, sino termina la ejecución del proceso.
Con el tercer if validamos si el tamaño del payload es pequeño, lo duplicamos.
Una vez se termine de leer la data con InternetReadFile, se encargará de romper el bucle while.
Para retornar este shellcode se define una estructura Shellcode (previamente definida) y se retorna este valor
Función Execute
Esta función se encarga de crear un espacio de memoria con el tamaño del shellcode con permisos de lectura, escritura y ejecución.
Después se copia a este espacio de memoria el shellcode que obtuvimos de la función Download().
Y por último se convierte el shellcode almacenado en la variable que creamos a una function pointer, y se la llama para ejecutar el shellcode.