From d980017ccf8860823fff514f49ae47c956e1c7f5 Mon Sep 17 00:00:00 2001 From: Sanjiv Kawa Date: Thu, 6 Dec 2018 17:10:24 -0500 Subject: [PATCH 1/2] Offline report generator --- OfflineReportGenerator.py | 427 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 427 insertions(+) create mode 100644 OfflineReportGenerator.py diff --git a/OfflineReportGenerator.py b/OfflineReportGenerator.py new file mode 100644 index 0000000..d856e22 --- /dev/null +++ b/OfflineReportGenerator.py @@ -0,0 +1,427 @@ +#!/usr/bin/env python + + +import sqlite3, re, subprocess, time, cgi, os, sys +import pandas as pd + +# Configurable Setting +ReportsDirectory = "./" +# End + +if not os.path.exists(ReportsDirectory): + os.makedirs(ReportsDirectory) + +DB = "" + +try: + DB = sys.argv[1] +except IndexError: + DB = "" + +if len(DB) < 1: + print "Usage: python OfflineReportGenerator.py sqPowershellC2.SQLite" + exit() + +if not os.path.exists(DB): + print "%s Does not exist" % DB + exit() + +# Main program +def replace_tabs(s): + s = s.replace("\t", " ") + return s + + HostnameIP = "1.1.1.1" + ServerTAG = "\\n\\n\\n\\n\\n\\n\\n\\n\\n\\nPoshC2 Server\\n%s" % HostnameIP + GV = GV.replace("POSHSERVER",ServerTAG) + + implants = get_implants_all_db() + hosts = "" + daisyhosts = "" + + for i in implants: + if "Daisy" not in i[15]: + if i[3] not in hosts: + hostname = i[11].replace("\\","\\\\") + hosts += "\"%s\" -> \"%s \\n %s\\n\\n\\n\\n \"; \n" % (ServerTAG,hostname,i[3]) + + for i in implants: + if "Daisy" in i[15]: + hostname = i[11].replace("\\","\\\\") + if "\"%s\\n\\n\\n\\n \" -> \"%s \\n %s\\n\\n\\n\\n \"; \n" % (i[9].replace('\x00','').replace("\\","\\\\").replace('@',' \\n '),hostname,i[3]) not in daisyhosts: + daisyhosts += "\"%s\\n\\n\\n\\n \" -> \"%s \\n %s\\n\\n\\n\\n \"; \n" % (i[9].replace('\x00','').replace("\\","\\\\").replace('@',' \\n '),hostname,i[3]) + + GV = GV.replace("DAISYHOSTS",daisyhosts) + GV = GV.replace("IMPLANTHOSTS",hosts) + +def get_implants_all_db(): + conn = sqlite3.connect(DB) + conn.row_factory = sqlite3.Row + c = conn.cursor() + c.execute("SELECT * FROM Implants") + result = c.fetchall() + if result: + return result + else: + return None + +def get_htmlimplant( randomuri ): + conn = sqlite3.connect(DB) + conn.row_factory = sqlite3.Row + c = conn.cursor() + c.execute("SELECT * FROM Implants WHERE RandomURI=?",(randomuri,)) + result = c.fetchone() + if result: + return result + else: + return None + +def generate_table(table): + HTMLPre = """ + + + +
+__________            .__.     _________  ________
+\_______  \____  _____|  |__   \_   ___ \ \_____  \
+|     ___/  _ \/  ___/  |  \  /    \  \/  /  ____/
+|    |  (  <_> )___ \|   Y  \ \     \____/       \
+|____|   \____/____  >___|  /  \______  /\_______
+                  \/     \/          \/         \/
+=============== v4.0 www.PoshC2.co.uk =============
+
+""" + + if table == "CompletedTasks": + HTMLPre += """ + + +""" + + if table == "Implants": + HTMLPre += """ + + +""" + conn = sqlite3.connect(DB) + pd.set_option('display.max_colwidth', -1) + pd.options.mode.chained_assignment = None + frame = pd.read_sql_query("SELECT * FROM %s" % table, conn) + + # encode the Output column + if table == "CompletedTasks": + for index, row in frame.iterrows(): + frame.loc[index, "Command"] = replace_tabs(cgi.escape(row["Command"])) + frame.loc[index, "Output"] = replace_tabs(cgi.escape(row["Output"])) + + # convert the random uri to original hostname + if table == "CompletedTasks": + framelen = frame['RandomURI'].count() + for x in range(0, framelen): + try: + frame['RandomURI'][x] + a = get_htmlimplant(str(frame['RandomURI'][x])) + frame['RandomURI'][x] = a[2] + " @ " + a[3] + except Exception as e: + print e + a = "None" + + reportname = "%s%s.html" % (ReportsDirectory,table) + output_file = open(reportname, 'w') + HTMLPost = (frame.to_html(classes='table',index=False,escape=False)).replace("\\r\\n","
") + HTMLPost = HTMLPost.replace("\\n","
") + HTMLPost = re.sub(u'\x00', '', HTMLPost) + HTMLPost = HTMLPost.replace(" "," ") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","
") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost.replace("","") + HTMLPost = HTMLPost + """ +""" + output_file.write("%s%s" % (HTMLPre.encode('utf-8'),HTMLPost.encode('utf-8'))) + output_file.close() + print reportname + +generate_table("CompletedTasks") +generate_table("C2Server") +generate_table("Creds") +generate_table("Implants") From 904c2fe3662ecc8568a10a45dce489b9dd7cb56f Mon Sep 17 00:00:00 2001 From: Ben Turner Date: Thu, 6 Dec 2018 22:13:43 +0000 Subject: [PATCH 2/2] Removed versioning and typo --- OfflineReportGenerator.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/OfflineReportGenerator.py b/OfflineReportGenerator.py index d856e22..7519b2f 100644 --- a/OfflineReportGenerator.py +++ b/OfflineReportGenerator.py @@ -19,7 +19,7 @@ except IndexError: DB = "" if len(DB) < 1: - print "Usage: python OfflineReportGenerator.py sqPowershellC2.SQLite" + print "Usage: python OfflineReportGenerator.py PowershellC2.SQLite" exit() if not os.path.exists(DB): @@ -345,7 +345,7 @@ __________ .__. _________ ________ | | ( <_> )___ \| Y \ \ \____/ \ |____| \____/____ >___| / \______ /\_______ \/ \/ \/ \/ -=============== v4.0 www.PoshC2.co.uk ============= +================= www.PoshC2.co.uk =============== """
CompletedTaskIDIDIDIDTaskIDTaskIDRandomURIRandomURICommandCommandOutputOutputPromptPromptImplantIDImplantIDUserUserHostnameHostnameIpAddressIpAddressKeyKeyFirstSeenFirstSeenLastSeenLastSeenPIDPIDProxyProxyArchArchDomainDomainAliveAliveSleepSleepModsLoadedModsLoadedPivotPivot