diff --git a/ad_miner/sources/modules/main_page.py b/ad_miner/sources/modules/main_page.py index 2286a7a..a6fb0ae 100644 --- a/ad_miner/sources/modules/main_page.py +++ b/ad_miner/sources/modules/main_page.py @@ -243,7 +243,8 @@ def create_dico_data( "unpriviledged_users_with_admincount": len(users.unpriviledged_users_with_admincount), "priviledge_users_without_admincount": len([dic for dic in users.users_nb_domain_admins if not dic["admincount"]]), "privileged_accounts_outside_Protected_Users": len([dic for dic in users.users_nb_domain_admins if "Protected Users" not in dic["admin type"]]), - "sid_singularities": users.sid_singularities + "sid_singularities": users.sid_singularities, + "pre_windows_2000_compatible_access_group": len(users.pre_windows_2000_compatible_access_group) } dico_data["color_category"] = dico_rating_color @@ -338,7 +339,8 @@ def render( "guest_accounts": f"{dico_data['value']['guest_accounts']} guests accounts are enabled", "up_to_date_admincount": f"{dico_data['value']['priviledge_users_without_admincount']} priviledged accounts don't have admincount and {dico_data['value']['unpriviledged_users_with_admincount']} unpriviledged accounts have admincount", "privileged_accounts_outside_Protected_Users": f"{dico_data['value']['privileged_accounts_outside_Protected_Users']} priviledged accounts are not part of the Protected Users group", - "primaryGroupID_lower_than_1000": f"{dico_data['value']['sid_singularities']} accounts have unknown SIDs or unexpected names" + "primaryGroupID_lower_than_1000": f"{dico_data['value']['sid_singularities']} accounts have unknown SIDs or unexpected names", + "pre_Win_2000_accounts": f"{len(users.pre_windows_2000_compatible_access_group)} unauthenticated users in Pre-Win 2000 Compatible Access group" } descriptions = DESCRIPTION_MAP diff --git a/ad_miner/sources/modules/rating.py b/ad_miner/sources/modules/rating.py index 870a53e..45c33f8 100644 --- a/ad_miner/sources/modules/rating.py +++ b/ad_miner/sources/modules/rating.py @@ -170,7 +170,7 @@ def rating(users, domains, computers, objects, arguments): d[rate_admincount(users.unpriviledged_users_with_admincount, users.users_nb_domain_admins)].append("up_to_date_admincount"), d[1 if len([dic for dic in users.users_nb_domain_admins if "Protected Users" not in dic["admin type"]]) > 0 else 5].append("privileged_accounts_outside_Protected_Users"), d[1 if users.sid_singularities > 0 else 5].append("primaryGroupID_lower_than_1000") - + d[1 if "1-5-7" in [dni[2] for dni in users.pre_windows_2000_compatible_access_group] else 2 if len(users.pre_windows_2000_compatible_access_group) > 0 else 5].append("pre_windows_2000_compatible_access_group") return d diff --git a/ad_miner/sources/modules/requests.json b/ad_miner/sources/modules/requests.json index 40237f5..4b92424 100644 --- a/ad_miner/sources/modules/requests.json +++ b/ad_miner/sources/modules/requests.json @@ -677,7 +677,7 @@ }, "pre_windows_2000_compatible_access_group": { "name": "Pre-Windows 2000 Compatible Access contains unauthenticated users", - "request": "MATCH (n:Group) WHERE n.name STARTS WITH \"PRE-WINDOWS 2000 COMPATIBLE ACCESS@\" MATCH (m)-[r:MemberOf]->(n) WHERE NOT m.objectid ENDS WITH \"-S-1-5-11\" return m.name,m.objectid", + "request": "MATCH (n:Group) WHERE n.name STARTS WITH \"PRE-WINDOWS 2000 COMPATIBLE ACCESS@\" MATCH (m)-[r:MemberOf]->(n) WHERE NOT m.objectid ENDS WITH \"-S-1-5-11\" return m,domain, m.name, m.objectid", "output_type": "list" }, "guest_accounts": { diff --git a/ad_miner/sources/modules/smolcard_class.py b/ad_miner/sources/modules/smolcard_class.py index 33f6c28..f78519a 100644 --- a/ad_miner/sources/modules/smolcard_class.py +++ b/ad_miner/sources/modules/smolcard_class.py @@ -51,6 +51,7 @@ "up_to_date_admincount", "privileged_accounts_outside_Protected_Users", "primaryGroupID_lower_than_1000" + "pre_windows_2000_compatible_access_group" ], "misc": [ "computers_os_obsolete", diff --git a/ad_miner/sources/modules/users.py b/ad_miner/sources/modules/users.py index d55bc33..5d59b0a 100644 --- a/ad_miner/sources/modules/users.py +++ b/ad_miner/sources/modules/users.py @@ -216,6 +216,8 @@ def __init__(self, arguments, neo4j, domain): self.primaryGroupID_lower_than_1000 = neo4j.all_requests["primaryGroupID_lower_than_1000"]["result"] + self.pre_windows_2000_compatible_access_group = neo4j.all_requests["pre_windows_2000_compatible_access_group"]["result"] + # Generate all the users-related pages self.genComputersWithMostAdminsPage() self.genServersCompromisablePage() @@ -248,7 +250,7 @@ def __init__(self, arguments, neo4j, domain): self.genUpToDateAdmincount() self.genProtectedUsers() self.genSID_lower_than_1000() - + self.preWin2000() logger.print_warning(timer_format(time.time() - self.start)) # List of Servers with the most user compromise paths (and if to handle empty cases) @@ -1729,3 +1731,28 @@ def genSID_lower_than_1000(self): grid.setData(sorted_data) page.addComponent(grid) page.render() + + def genPreWin2000(self): + page = Page( + self.arguments.cache_prefix, + "pre_windows_2000_compatible_access_group", + "Pre-Windows 2000 Compatible Access accounts", + "pre_windows_2000_compatible_access_group", + ) + grid = Grid("Pre-Windows 2000 Compatible Access") + grid.setheaders(["Domain", "Name", "User type"]) + + # Sort accounts with anonymous accounts first + sorted_list = [dni for dni in self.pre_windows_2000_compatible_access_group if "1-5-7" in dni[2]] + sorted_list += [dni for dni in self.pre_windows_2000_compatible_access_group if "1-5-7" not in dni[2]] + + data = [] + for domain, account_name, objectid in sorted_list: + tmp_data = {"Domain": ' ' + domain} + tmp_data["Name"] = ' ' + account_name + tmp_data["User type"] = "Unauthenticated" if objectid != "1-5-7" else "Anonymous" + data.append(tmp_data) + + grid.setData(data) + page.addComponent(grid) + page.render() \ No newline at end of file