diff --git a/AirlockTools.py b/AirlockTools.py index 180d624..6042242 100644 --- a/AirlockTools.py +++ b/AirlockTools.py @@ -34,7 +34,7 @@ dotenv.load_dotenv() #Constants url = os.getenv('url') bad_publisher_list = ["Brave","Zoom", "GlavSoft", "VNC"] -pups = ["logmein", "invalid" , "nmap"] +pups = ["logmein", "invalid" , "nmap", "VNC", "Kaseya", "Solarwinds", "mRemoteNG"] badpathparts = ["users", "wwwroot", "windows\\temp", "windows\\task", "windows\\system32", "startup", "windows\\fonts", "Recycle.Bin", "AppData", "programdata", "Solarwinds", "kaseya", "Windows\\assembly", "WindowsPowerShell\\Modules"] path_exclusion_constant = 4 min_files_for_path = 4 @@ -241,6 +241,7 @@ def menu_prepare_to_enforce(): if os.path.exists(f"approved\\hashes_rep_unknown_{first_policy}_{second_policy}.csv") and os.path.exists(f"approved\\hashes_rep_good_{first_policy}_{second_policy}.csv"): utils.pathfunctions.generatePathReview(first_policy, second_policy, badpathparts, min_files_for_path) + utils.hashfunctions.generatePublist(first_policy,second_policy,bad_publisher_list) else: print(ct.colorText(f"Please manually approve hashes prior to this step","red")) diff --git a/utils/hashfunctions.py b/utils/hashfunctions.py index b4e8c84..2c45e32 100644 --- a/utils/hashfunctions.py +++ b/utils/hashfunctions.py @@ -367,6 +367,9 @@ def generatePreflights(first_policy, second_policy): pathexclusions = tryToReadCSV(f"approved\\path_needs_approved_{first_policy}_{second_policy}.csv") pathexclusions.to_parquet(f"parquet\\final_path_exclusions_{first_policy}_{second_policy}.parquet", index=False) + publishers = tryToReadCSV(f"approved\\publishers_{first_policy}_{second_policy}.csv") + publishers.to_parquet(f"parquet\\publishers_{first_policy}_{second_policy}.parquet", index=False) + allowbyhash = allhashes[~allhashes['sha256'].isin(pathexclusions['sha256'])] allowbyhash.to_parquet(f"parquet\\final_hash_approvals_{first_policy}_{second_policy}.parquet", index=False) @@ -375,9 +378,25 @@ def generatePreflights(first_policy, second_policy): ct.style_dataframe_dark(allowbyhash, f"preflight\\final_hash_approvals_{first_policy}_{second_policy}.html") ct.style_dataframe_dark(pathexclusions, f"preflight\\final_path_exclusions_{first_policy}_{second_policy}.html") - + ct.style_dataframe_dark(publishers, f"preflight\\publishers_{first_policy}_{second_policy}.html") + del allowbyhash del pathexclusions gc.collect() +def generatePublist(first_policy,second_policy,bad_publisher_list): + + try: + publist = pd.read_parquet(f"parquet\\all_approved_hashes_{first_policy}_{second_policy}.parquet", columns=['publisher']) + except Exception as e: + print(f"Error reading parquet file: {e}") + publist = pd.DataFrame() + + #Drop all not signed, only keep unique values + publist = publist[publist['publisher'] != "Not Signed"].drop_duplicates(subset='publisher') + #Remove Bad publisher if somehow they made it this far + pattern = pathf.regulator(bad_publisher_list) + publist = publist[~publist["publisher"].str.contains(pattern, na=False)] + + publist.to_csv(f"needs_approved\\publishers_{first_policy}_{second_policy}.csv", index=False) \ No newline at end of file diff --git a/utils/policyfunctions.py b/utils/policyfunctions.py index 815d868..0037a37 100644 --- a/utils/policyfunctions.py +++ b/utils/policyfunctions.py @@ -40,10 +40,16 @@ def addPath(url, policy, hash): print(f"Adding the following Path Exclusions to {policy}:") for p in hash: print(p) + +def addPub(url, policy, publist): + print(f"Adding the following Publishers to {policy}:") + for p in publist: + print(p) + def addHashReal(url, allowlistID, hashlist): endpoint = url + '/v1/hash/application/add' - print(ct.colorText("[+] Grabbing All Categories", "cyan")) + payload = { "applicationid" : allowlistID, "hashes" : hashlist @@ -60,7 +66,6 @@ def addHashReal(url, allowlistID, hashlist): def addPathReal(url, grouplistID, pathlist): endpoint = url + '/v1/group/path/add' - print(ct.colorText("[+] Grabbing All Categories", "cyan")) payload = { "groupid" : grouplistID, "path" : pathlist @@ -73,6 +78,22 @@ def addPathReal(url, grouplistID, pathlist): response = requests.request("POST", endpoint, headers=headers, data=payload, verify=False) print(response.text) + +def addPubReal(url, grouplistID, publist): + endpoint = url + '/v1/group/publisher/add' + payload = { + "groupid" : grouplistID, + "publisher" : publist + } + headers = { + "X-APIKey": os.getenv('APIKEY') + } + print(payload) + payload = json.dumps(payload) + response = requests.request("POST", endpoint, headers=headers, data=payload, verify=False) + print(response.text) + + def getPolicyInfo(url, policy, days): executionhist_policy = pd.DataFrame() exehist = pullPolicyExechistories(url, policy, days, True) @@ -92,6 +113,7 @@ def getPolicyInfo(url, policy, days): def sendToPolicy(url, first_policy, second_policy, destination_name, destination_id, allowlist_parent_name, allowlist_parent_id, allowlist_child_name, allowlist_child_id): pathexclusions = pd.read_parquet(f"parquet\\final_path_exclusions_{first_policy}_{second_policy}.parquet") allowbyhash = pd.read_parquet(f"parquet\\final_hash_approvals_{first_policy}_{second_policy}.parquet") + publishers = pd.read_parquet(f"parquet\\publishers_{first_policy}_{second_policy}.parquet") ct.areYouSure() confirmation = input(ct.colorText("Type 'I AGREE' to continue: ","white")) @@ -114,7 +136,10 @@ def sendToPolicy(url, first_policy, second_policy, destination_name, destination ] addPathReal(url, destination_id,processed_paths) - + + publisher_list = publishers['publisher'].tolist() + addPubReal(url, destination_id, publisher_list) + print(ct.colorText(f"Adding hashes to {allowlist_parent_name}", "yellow")) allowlist_parenthashlist = allowbyhash[allowbyhash['reputation_status'] == 'KNOWN']['sha256'].unique().tolist() diff --git a/utils/pretty.py b/utils/pretty.py index 1635dc9..e651d3e 100644 --- a/utils/pretty.py +++ b/utils/pretty.py @@ -264,6 +264,7 @@ def printEnforceChecklist(first_policy, second_policy, allowlist_child_name, all print(colorText(f"4. Manually review the file 'needs_approved\\paths_needing_review_{first_policy}_{second_policy}.csv'", "cyan")) print(colorText(" Remove the rows containing path exclusions you do not approve of" , "cyan")) print(colorText(" When complete, save the csv file to the directory 'approved'", "cyan")) + print(colorText(" Do the same process with the list of publishers forthe same directories", "cyan")) print(colorText(" Preflight Lists will be generated", "cyan")) if os.path.exists(f"approved\\path_needs_approved_{first_policy}_{second_policy}.csv"):