# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['goodhound']

package_data = \
{'': ['*']}

install_requires = \
['pandas==1.3.5', 'py2neo==2021.2.3']

entry_points = \
{'console_scripts': ['goodhound = goodhound:main']}

setup_kwargs = {
    'name': 'goodhound',
    'version': '0.8.3',
    'description': 'Attackers think in graphs, defenders think in actions, management think in charts.  GoodHound operationalises Bloodhound by determining the busiest paths to high value targets and creating actionable output to prioritise remediation of attack paths.',
    'long_description': '# GoodHound\n\n```\n   ______                ____  __                      __\n  / ____/___  ____  ____/ / / / /___  __  ______  ____/ /\n / / __/ __ \\/ __ \\/ __  / /_/ / __ \\/ / / / __ \\/ __  / \n/ /_/ / /_/ / /_/ / /_/ / __  / /_/ / /_/ / / / / /_/ /  \n\\____/\\____/\\____/\\__,_/_/ /_/\\____/\\__,_/_/ /_/\\__,_/   \n                                                         \n```\n> Attackers think in graphs, defenders think in actions, management think in charts.\n\nGoodHound operationalises Bloodhound by determining the busiest paths to high value targets and creating actionable output to prioritise remediation of attack paths.\n\n[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/B0B7AAAK2)  \n> I\'m lucky enough to do this for a living. Any donations will be passed on to my local foodbank, animal sanctuary and animal rescue centres.\n\n## Usage\n\n### Quick Start\nFor a very quick start with most of the default options, make sure you have your neo4j server running and loaded with SharpHound data and run:\n```\ngit clone https://github.com/idnahacks/GoodHound.git\ncd GoodHound\npip install -r requirements.txt\npython -m goodhound -p "neo4jpassword"\n```\nThis will process the data in neo4j and output 3 csv reports in the GoodHound directory.\n\n![Demo](images/demo.gif)\n\n\n### Default behaviour\n\nAll options are __optional__.  \nThe default behaviour is to connect to a neo4j server setup with the default location (bolt://localhost:7687) and credentials (neo4j:neo4j), calculate the busiest paths from non-admin users to highvalue targets, the "weakest links" (the links of an attack path that are seen across many paths), and some grandtotals.  \n3 separate csv files will be created with details for each of these 3 sections.\n\nThe neo4j database will need to already have the Sharphound collector output uploaded using the Upload button in the Bloodhound GUI. An example Sharphound output collected using [Bad Blood](https://github.com/davidprowe/BadBlood) on a [Detection Labs](https://detectionlab.network/) can be found in this repo at [/Sample%20SharpHound%20Output](/Sample%20SharpHound%20Output).\n\n## The Output\n### Summary Report\nThe Summary report contains some high level information regarding the number of paths found, the number of enabled non-admin users that are exposed to an attack path, and the number of paths that have been seen before based on the entries in the GoodHound local database.  \n\nThe end goal is to reduce the number of exposed users, by taking a two pronged approach.  \nBusiest paths will highlight attack paths that are exposed to the greatest number of users.  \nWeakest links will highlight links that might help to close down the number of paths available.\n\n### Busiest Paths Report\nThe output shows a total number of unique users that have a path to a HighValue target.  \nIt then breaks this down to individual paths, ordered by the risk score (more on this later).  \nEach path is then displayed showing the starting group, the number of non-admin users within that path, the number of hops, the risk score, a text version of the path and also a Cypher query. This cypher query can be directly copied into the Raw Query bar in Bloodhound for a visual representation of the attack path. \n\n### Weakest Links Report\nThe weakest links report is a way to potentially find links of attack paths that repeatedly show up in the dataset. For each weak link shown the report will also tell you how many of the total attack paths that was seen in.\n\n\n## Options\n\n### Database settings\n-s can be used to point GoodHound to a server other than the default localhost installation (bolt://localhost:7687)  \n-u can be used to set the neo4j username  \n-p can be used to set the neo4j password  \n\n### Output formats\n-o can be used to select from:  \n- stdout -displays the output on screen\n- csv saves a comma separated values file for use with reporting or MI (completing the graphs, actions, charts trifecta in the tagline)\n- md or markdown to display a markdown formatted output  \n\n-d an optional filepathdirectory path for the csv output option \n\nBy default the output is csv in the current working directory.\n\n-q supresses all output  \n-v enables verbose output  \n--debug enables debug output  \n\n### Number of results\n-r can be used to select the amount of results to show. By default the top 5 busiest paths are displayed.  \n-sort can be used to sort by:\n - number of users with the path (descending)\n - hop count (ascending)\n - risk score (descending)\n\n### Schema\n-sch select a file containing cypher queries to set a custom schema to alter the default Bloodhound schema. This can be useful if you want to set the \'highvalue\' label on AD objects that are not covered as standard, helping to provide internal context.\nFor example, you want to add the highvalue label to \'dbserver01\' because it contains all of your customer records. The schema file to load in could contain the following cypher query:  \n```\nmatch (c:Computer {name:\'DBSERVER01@YOURDOMAIN.LOCAL\'}) set c.highvalue=TRUE\n```\nThe schema can contain multiple queries, each on a separate line. \n\n### SQLite Database\nBy default Goodhound stores all attack paths in a SQLite database called goodhound.db stored in the local directory. This gives the opportunity to query attack paths over time.  \n--db-skip will skip logging anything to a local database  \n--sql-path can be used to point Goodhound to a SQLite db file that is not stored in the default location. The db file will be created in the set location if it does not already exist.\n\n## Performance\n\nLarger datasets can take time to process.  \nGoodHound does "warm-up" the database using the same query that the Warm-Up Database option in the Bloodhound GUI does, however the Neo4j documentation suggests that this is no longer necessary, and in practice I haven\'t seen it make any different on Neo4j 4.0 and greater.  \nThere are also many guides for tuning the neo4j database for increased performance which are out of scope here (although if I make any significant improvements I\'ll document the findings).\n\n## Installation\n\n### Pre-requisites\n- Python and pip already installed.\n- Both neo4j and bloodhound will need to be already installed. The docs at https://bloodhound.readthedocs.io/en/latest/#install explain this well.\n\n### Downloading GoodHound\nEither download using git or by downloading the zip file and extract to your chosen location.\n```\ngit clone https://github.com/idnahacks/GoodHound.git\ncd goodhound\n```\n__OR__\n```\nhttps://github.com/idnahacks/GoodHound/archive/refs/heads/main.zip\n```\n\n### Installing\n- Install required Python modules.  \n- Goodhound will install py2neo and pandas libraries, if you do not wish to change any local modules you already have installed it is recommended to use pipenv.  \n```\npip install -r requirements.txt\n```\n\n## SQLite Database\nBy default Goodhound will insert all of attack paths that it finds into a local SQLite database located in a db directory inside the current working directory.  \nThis database can be then queried separately using the SQLite tools and queries. More details on that can be found [here](sqlqueries.md).\n\n## Risk Score\nThe Risk Score is a mechanism to help prioritise remediation. It is calculated based on the Exploit Cost and the number of non-admin users exposed to that attack path. The more users that are exposed, and the lower the exploit cost, the higher the risk score.  \n**It is not intended to be a risk assessment in and of itself, and the intention is not to assign severities such as Critical, High, Medium etc to certain scores.**\n\nThe score is calculated using the following formula:  \n```\nRisk Score = (MaxExploitCostPossible - ExploitCost) / MaxExploitCostPossible * %ofEnabledNon-AdminUserswiththepath\n```\n\nMaxExploitCostPossible is 3 * the maximum number of hops seen across all attack paths. 3 is chosen because it is the highest score any single hop in an attack path can have.\n\n### Exploit Cost\nExploit Cost is an estimation of how noisy or complex a particular attack path might be.  (Kudos to the [ACLPWN](https://github.com/fox-it/aclpwn.py) project for this idea.)  \nFor example, if an attacker has compromised userA and userA is a member of groupB then that step in the attack path doesn\'t require any further exploitation or real opsec considerations.  \nConversely if an attacker has compromised a user\'s workstation which also has an admin user session on it, to exploit this the attacker would (possibly) need to elevate permissions on the workstation and run something like Mimikatz to extract credentials from memory. This would require OPSEC considerations around monitoring of LSASS processes and also potentially require endpoint protectionbypasses. All of which make the exploitation that little bit more difficult.\n\n*These scores have been assigned based upon my personal best judgement. They are not set in stone and discussions around the scoring are welcome and will only help to improve this.**\nThe scores assigned to each exploit are:\n| Relationship        | Target Node Type    | OPSEC Considerations | Possible Protections to Bypass | Possible Privesc Required | Cost |\n|---------------------|---------------------|----------------------|--------------------------------|---------------------------|------|\n| Memberof            | Group               | No                   | No                             | No                        | 0    |\n| HasSession          | Any                 | Yes                  | Yes                            | Yes                       | 3    |\n| CanRDP              | Any                 | No                   | No                             | No                        | 0    |\n| Contains            | Any                 | No                   | No                             | No                        | 0    |\n| GPLink              | Any                 | No                   | No                             | No                        | 0    |\n| AdminTo             | Any                 | Yes                  | No                             | No                        | 1    |\n| ForceChangePassword | Any                 | Yes                  | No                             | No                        | 1    |\n| AllowedToDelegate   | Any                 | Yes                  | No                             | No                        | 1    |\n| AllowedToAct        | Any                 | Yes                  | No                             | No                        | 1    |\n| AddAllowedToAct     | Any                 | Yes                  | No                             | No                        | 1    |\n| ReadLapsPassword    | Any                 | Yes                  | No                             | No                        | 1    |\n| ReadGMSAPassword    | Any                 | Yes                  | No                             | No                        | 1    |\n| HasSidHistory       | Any                 | Yes                  | No                             | No                        | 1    |\n| CanPSRemote         | Any                 | Yes                  | No                             | No                        | 1    |\n| ExecuteDcom         | Any                 | Yes                  | No                             | No                        | 1    |\n| SqlAdmin            | Any                 | Yes                  | No                             | No                        | 1    |\n| AllExtendedRights   | Group/User/Computer | Yes                  | No                             | No                        | 1    |\n| AddMember           | Group               | Yes                  | No                             | No                        | 1    |\n| AddSelf             | Group               | Yes                  | No                             | No                        | 1    |\n| GenericAll          | Group/User/Computer | Yes                  | No                             | No                        | 1    |\n| WriteDACL           | Group/User/Computer | Yes                  | No                             | No                        | 1    |\n| WriteOwner          | Group/User/Computer | Yes                  | No                             | No                        | 1    |\n| Owns                | Group/User/Computer | Yes                  | No                             | No                        | 1    |\n| GenericWrite        | Group/User/Computer | Yes                  | No                             | No                        | 1    |\n| AllExtendedRights   | Domain              | Yes                  | Yes                            | No                        | 2    |\n| GenericAll          | Domain              | Yes                  | Yes                            | No                        | 2    |\n| WriteDACL           | Domain              | Yes                  | Yes                            | No                        | 2    |\n| WriteOwner          | Domain              | Yes                  | Yes                            | No                        | 2    |\n| Owns                | Domain              | Yes                  | Yes                            | No                        | 2    |\n| GenericAll          | GPO/OU              | Yes                  | No                             | No                        | 1    |\n| WriteDACL           | GPO/OU              | Yes                  | No                             | No                        | 1    |\n| WriteOwner          | GPO/OU              | Yes                  | No                             | No                        | 1    |\n| Owns                | GPO/OU              | Yes                  | No                             | No                        | 1    |\n| WriteSPN            | User                | Yes                  | No                             | No                        | 1    |\n| AddKeyCredentialLink| Any                 | Yes                  | Yes                            | No                        | 2    |\n\n\n## Acknowledgments\n- The [py2neo](https://py2neo.org) project which makes this possible.\n- The [PlumHound](https://github.com/PlumHound/PlumHound) project which gave me the idea of creating something similar which suited my needs.\n- The [aclpwn](https://github.com/fox-it/aclpwn.py) for the idea around exploit cost.\n- The [Bloodhound Gang Slack channel](https://bloodhoundhq.slack.com) for Cypher help.\n- The [BloodHound project](https://bloodhound.readthedocs.io/en/latest/index.html) for changing the world and for continuing their support for the Open-Source community even when having a commercial offering.\n',
    'author': 'Andi Morris',
    'author_email': 'andi.morris@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/idnahacks/GoodHound',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'entry_points': entry_points,
    'python_requires': '>=3.9.2,<4.0.0',
}


setup(**setup_kwargs)
