Skip to content

Commit

Permalink
start at code cleanup; PH in this branch will not work
Browse files Browse the repository at this point in the history
  • Loading branch information
Relkci committed Dec 10, 2020
1 parent bbd5e0d commit bfd9701
Show file tree
Hide file tree
Showing 11 changed files with 478 additions and 378 deletions.
397 changes: 19 additions & 378 deletions PlumHound.py

Large diffs are not rendered by default.

Empty file added lib/__init__.py
Empty file.
42 changes: 42 additions & 0 deletions lib/phCLImanagement.py
@@ -0,0 +1,42 @@
#!/usr/bin/env python
# -*- coding: utf8 -*-
# PlumHound (phCLIManagement.py) - Management of Command Line Arguments
# https://github.com/PlumHound/PlumHound
# License GNU GPL3

# Import Python Modules
import argparse

def SetupArguments():
parser = argparse.ArgumentParser(description="BloodHound Wrapper for Blue/Purple Teams; v01.070a", add_help=True, epilog="For more information see https://plumhound.DefensiveOrigins.com")
pgroupc = parser.add_argument_group('DATABASE')
pgroupc.add_argument("-s", "--server", type=str, help="Neo4J Server", default="bolt://localhost:7687")
pgroupc.add_argument("-u", "--username", default="neo4j", type=str, help="Neo4J Database Useranme")
pgroupc.add_argument("-p", "--password", default="neo4jj", type=str, help="Neo4J Database Password")
pgroupc.add_argument("--UseEnc", default=False, dest="UseEnc", help="Use encryption when connecting.", action='store_true')

pgroupx = parser.add_mutually_exclusive_group(required="True")
pgroupx.add_argument("--easy", help="Test Database Connection, Returns Domain Users to stdout", action='store_true')
pgroupx.add_argument("-x", "--TaskFile", dest="TaskFile", type=str, help="Specify a PlumHound TaskList File")
pgroupx.add_argument("-q," "--QuerySingle", dest="QuerySingle", type=str, help="Specify a Single Cypher Query")
pgroupx.add_argument("-bp," "--BusiestPath", dest="BusiestPath", nargs='+', default=False, type=str, help="Find the X Shortest Paths that give the most users a path to Domain Admins. Need to specified [short|all] for shortestpath and the number of results. Ex: PlumHound -cu all 3")
pgroupx.add_argument("-ap," "--AnalyzePath", dest="AnalyzePath", nargs='+', default=False, type=str, help="Analyze 'Attack Paths' between two nodes and find which path needs to be remediated to brake the path.")

pgroupo = parser.add_argument_group('OUTPUT', "Output Options (For single cypher queries only. --These options are ignored when -x or --easy is specified.")
pgroupo.add_argument("-t", "--title", dest="title", default="Adhoc Query", type=str, help="Report Title for Single Query [HTML,CSV,Latex]")
pgroupo.add_argument("--of", "--OutFile", dest="OutFile", default="PlumHoundReport", type=str, help="Specify a Single Cypher Query")
pgroupo.add_argument("--op", "--OutPath", dest="path", default="reports//", type=str, help="Specify an Output Path for Reports")
pgroupo.add_argument("--ox", "--OutFormat", dest="OutFormat", default="stdout", type=str, help="Specify the type of output", choices=['stdout', 'HTML', 'CSV'])

pgrouph = parser.add_argument_group('HTML', "Options for HTML Output (For single queries or TaskLists")
pgrouph.add_argument("--HTMLHeader", dest="HTMLHeader", type=str, default="template//head.html", help="HTML Header (file) of Report")
pgrouph.add_argument("--HTMLFooter", dest="HTMLFooter", type=str, default="template//tail.html", help="HTML Footer (file) of Report")
pgrouph.add_argument("--HTMLCSS", dest="HTMLCSS", type=str, default="template//html.css", help="Specify a CSS template for HTML Output")

pgroupv = parser.add_argument_group('VERBOSE' "Set verbosity")
pgroupv.add_argument("-v", "--verbose", type=int, default="100", help="Verbosity 0-1000, 0 = quiet")

args = parser.parse_args()

return args

12 changes: 12 additions & 0 deletions lib/phCheckPython.py
@@ -0,0 +1,12 @@
#!/usr/bin/env python
# -*- coding: utf8 -*-
# PlumHound (phCheckPython.py) - Check for appropriate version of python
# https://github.com/PlumHound/PlumHound
# License GNU GPL3

import sys

def CheckPython():
if sys.version_info < (3, 0, 0):
print(__file__ + ' requires Python 3, while Python ' + str(sys.version[0] + ' was detected. Terminating. '))
sys.exit(1)
34 changes: 34 additions & 0 deletions lib/phDatabase.py
@@ -0,0 +1,34 @@
#!/usr/bin/env python
# -*- coding: utf8 -*-
# PlumHound (phDatabase.py) Database Connection Management
# https://github.com/PlumHound/PlumHound
# License GNU GPL3

from neo4j import GraphDatabase
from lib.phLoggy import Loggy as Loggy

# Setup Database Connection
def setup_database_conn(phArgs):
Loggy(phArgs.verbose,900, "------ENTER: SETUP_DATABASE_CONN-----")
Loggy(phArgs.verbose,200, "[!] Attempting to connect to your Neo4j project using {}:{} @ {} {}.".format(phArgs.username, phArgs.password, phArgs.server, "[ENCRYPTED]" if args.UseEnc else "[UNECNCRYPTED]"))
try:
if args.UseEnc:
Loggy(phArgs.verbose,200, " Using Neo4j encryption")
driver_connection = GraphDatabase.driver(phArgs.server, auth=(phArgs.username, phArgs.password), encrypted=True)
else:
Loggy(phArgs.verbose,200, " Not using Neo4j encryption")
driver_connection = GraphDatabase.driver(phArgs.server, auth=(phArgs.username, phArgs.password), encrypted=False)
Loggy(phArgs.verbose,200, "[+] Success!")
return driver_connection
except Exception:
Loggy(phArgs.verbose,100, "There was a problem. Check username, password, and server parameters.")
Loggy(phArgs.verbose,100, "[X] Database connection failed!")
exit()
Loggy(phArgs.verbose,900, "------EXIT: SETUP_DATABASE_CONN-----")

def close_database_con(phArgs,connectiondriver):
Loggy(phArgs.verbose,900, "------ENTER: CLOSE_DATABASE_CONN-----")
connectiondriver.close
return False
Loggy(phArgs.verbose,200, "[+] Closed Database Connection!")
exit()
15 changes: 15 additions & 0 deletions lib/phLoggy.py
@@ -0,0 +1,15 @@
#!/usr/bin/env python
# -*- coding: utf8 -*-
# PlumHound (phLoggy.py) - Logging Function
# https://github.com/PlumHound/PlumHound
# License GNU GPL3

# Loggy Function for lazy debugging
def Loggy(hurdle, level, notice):
if level <= hurdle:
if level <= 100:
print("[*]" + notice)
elif level < 500:
print("[!]" + notice)
else:
print("[*]" + notice)
130 changes: 130 additions & 0 deletions lib/phdeliver.py
@@ -0,0 +1,130 @@
#!/usr/bin/env python
# -*- coding: utf8 -*-
# PlumHound - Output Delivery and Parsing Functions(phdeliver.py)
# https://github.com/PlumHound/PlumHound
# License GNU GPL3

#Python Libraries
import sys
import ast
import csv
from tabulate import tabulate
from datetime import date

#Plumhound Modules
from lib.phLoggy import Loggy as Loggy


def SenditOut(list_KeysList, Processed_Results_List, OutFormat, OutFile, OutPath, Title, HTMLHeader, HTMLFooter, HTMLCSS):
Loggy(900, "------ENTER: SENDITOUT-----")
# Quick fix if keys returned no records to properly rebuild the keys list of 0, instead of int(0)
if isinstance(list_KeysList, int):
list_KeysList = []
output = ""

if OutFormat == "CSV":
Loggy(100, "Beginning Output CSV:" + OutPath + OutFile)
with open(OutPath + OutFile, "w", newline="") as f:
Loggy(500, "KeyType: " + str(type(list_KeysList)))
Loggy(500, "KeyList: " + str((list_KeysList)))
writer = csv.writer(f)
ModKeyList = ast.literal_eval("[" + str(list_KeysList) + "]")
Loggy(500, "KeyTypeMod: " + str(type(ModKeyList)))
Loggy(500, "KeyListMod: " + str(ModKeyList))
writer.writerows(ModKeyList)
Loggy(500, "ResultsType: " + str(type(Processed_Results_List)))
Loggy(999, "ResultsList: " + str(Processed_Results_List))
writer.writerows(Processed_Results_List)
return True

if OutFormat == "STDOUT":
print()
output = tabulate(Processed_Results_List, list_KeysList, tablefmt="simple")
print(output)
return True

if OutFormat == "HTML":
Loggy(100, "Beginning Output HTML:" + OutFile)

output = tabulate(Processed_Results_List, list_KeysList, tablefmt="html")
HTMLCSS_str = ""
HTMLHeader_str = ""
HTMLFooter_str = ""
HTMLPre_str = "<HTML><head>"
HTMLMId_str = "</head><Body>"
HTMLEnd_str = "</body></html>"
if HTMLHeader:
with open(HTMLHeader, 'r') as header:
HTMLHeader_str = header.read()
HTMLHeader_str = ReplaceHTMLReportVars(HTMLHeader_str, Title)

if HTMLFooter:
with open(HTMLFooter, 'r') as footer:
HTMLFooter_str = footer.read()
HTMLFooter_str = ReplaceHTMLReportVars(HTMLFooter_str, Title)

if HTMLCSS:
with open(HTMLCSS, 'r') as css:
HTMLCSS_str = "<style>\n" + css.read() + "\n</style>"

Loggy(500, "File Writing " + OutPath + OutFile)
output = HTMLPre_str + HTMLCSS_str + HTMLMId_str + HTMLHeader_str + output + HTMLFooter_str + HTMLEnd_str
fsys = open(OutPath + OutFile, "w")
fsys.write(output)
fsys.close
return True
Loggy(900, "------EXIT: SENDITOUT-----")


def FullSenditOut(Processed_Results_List, OutPath, HTMLHeader, HTMLFooter, HTMLCSS):
Loggy(900, "------ENTER: FULLSENDITOUT-----")

list_KeysList = ["Title", "Count", "Further Details"]
OutFile = "Report.html"
Title = "Full Report Details"

Loggy(100, "Beginning Output HTML:" + OutFile)

for entry in Processed_Results_List:
filename = entry[2]
entry[2] = "<a href=\"" + filename + "\">Details</a>"

output = str(tabulate(Processed_Results_List, list_KeysList, tablefmt="html"))
output = output.replace("&lt;","<")
output = output.replace("&gt;",">")
output = output.replace("&quot;",'"')

HTMLCSS_str = ""
HTMLHeader_str = ""
HTMLFooter_str = ""
HTMLPre_str = "<HTML><head>"
HTMLMId_str = "</head><Body>"
HTMLEnd_str = "</body></html>"
if HTMLHeader:
with open(HTMLHeader, 'r') as header:
HTMLHeader_str = header.read()
HTMLHeader_str = ReplaceHTMLReportVars(HTMLHeader_str, Title)

if HTMLFooter:
with open(HTMLFooter, 'r') as footer:
HTMLFooter_str = footer.read()
HTMLFooter_str = ReplaceHTMLReportVars(HTMLFooter_str, Title)

if HTMLCSS:
with open(HTMLCSS, 'r') as css:
HTMLCSS_str = "<style>\n" + css.read() + "\n</style>"

Loggy(500, "File Writing " + OutPath + OutFile)
output = HTMLPre_str + HTMLCSS_str + HTMLMId_str + HTMLHeader_str + output + HTMLFooter_str + HTMLEnd_str
fsys = open(OutPath + OutFile, "w")
fsys.write(output)
fsys.close
Loggy(100, "Full report written to Report.html")
return True
Loggy(900, "------EXIT: FULLSENDITOUT-----")


def ReplaceHTMLReportVars(InputStr, Title):
sOutPut = InputStr.replace("--------PH_TITLE-------", str(Title))
sOutPut = sOutPut.replace("--------PH_DATE-------", str(date.today()))
return sOutPut

0 comments on commit bfd9701

Please sign in to comment.