214 lines
6.5 KiB
Python
214 lines
6.5 KiB
Python
"""
|
|
|
|
HTTP related methods used by Empire.
|
|
|
|
Includes URI validation/checksums, as well as the base
|
|
http server (EmpireServer) and its modified request
|
|
handler (RequestHandler).
|
|
|
|
These are the first places URI requests are processed.
|
|
|
|
"""
|
|
|
|
from BaseHTTPServer import BaseHTTPRequestHandler
|
|
import BaseHTTPServer, threading, ssl, os, string, random
|
|
from pydispatch import dispatcher
|
|
import re
|
|
|
|
# Empire imports
|
|
import encryption
|
|
import helpers
|
|
|
|
|
|
#TODO: place this in a config
|
|
def default_page():
|
|
"""
|
|
Returns the default page for this server.
|
|
"""
|
|
page = "<html><body><h1>It works!</h1>"
|
|
page += "<p>This is the default web page for this server.</p>"
|
|
page += "<p>The web server software is running but no content has been added, yet.</p>"
|
|
page += "</body></html>"
|
|
return page
|
|
|
|
###############################################################
|
|
#
|
|
# Host2lhost helper.
|
|
#
|
|
###############################################################
|
|
|
|
def host2lhost(s):
|
|
"""
|
|
Return lhost for Empire's native listener from Host value
|
|
"""
|
|
reg = r'(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'
|
|
res = re.findall( reg, s)
|
|
return res[0] if len(res) == 1 else '0.0.0.0'
|
|
|
|
###############################################################
|
|
#
|
|
# Checksum helpers.
|
|
#
|
|
###############################################################
|
|
|
|
def checksum8(s):
|
|
"""
|
|
Add up all character values and mods the total by 256.
|
|
"""
|
|
return sum([ord(ch) for ch in s]) % 0x100
|
|
|
|
|
|
###############################################################
|
|
#
|
|
# HTTP servers and handlers.
|
|
#
|
|
###############################################################
|
|
|
|
class RequestHandler(BaseHTTPRequestHandler):
|
|
"""
|
|
Main HTTP handler we're overwriting in order to modify the HTTPServer behavior.
|
|
"""
|
|
|
|
# retrieve the server headers from the common config
|
|
serverVersion = helpers.get_config('server_version')[0]
|
|
|
|
# fake out our server headers base
|
|
BaseHTTPRequestHandler.server_version = serverVersion
|
|
BaseHTTPRequestHandler.sys_version = ""
|
|
|
|
|
|
def do_GET(self):
|
|
|
|
# get the requested path and the client IP
|
|
resource = self.path
|
|
clientIP = self.client_address[0]
|
|
sessionID = None
|
|
|
|
cookie = self.headers.getheader("Cookie")
|
|
if cookie:
|
|
# search for a SESSIONID value in the cookie
|
|
parts = cookie.split(";")
|
|
for part in parts:
|
|
if "SESSIONID" in part:
|
|
# extract the sessionID value
|
|
name, sessionID = part.split("=", 1)
|
|
|
|
# fire off an event for this GET (for logging)
|
|
dispatcher.send("[*] "+resource+" requested from "+str(sessionID)+" at "+clientIP, sender="HttpHandler")
|
|
|
|
# get the appropriate response from the agent handler
|
|
(code, responsedata) = self.server.agents.process_get(self.server.server_port, clientIP, sessionID, resource)
|
|
|
|
# write the response out
|
|
self.send_response(code)
|
|
self.end_headers()
|
|
self.wfile.write(responsedata)
|
|
self.wfile.flush()
|
|
# self.wfile.close() # causes an error with HTTP comms
|
|
|
|
def do_POST(self):
|
|
|
|
resource = self.path
|
|
clientIP = self.client_address[0]
|
|
sessionID = None
|
|
|
|
cookie = self.headers.getheader("Cookie")
|
|
if cookie:
|
|
# search for a SESSIONID value in the cookie
|
|
parts = cookie.split(";")
|
|
for part in parts:
|
|
if "SESSIONID" in part:
|
|
# extract the sessionID value
|
|
name, sessionID = part.split("=", 1)
|
|
|
|
# fire off an event for this POST (for logging)
|
|
dispatcher.send("[*] Post to "+resource+" from "+str(sessionID)+" at "+clientIP, sender="HttpHandler")
|
|
|
|
# read in the length of the POST data
|
|
if self.headers.getheader('content-length'):
|
|
length = int(self.headers.getheader('content-length'))
|
|
postData = self.rfile.read(length)
|
|
|
|
# get the appropriate response for this agent
|
|
(code, responsedata) = self.server.agents.process_post(self.server.server_port, clientIP, sessionID, resource, postData)
|
|
|
|
# write the response out
|
|
self.send_response(code)
|
|
self.end_headers()
|
|
self.wfile.write(responsedata)
|
|
self.wfile.flush()
|
|
# self.wfile.close() # causes an error with HTTP comms
|
|
|
|
# supress all the stupid default stdout/stderr output
|
|
def log_message(*arg):
|
|
pass
|
|
|
|
|
|
class EmpireServer(threading.Thread):
|
|
"""
|
|
Version of a simple HTTP[S] Server with specifiable port and
|
|
SSL cert. Defaults to HTTP is no cert is specified.
|
|
|
|
Uses agents.RequestHandler handle inbound requests.
|
|
"""
|
|
|
|
def __init__(self, handler, lhost='0.0.0.0', port=80, cert=''):
|
|
|
|
# set to False if the listener doesn't successfully start
|
|
self.success = True
|
|
|
|
try:
|
|
threading.Thread.__init__(self)
|
|
self.server = None
|
|
|
|
self.server = BaseHTTPServer.HTTPServer((lhost, int(port)), RequestHandler)
|
|
|
|
# pass the agent handler object along for the RequestHandler
|
|
self.server.agents = handler
|
|
|
|
self.port = port
|
|
self.serverType = "HTTP"
|
|
|
|
# wrap it all up in SSL if a cert is specified
|
|
if cert and cert != "":
|
|
self.serverType = "HTTPS"
|
|
cert = os.path.abspath(cert)
|
|
|
|
self.server.socket = ssl.wrap_socket(self.server.socket, certfile=cert, server_side=True)
|
|
|
|
dispatcher.send("[*] Initializing HTTPS server on "+str(port), sender="EmpireServer")
|
|
else:
|
|
dispatcher.send("[*] Initializing HTTP server on "+str(port), sender="EmpireServer")
|
|
|
|
except Exception as e:
|
|
self.success = False
|
|
# shoot off an error if the listener doesn't stand up
|
|
dispatcher.send("[!] Error starting listener on port "+str(port)+": "+str(e), sender="EmpireServer")
|
|
|
|
|
|
def base_server(self):
|
|
return self.server
|
|
|
|
|
|
def run(self):
|
|
try: self.server.serve_forever()
|
|
except: pass
|
|
|
|
|
|
def shutdown(self):
|
|
|
|
# shut down the server/socket
|
|
self.server.shutdown()
|
|
self.server.socket.close()
|
|
self.server.server_close()
|
|
self._Thread__stop()
|
|
|
|
# make sure all the threads are killed
|
|
for thread in threading.enumerate():
|
|
if thread.isAlive():
|
|
try:
|
|
thread._Thread__stop()
|
|
except:
|
|
pass
|
|
|