def group(self, domain): """ Generate statistics for Active Directory groups, such as average group membership. """ print( green("[+] Group Module Selected: Crunching group membership data...")) neo4j_driver = setup_database_conn() domain_metrics = domains.DomainData(neo4j_driver) group_metrics = groups.GroupMetrics(neo4j_driver) users_metrics = users.UserMetrics(neo4j_driver) if domain: all_domains = [domain] else: all_domains = domain_metrics.get_all_domains() for domain in all_domains: # We may get a 'None' domain if the label is missing in BloodHound if domain: print(green("[*] Domain: %s" % domain)) avg_membership_nonrecur = group_metrics.get_avg_group_membership( domain) avg_membership_recur = group_metrics.get_avg_group_membership( domain, True) admin_groups = group_metrics.find_admin_groups(domain) local_admin = group_metrics.find_local_admin_groups(domain) foreign_groups = group_metrics.find_foreign_group_membership( domain) print( green("L.. Average group membership:\t\t\t%s" % avg_membership_nonrecur)) print( green("L.. Average recursive group membership:\t\t%s" % avg_membership_recur)) print( green("L.. Nested groups increased membership by:\t%s" % float(avg_membership_recur - avg_membership_nonrecur))) print(green("L.. Admin groups:")) for group in admin_groups: print(yellow("\t%s" % group)) print(green("L.. Non-Admin groups with Local Admin:")) for group in local_admin: print(yellow("\t%s" % group)) print(green("L.. Groups with foregin group membership:")) for group, foreign_group in foreign_groups.items(): print(yellow("\t%s -> %s" % (group, foreign_group)))
def domain(self, domain): """ Generate information and statistics for domains in the dataset. """ print( green("[+] Domain Module Selected: Crunching domain-related data...")) neo4j_driver = setup_database_conn() domain_metrics = domains.DomainData(neo4j_driver) group_metrics = groups.GroupMetrics(neo4j_driver) users_metrics = users.UserMetrics(neo4j_driver) if domain: all_domains = [domain] else: all_domains = domain_metrics.get_all_domains() for domain in all_domains: # We may get a 'None' domain if the label is missing in BloodHound if domain: print(green("\n[+] Domain: %s" % domain)) operating_systems = domain_metrics.get_operating_systems(domain) gpo_list = domain_metrics.get_all_gpos(domain) da_sessions = domain_metrics.get_systems_with_da(domain) print(green("L.. Number of GPOs:\t%s" % len(gpo_list))) print( green( "L.. Systems that are not Domain Controllers with Domain Admin sessions:" )) if da_sessions: for session in da_sessions: print(yellow("\t%s" % session)) else: print(yellow("\tNone! :D")) print(green("L.. Operating Systems seen in domain:")) for op_sys, count in operating_systems.items(): print(yellow("\t%s\t%s" % (count, op_sys)))
def fox(domain, pass_age): """ Welcome to Fox! Before using Fox, start your Neo4j project containing your BloodHound data. Please review the README for details for the modules and queries.\n Let's crunch some BloodHound data! """ click.clear() print(green(""" █████▒▒█████ ▒██ ██▒ ▓██ ▒▒██▒ ██▒▒▒ █ █ ▒░ ▒████ ░▒██░ ██▒░░ █ ░ ░▓█▒ ░▒██ ██░ ░ █ █ ▒ ░▒█░ ░ ████▓▒░▒██▒ ▒██▒ ▒ ░ ░ ▒░▒░▒░ ▒▒ ░ ░▓ ░ ░ ░ ▒ ▒░ ░░ ░▒ ░ ░ ░ ░ ░ ░ ▒ ░ ░ ░ ░ ░ ░ \t\t v.0.2 """)) # Setup the DB connection and metrics objects neo4j_driver = helpers.setup_database_conn() domain_metrics = domains.DomainData(neo4j_driver) group_metrics = groups.GroupMetrics(neo4j_driver) users_metrics = users.UserMetrics(neo4j_driver) all_domains = helpers.prepare_domains_list(domain_metrics, domain) # A few variables we need for tracking some numbers across domains super_total_users = 0 super_total_enabled_users = 0 super_total_computers = 0 for domain in all_domains: # We may get a 'None' domain if the label is missing in BloodHound if domain: # Neo4j will expect domain names to match what it has in the database, so must be all uppercase domain = domain.upper() print(green("\n[+] Domain: %s" % domain)) # Collect session info print(green("[+] Collecting session data...")) da_sessions = domain_metrics.get_systems_with_da(domain) # Calculations for group membership print(green("[+] Collecting group membership information...")) avg_membership_nonrecur = group_metrics.get_avg_group_membership(domain) avg_membership_recur = group_metrics.get_avg_group_membership(domain, True) dadmins, eadmins, admins = group_metrics.get_admin_groups(domain) admin_groups = group_metrics.find_admin_groups(domain) local_admin = group_metrics.find_local_admin_groups(domain) rdp_users = group_metrics.find_remote_desktop_users(domain) foreign_groups = group_metrics.find_foreign_group_membership(domain) # Collect user object info print(green("[+] Collecting user and computer object information...")) total_users = users_metrics.get_total_users(domain) total_enabled_users = users_metrics.get_total_users(domain, True) total_computers = users_metrics.get_total_computers(domain) unc_deleg_computers = users_metrics.find_unconstrained_delegation(domain) # Calculations for user objects super_total_users += total_users super_total_enabled_users += total_enabled_users super_total_computers = super_total_computers + total_computers # Path to DA calculations print(green("[+] Calculating paths to Domain Admin and averages -- this can take \ some time...")) total_paths = domain_metrics.get_all_da_paths(domain) #avg_path = domain_metrics.avg_path_length(domain) try: percentage_users_path_to_da = 100.0 * (total_paths/total_users) except: percentage_users_path_to_da = 0 try: percentage_comps_path_to_da = 100.0 * (total_paths/total_computers) except: percentage_comps_path_to_da = 0 # Other statistics and data print(green("[+] Querying some additional interesting data... nearly done...")) gpo_list = domain_metrics.get_all_gpos(domain) operating_systems = domain_metrics.get_operating_systems(domain) old_passwords = users_metrics.find_old_pwdlastset(domain, pass_age) special_users = users_metrics.find_special_users(domain) da_spn = users_metrics.find_da_spn(domain) foreign_groups = users_metrics.find_foreign_group_membership(domain) blocker_ous = domain_metrics.find_blocked_inheritance(domain) # Review the data to see if we can detect any missing labels/data and try to name # CollectionMethod types that are missing from the database warning_count = 0 print(yellow("\n[!] WARNINGS for %s:" % domain)) if len(gpo_list) == 0: warning_count += 1 print(yellow("[*] There are zero GPOs for this domain!")) print(yellow("L.. Missing CollectionMethod: GPO")) if total_enabled_users == 0: warning_count += 1 print(yellow("[*] There are no user objects with the Enabled attribute!")) print(yellow("L.. Missing CollectionMethod: ObjectProps")) if not operating_systems: warning_count += 1 print(yellow("[*] There are no computer objects with the operating system attribute!")) print(yellow("L.. Missing CollectionMethod: ObjectProps")) if not avg_membership_nonrecur: warning_count += 1 print(red("[X] Cannot pull group membership data!")) print(red("L.. Data for this domain is too incomplete and will be skipped.")) continue if warning_count == 0: print(green("\tNone! BloodHound data looks good!\n")) # Report domain-related data if len(gpo_list) > 0: print(green("Number of GPOs:\t%s" % len(gpo_list))) if blocker_ous: print(green("OUs blocking inheritance:")) for ou in blocker_ous: print(yellow("\t%s" % ou)) if operating_systems: print(green("Operating Systems seen in domain:")) for key, value in operating_systems.items(): print(yellow("\t%s\t%s" % (value, key))) print(green("Domain Admins tied to SPNs:")) if len(da_spn): for account in da_spn: print(yellow("\t%s" % account)) else: print(green("\tNone! :D")) # Report session data print(green("Systems that are not Domain Controllers with Domain Admin sessions:")) if da_sessions: for session in da_sessions: print(yellow("\t%s" % session)) else: print(green("\tNone! :D")) # Report group-related data print(green("Average group membership:\t\t\t%s" % avg_membership_nonrecur)) print(green("Average recursive group membership:\t\t%s" % avg_membership_recur)) print(green("Nested groups increased membership by:\t\t%s" % float(avg_membership_recur-avg_membership_nonrecur))) print(green("Domain Admins:")) for user in dadmins: print(yellow("\t%s" % user)) print(green("Enterprise Admins:")) for user in eadmins: print(yellow("\t%s" % user)) print(green("Administrators:")) for user in admins: print(yellow("\t%s" % user)) print(green("Other ADMIN groups:")) for group in admin_groups: print(yellow("\t%s" % group)) print(green("Non-Admin groups with Local Admin:")) if local_admin: for group in local_admin: print(yellow("\t%s" % group)) else: print(green("\tNone! :D")) print(green("REMOTE DESKTOP USERS members:")) for member in rdp_users: if "DOMAIN USERS" in member: print(red("\t--> %s" % member)) else: print(yellow("\t%s" % member)) if foreign_groups: print(green("Groups with foregin group membership:")) for group,foreign_group in foreign_groups.items(): print(yellow("\t%s -> %s" % (group, foreign_group))) # Report user statistics print(green("Total users:\t\t\t\t\t%s" % total_users)) print(green("Total enabled users:\t\t\t\t%s (%s disabled)" % (total_enabled_users, total_users-total_enabled_users))) print(green("Users with passwords older than %s months:\t%s" % (pass_age, len(old_passwords)))) print(green("Total computers:\t\t\t\t%s" % total_computers)) print(green("Potentially privileged accounts:")) for account in special_users: print(yellow("\t%s" % account)) print(green("Users with foregin group membership:")) if foreign_groups: for account,group in foreign_groups.items(): print(yellow("\t%s -> %s" % (account, group))) else: print(green("\tNone!")) # Report on computer objects print(green("Computers with Unconstrained Delegation:")) if unc_deleg_computers: for computer in unc_deleg_computers: print(yellow("\t%s" % computer)) else: print(green("\tNone! :D")) # Report on paths print(green("Total paths:\t\t\t\t\t%s" % total_paths)) #print(green("Average path length:\t\t\t\t%s" % avg_path)) print(green("Users with path to a Domain Admin:\t\t%s %%" % percentage_users_path_to_da)) print(green("Machines with path to Domain Admin:\t\t%s %%" % percentage_comps_path_to_da)) # Report totals across domains print(green("\n[+] Totals for all domains in dataset:")) print(green("Total users across domains:\t\t\t%s" % super_total_users)) print(green("Total enabled users across domains:\t\t%s" % super_total_enabled_users)) print(green("Total computers across domains:\t\t\t%s" % super_total_computers))
def user(self, domain, pass_age): """ Generate information and statistics for Active Directory user objects. """ print( green("[+] User Module Selected: Crunching group membership data...")) neo4j_driver = setup_database_conn() domain_metrics = domains.DomainData(neo4j_driver) group_metrics = groups.GroupMetrics(neo4j_driver) users_metrics = users.UserMetrics(neo4j_driver) super_total_users = 0 super_total_enabled_users = 0 super_total_computers = 0 if domain: all_domains = [domain] else: all_domains = domain_metrics.get_all_domains() for domain in all_domains: # We may get a 'None' domain if the label is missing in BloodHound if domain: print(green("\n[+] Domain: %s" % domain)) # Calculations for totals of user objects total_users = users_metrics.get_total_users(domain) total_enabled_users = users_metrics.get_total_users(domain, True) total_computers = users_metrics.get_total_computers(domain) super_total_users = super_total_users + total_users super_total_enabled_users = super_total_enabled_users + total_enabled_users super_total_computers = super_total_computers + total_computers # Path to DA calculations total_paths = domain_metrics.get_all_da_paths(domain) avg_path = domain_metrics.avg_path_length(domain) percentage_users_path_to_da = 100.0 * (total_paths / total_users) percentage_comps_path_to_da = 100.0 * (total_paths / total_computers) # Other statistics and data old_passwords = users_metrics.find_old_pwdlastset(domain, pass_age) special_users = users_metrics.find_special_users(domain) da_spn = users_metrics.find_da_spn(domain) foreign_groups = users_metrics.find_foreign_group_membership( domain) print(green("L.. Total users:\t\t\t\t%s" % total_users)) print( green( "L.. Total enabled users:\t\t\t%s (%s disabled)" % (total_enabled_users, total_users - total_enabled_users))) print(green("L.. Total computers:\t\t\t\t%s" % total_computers)) print(green("L.. Total paths:\t\t\t\t%s" % total_paths)) print(green("L.. Average path length:\t\t\t%s" % avg_path)) print( green("L.. Users with path to a Domain Admin:\t\t%s%%" % percentage_users_path_to_da)) print( green("L.. Machines with path to Domain Admin:\t\t%s%%" % percentage_comps_path_to_da)) print( green("L.. Users with passwords older than %s months:\t%s" % (pass_age, len(old_passwords)))) print(green("L.. Domain Admins tied to SPNs:")) for account in da_spn: print(yellow("\t%s" % account)) print(green("L.. Potentially privileged accounts:")) for account in special_users: print(yellow("\t%s" % account)) print(green("L.. Users with foregin group membership:")) for account, group in foreign_groups.items(): print(yellow("\t%s -> %s" % (account, group))) print( green("\n[*] Total users across domains:\t\t\t%s" % super_total_users)) print( green("[*] Total enabled users across domains:\t\t%s" % super_total_enabled_users)) print( green("[*] Total computers across domains:\t\t%s" % super_total_computers))