Nota: el contenido de esta entrada estará escrito en inglés con el objetivo de cumplir los requerimientos del examen para la obtención del certificado SLAE32 de Pentester Academy.
Note: content of this post will be written in English in order to be compliant and pass the SLAE32 certification exam brought by Pentester Academy.
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-26078
GitHub repository: https://github.com/tdkmp4n4/SLAE32_Exam
Introduction
SecurityTube Linux Assembly Expert (SLAE) for 32-bit or x86 architecture is the final certificate of Pentester Academy course “x86 Assembly Language and Shellcoding on Linux” which will be earned by those students who want to pass an exam consisting on several assignments. The following blog posts were written by student SLAE-XXXX (David Álvarez Robles) in order to qualify for the certification:
- SLAE32 Assignment 1 – Shell Bind TCP
- SLAE32 Assignment 2 – Shell Reverse TCP
- SLAE32 Assignment 3 – EggHunter shellcode
- SLAE32 Assignment 4 – Custom encoding scheme
- SLAE32 Assignment 5 – Metasploit shellcode analysis
- SLAE32 Assignment 6 – Creating polymorphic shellcode
- SLAE32 Assignment 7 – Creating a custom crypter
Auxiliary scripts
Throughout all blog posts regarding SLAE32 certification, several auxiliary scripts were used in order to automate some usual tasks. This section describes all the scripts developed by the student and serves as a reference for all of them.
install_libemu.sh
This script is used in order to install Libemu tool on a fresh Ubuntu operating system install. It is a simple bash script which can be run under elevated privileges.
# Filename: install_libemu.sh
# Author: David Alvarez Robles (km0xu95)
# Website: https://blog.asturhackers.es
# Purpose: This script was developed in order to install libemu on a fresh
# Ubuntu operating system installation
apt-get install git autoconf libtool
git clone https://github.com/buffer/libemu
cd libemu
autoreconf -v -i
./configure --prefix=/opt/libemu; make install
cd tools/sctest
make
Reverse_Opcode.py
This script is used to prepare the sequence of push statements needed to push all the opcodes needed to run a shellcode on the stack. It is very useful for encoders and decoders, as well as for knowing how the stack is used and padded.
#!/usr/bin/python
# Filename: Reverse_Opcode.py
# Author: David Alvarez Robles (km0xu95)
# Website: https://blog.asturhackers.es
# Purpose: This script was developed in order to prepare opcodes to be pushed
# to the stack were dealing with syscalls on assembly code
import sys
if(len(sys.argv) != 2):
print "Usage: ./Reverse_Opcode.py <opcode (no x)>"
sys.exit(0)
else:
opcodes = sys.argv[1]
bytes = [opcodes[i:i+2] for i in range (0, len(opcodes), 2)]
if len(opcodes) % 2 != 0:
print "Opcode lenght not divisible by 2. Check it out"
sys.exit(0)
count = 0
str = ""
pushes = []
for byte in bytes:
if (count == 3):
str = byte + str
push = "push 0x"+str
pushes.insert(0,push)
str = ""
count=0
else:
str = byte + str
count+=1
while((len(str)!=8 and str!="") and len(str)<=8):
str = "90" + str
if str!="":
push = "push 0x"+str
pushes.insert(0,push)
for push in pushes:
print push
Get-String-To-Stack.py
This script is used to prepare the sequence of push statements needed to push a string on the stack. It is very useful for syscalls where strings are passed as arguments, as well as for knowing how the stack is used and padded.
#!/usr/bin/python
# Filename: Get-String-To-Stack.py
# Author: David Alvarez Robles (km0xu95)
# Website: https://blog.asturhackers.es
# Purpose: This script was developed in order to prepare strings to be pushed
# to the stack were dealing with syscalls on assembly code
import sys
if(len(sys.argv) != 2):
print "Usage: ./Get-String-To-Stack.py <String>"
sys.exit(0)
input = sys.argv[1]
print '[*] String length : ' +str(len(input))
stringList = [input[i:i+4] for i in range(0, len(input), 4)]
for item in stringList[::-1] :
print item[::-1] + '\t push 0x' + str(item[::-1].encode('hex'))
Get-Shellcode.py
This script is used to automate all the process of compiling and linking the assembly file, the extraction of the shellcode and its testing using a C proof-of-concept. Several system commands are executed in order to obtain all the information. The source code below performs the following tasks:
- Compilation of assembly file using nasm resulting in an object file
- Linking of the object file using ld resulting in a binary file
- Shellcode visualization using objdump
- Shellcode extraction using objdump
- Creation of custom C proof-of-concept file to test the shellcode
- Compilation and linking of C proof-of-concept file using GCC resulting in a binary file
#!/usr/bin/python
# Filename: Get-Shellcode.py
# Author: David Alvarez Robles (km0xu95)
# Website: https://blog.asturhackers.es
# Purpose: This script was developed in order to automate all the tasks related
# to assembly code compilation and linking. Moreover, this script will compile
# a C proof-of-concept program to test the shellcode dumped from the assembled
# file
import sys,os,time
def replace_line(filename, line, text):
lines = open(filename, "r").readlines()
lines[line] = text
out = open(filename,"w")
out.writelines(lines)
out.close()
if(len(sys.argv) != 2):
print "Usage: ./Get-Shellcode.py <Assembly File (.nasm)>"
sys.exit(0)
else:
print "[*] Trying to create object file from assembly code using nasm"
ret = os.system("nasm -f elf32 -o "+sys.argv[1].split(".")[0]+".o "+sys.argv[1]+" > /dev/null 2>&1")
if (ret!=0):
print "[-] Failed to create object file from assembly code using nasm"
sys.exit(0)
else:
time.sleep(2)
print "[+] Done!"
print "\n[*] Linking file using LD to create final executable"
ret = os.system("ld -o "+sys.argv[1].split(".")[0]+" "+sys.argv[1].split(".")[0]+".o > /dev/null 2>&1")
if (ret!=0):
print "[-] Failed to link file using LD"
sys.exit(0)
else:
time.sleep(2)
print "[+] Done!"
print "\n[*] Getting shellcode using objdump utility"
print "[*] Check objdump raw output"
ret = os.system("objdump -D -M intel -d ./"+sys.argv[1].split(".")[0]+" 2>&1")
if (ret!=0):
print "[-] Failed obtaining objdump raw output"
sys.exit(0)
else:
time.sleep(2)
print "\n[*] Check objdump shellcode extraction"
command = "objdump -D -M intel -d ./"+sys.argv[1].split(".")[0]+"|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-9 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\\\x/g'|paste -d '' -s |sed 's/^/\"/'|sed 's/$/\"/g' > shellcode.txt"
ret = os.system(command)
if (ret!=0):
print "[-] Failed obtaining raw shellcode"
sys.exit(0)
else:
time.sleep(2)
f = open("shellcode.txt","r")
shellcode = f.read()
print "[+] Shellcode: "+shellcode
command = "objdump -D -M intel -d ./"+sys.argv[1].split(".")[0]+"|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-9 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'| sed 's/ //g' | paste -d '' -s |sed 's/^/\"/'|sed 's/$/\"/g' > shellcode_opcode.txt"
ret = os.system(command)
if (ret!=0):
print "[-] Failed obtaining raw shellcode (opcodes)"
sys.exit(0)
else:
time.sleep(2)
f = open("shellcode_opcode.txt","r")
shellcode_opcode = f.read()
print "[+] Shellcode (opcode): "+shellcode_opcode
print "[+] Done!"
print "\n[*] Creating shellcode testing file"
text = 'unsigned char code[] = '+shellcode.split("\n")[0]+';\n'
replace_line("shellcode.c",3,text)
os.system("cat shellcode.c")
time.sleep(2)
print "[+] Done!"
print "\n[*] Building shellcode testing binary file"
ret = os.system("gcc -fno-stack-protector -zexecstack shellcode.c -o shellcode")
if (ret!=0):
print "[-] Failed building shellcode testing binary file"
sys.exit(0)
else:
time.sleep(2)
print "[+] Done!"
Get-AssemblyDefineBytes.py
This script is used to prepare the sequence of bytes to define them on assembly language. It is very useful for syscalls where strings are passed as variables.
#!/usr/bin/python
# Filename: Get-AssemblyDefineBytes.py
# Author: David Alvarez Robles (km0xu95)
# Website: https://blog.asturhackers.es
# Purpose: This script was developed in order to prepare opcodes to be defined
# on assembly code
import sys
if(len(sys.argv) != 2):
print "Usage: ./Get-AssemblyDefineBytes.py <opcode (no x)>"
sys.exit(0)
else:
opcodes = sys.argv[1]
print "\nOriginal shellcode: " + opcodes
output = ""
for i in range(0,len(opcodes),2):
insertion = "0x"+opcodes[i:i+2]+", "
output+=insertion
print "\n[+] Shellcode to be inserted: " + output[:-2]
~km0xu95