diff --git a/AirlockTools.py b/AirlockTools.py index 575d060..8da894c 100644 --- a/AirlockTools.py +++ b/AirlockTools.py @@ -80,7 +80,7 @@ def menu_main(): ct.displayIntro(); print(ct.colorText("1. 🖥️ - Get All Events for Single Device", "yellow")) print(ct.colorText("2. 🎫 - OTP", "yellow")) - print(ct.colorText("3. ⏱️ - Placeholder", "yellow")) + print(ct.colorText("3. 🔇 - Find Quiet Hosts", "yellow")) print(ct.colorText("4. 🔒 - Prepare Policy For Enforcement", "yellow")) print(ct.colorText("5. 🔄 - Update Audit Policies from Enforcement Policies", "yellow")) print(ct.colorText("6 🔍 - Device Search", "yellow")) @@ -92,7 +92,7 @@ def menu_main(): elif choice == "2": menu_otp() elif choice == "3": - pass + utils.clientfunctions.findQuietAgents(url) elif choice == "4": utils.policyfunctions.prepare_to_enforce(url, bad_publisher_list, pups, badpathparts, threat_tolerance_constant, path_exclusion_constant, min_files_for_path) elif choice == "5": diff --git a/utils/clientfunctions.py b/utils/clientfunctions.py index bdee8b8..63efc61 100644 --- a/utils/clientfunctions.py +++ b/utils/clientfunctions.py @@ -349,4 +349,80 @@ def returnToEnforcement(url, device_df, policy_relationship_map, bad_publisher_l break else: print(ct.colorText("Invalid choice. Please try again.", "red")) - """ \ No newline at end of file + """ + +def findQuietAgents(url): + + choice, policynames, policyid = policyf.listPolicies(url) + policy = policynames[choice] + groupid = policyid[choice] + agents = findGroupAgents(url,groupid) + + while True: + try: + history_days = int(input("Enter the how many days in of history do you want to pull - select a number between 1 and 150: ")) + if 1 <= history_days <= 150: + break + else: + print("Invalid input. Please enter a number between 1 and 150.") + except ValueError: + print("Invalid input. Please enter a valid integer.") + + policy_exec_history = policyf.getPolicyInfo(url, policy, [1, 2, 6, 7], history_days) + + # Count occurrences of each hostname in the executions dataframe + hostname_counts = policy_exec_history['hostname'].value_counts() + + # Map those counts to the hostnames in the first dataframe + agents['execution_count'] = agents['hostname'].map(hostname_counts).fillna(0).astype(int) + + agents = agents.sort_values(by=['execution_count', 'hostname'], ascending=[True, True]) + + print(ct.colorText(f"Saving CSV to {policy}_agents_last_{history_days}_days.csv","green")) + agents.to_csv(f"{policy}_agents_last_{history_days}_days.csv", index=False) + + + # Count hosts with execution_count == 0 + zero_count = (agents['execution_count'] == 0).sum() + + # Total number of hosts + total_hosts = len(agents) + + # Calculate percentage + zero_percentage = (zero_count / total_hosts) * 100 + + # Print results + print(f"Number of hosts with execution_count = 0: {zero_count}") + print(f"Percentage of hosts with execution_count = 0: {zero_percentage:.2f}%") + + + +def findGroupAgents(url, groupid): + endpoint = url + '/v1/agent/find' + payload = { + "groupid" : f"{groupid}" + } + headers = {"X-APIKey": os.getenv('APIKEY')} + payload = json.dumps(payload) + response = requests.post(endpoint, headers=headers, data=payload, verify=False) + result = json.loads(response.text) + data = pd.DataFrame(result["response"]["agents"]) + group_ids = sorted(data['groupid'].unique().tolist()) + group_policy_map = {} + + for groupid in group_ids: + policy_name = getPolicyName(url, groupid) + group_policy_map[groupid] = policy_name + + data['policy_name'] = data['groupid'].map(group_policy_map) + + status_map = { + 0: 'Offline', + 1: 'Online', + 2: 'Hidden', + 3: 'Safemode' + } + + data['status'] = data['status'].map(status_map) + return(data) + return(data) \ No newline at end of file diff --git a/utils/policyfunctions.py b/utils/policyfunctions.py index e39bbaf..568e531 100644 --- a/utils/policyfunctions.py +++ b/utils/policyfunctions.py @@ -436,26 +436,7 @@ def prepare_to_enforce(url, bad_publisher_list, pups, badpathparts, threat_toler if choice == "1": - while True: - choice, policynames, policyid = listPolicies(url) - selected_policy = policynames[choice] - - if selected_policy not in policylist: - policylist.append(selected_policy) - - while True: - answer = input(ct.colorText("Do you want to load another policy? (yes/no): ", "white")).strip().lower() - if answer in ("no", "n"): - break # Exit the inner loop and then the outer loop - elif answer in ("yes", "y"): - break # Exit the inner loop and continue the outer loop - else: - print(ct.colorText("Please answer with 'yes' or 'no'.", "red")) - - if answer in ("no", "n"): - break - - print(policylist) + policylist, policyids = getMultiplePolicySelections(url) elif choice == "2": @@ -609,3 +590,32 @@ def savePreFlights(appr_base_dir, parq_base_dir, pflight_base_dir): df.to_parquet(f"{parq_base_dir}{name}.parquet", index=False) ct.style_dataframe_dark(df, f"{pflight_base_dir}{name}.html") +def getMultiplePolicySelections(url): + policynameslist = [] + policyidlist = [] + while True: + choice, policynames, policyid = listPolicies(url) + selected_policy = policynames[choice] + selected_policyid = policyid[choice] + + if selected_policy not in policynameslist: + policynameslist.append(selected_policy) + + if selected_policyid not in policyidlist: + policyidlist.append(selected_policyid) + + + while True: + answer = input(ct.colorText("Do you want to load another policy? (yes/no): ", "white")).strip().lower() + if answer in ("no", "n"): + break # Exit the inner loop and then the outer loop + elif answer in ("yes", "y"): + break # Exit the inner loop and continue the outer loop + else: + print(ct.colorText("Please answer with 'yes' or 'no'.", "red")) + + if answer in ("no", "n"): + break + + + return policynameslist, policyidlist \ No newline at end of file