Empire/lib/common/http.py

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