Lezione 3: Shellcode e Offuscamento
Shellcode: payload eseguibile
Lo shellcode è un frammento di codice (solitamente assembly) che viene iniettato in memoria e eseguito dopo l'overflow. L'obiettivo più comune è avviare una shell (es. /bin/sh su Linux, cmd.exe su Windows).
Caratteristiche di uno shellcode efficace
- Size ridotto: limita lo spazio disponibile; shellcode tipici 20-100 byte.
- Null-free: non deve contenere byte null (
\x00) per non interrompere le funzioni di copia stringa comestrcpy. - Position-independent: deve funzionare indipendentemente dall'indirizzo di memoria in cui viene caricato.
- Evitare caratteri nocivi: nel caso di input via URL o campi form, possono esserci restrizioni (es. no newline, no space, no non-printable).
Esempio di shellcode Linux x86 (25 byte)
; execve("/bin/sh", NULL, NULL)
xor eax, eax
push eax
push 0x68732f2f ; "//sh"
push 0x6e69622f ; "/bin"
mov ebx, esp
mov al, 0x0b
int 0x80
Offuscamento: XOR Encoding
L'articolo di DilDog mostrava come nascondere stringhe critiche (es. l'IP del server C2) con semplice XOR. La tecnica si estende all'intero shellcode:
encoded = [byte ^ key for byte in shellcode]
# iniettare encoded + decoder stub
Il decoder stub (piccolo, ad esempio 20 byte) viene eseguito per decodificare il resto dello shellcode in memoria. Questo aiuta a eludere rilevamento basato su signature.
Downloading Payloads
Invece di iniettare l'intero shellcode, si può trasferire da remoto. DilDog usava:
- Shellcode minimale che apre una connessione FTP e scarica un file.
- Il payload vero (es. backdoor) veniva scaricato ed eseguito.
- Vantaggio: exploit più piccolo; svantaggio: richiede connettività di rete.
Esercizio
Preparare uno shellcode Linux x86 che esegue /bin/sh e salvarlo in un file binario grezzo (objcopy -O binary shellcode.elf shellcode.bin). Verificarne la size e assicurarsi che non contenga byte null.
Nella prossima lezione affronteremo le protezioni moderne (ASLR, DEP, Stack Canaries) e comeaggirare.