GithubHelp home page GithubHelp logo

idnahacks / goodhound Goto Github PK

View Code? Open in Web Editor NEW
439.0 9.0 41.0 4.47 MB

Uses Sharphound, Bloodhound and Neo4j to produce an actionable list of attack paths for targeted remediation.

Python 100.00%
active-directory activedirectory bloodhound neo4j py2neo python3 blueteam redteam purpleteam cybersecurity

goodhound's Introduction

GoodHound

PyPI - Downloads

   ______                ____  __                      __
  / ____/___  ____  ____/ / / / /___  __  ______  ____/ /
 / / __/ __ \/ __ \/ __  / /_/ / __ \/ / / / __ \/ __  / 
/ /_/ / /_/ / /_/ / /_/ / __  / /_/ / /_/ / / / / /_/ /  
\____/\____/\____/\__,_/_/ /_/\____/\__,_/_/ /_/\__,_/   
                                                         

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.

ko-fi

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.

Usage

Quick Start

For 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:

pip install goodhound
goodhound -p "neo4jpassword"

This will process the data in neo4j and output 3 csv reports in the current working directory.

Demo

Documentation

All documentation can be found in the wiki

Acknowledgments

  • The py2neo project which makes this possible.
  • The PlumHound project which gave me the idea of creating something similar which suited my needs.
  • The aclpwn for the idea around exploit cost.
  • The Bloodhound Gang Slack channel for Cypher help.
  • The BloodHound project for changing the world and for continuing their support for the Open-Source community even when having a commercial offering.

goodhound's People

Contributors

idnahacks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

goodhound's Issues

Password with & symbol

Do not use the standard neo4j password and our password contained a & symbol, the password not parsed properly from the parameters and is being seen as a command.

Database connection failed

Despite removing every possible iteration of user-failure - it appears that I keep getting "database connection failure"

Nested group memberships

sometimes a path shows up twice if one group is a member of another group. An if statement to see if $group ismember of $group then break might work and might even speed up the process

Temporal tracking

Can paths be stored in a sqlite database with a timestamp to add some temporal tracking of paths?

Bloodhound 4.1 issue with highvalue attribute

The latest version of Bloodhound (4.1) currently has a bug where it doesn't set the highvalue property for anywhere where it's not TRUE. This means the queries in GoodHound will not pull results properly.

I'll work around this by setting it manually.

Repeated results

In many cases, a single starting group will have a number of onward paths and these are all being displayed in the busiest paths result.

Realistically, in most cases if the issue exposing the starting group is resolved in the AD environment, the other onward paths would also be no longer exposed, and so a way to just display the unique starting groups with the highest risk score will help to provide more useful results.

Error with goodhound.py when [0] == None

Location: https://github.com/idnahacks/GoodHound/blob/main/goodhound.py#L185

When I run this code, I see that I have a few entries where the group is "None". Currently, I am doing this to resolve:

df = pd.DataFrame(allresults)
allresults = df[~df[0].isna()].values.tolist()

Error:

sorted(allresults, key=lambda i: (i[0], -i[5]))
Traceback (most recent call last):
  File "<string>", line 1, in <module>
TypeError: '<' not supported between instances of 'NoneType' and 'str'

Testing:

df = pd.DataFrame(allresults)
len(df[df[0].isna()])
4

Bloodhound query output

If the Bloodhound query output can be adjusted to show the exact path, rather than the start - end nodes this will rapidly speed up using these queries for reporting.

Add check for paths to principals that can perform DCSync

As DCSync requires both GetChanges and GetChanges all I think it needs to be a separate query to the main one,

The script needs to look for these principals, check whether they will already by picked up by the main query and if not run a shortestpath to these principals query..

py2neo version issue

py2neo==2023.2.3 is known as py2neo-history.

if we try to install goodhound "pip install goodhound". It is showing error.

 pip install goodhound
Defaulting to user installation because normal site-packages is not writeable
Collecting goodhound
  Using cached goodhound-1.1.2-py3-none-any.whl (27 kB)
Collecting pandas==1.3.5 (from goodhound)
  Using cached pandas-1.3.5.tar.gz (4.7 MB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
INFO: pip is looking at multiple versions of goodhound to determine which version is compatible with other requirements. This could take a while.
Collecting goodhound
  Using cached goodhound-1.1.1-py3-none-any.whl (27 kB)
  Using cached goodhound-1.1.0-py3-none-any.whl (27 kB)
  Using cached goodhound-1.0.1-py3-none-any.whl (26 kB)
  Using cached goodhound-1.0.0-py3-none-any.whl (29 kB)
  Using cached goodhound-0.8.3-py3-none-any.whl (29 kB)
  Using cached goodhound-0.8.2-py3-none-any.whl (29 kB)
  Using cached goodhound-0.8.1-py3-none-any.whl (25 kB)
INFO: pip is still looking at multiple versions of goodhound to determine which version is compatible with other requirements. This could take a while.
  Using cached goodhound-0.8.0-py3-none-any.whl (25 kB)
ERROR: Cannot install goodhound==0.8.0, goodhound==0.8.1, goodhound==0.8.2, goodhound==0.8.3, goodhound==1.0.0, goodhound==1.0.1, goodhound==1.1.0, goodhound==1.1.1 and goodhound==1.1.2 because these package versions have conflicting dependencies.

The conflict is caused by:
    goodhound 1.1.2 depends on py2neo==2021.2.3
    goodhound 1.1.1 depends on py2neo==2021.2.3
    goodhound 1.1.0 depends on py2neo==2021.2.3
    goodhound 1.0.1 depends on py2neo==2021.2.3
    goodhound 1.0.0 depends on py2neo==2021.2.3
    goodhound 0.8.3 depends on py2neo==2021.2.3
    goodhound 0.8.2 depends on py2neo==2021.2.3
    goodhound 0.8.1 depends on py2neo==2021.2.3
    goodhound 0.8.0 depends on py2neo==2021.2.3

To fix this you could try to:
1. loosen the range of package versions you've specified
2. remove package versions to allow pip attempt to solve the dependency conflict

ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts

can anyone help me out please

Nested groups can timeout

There have been issues seen in larger environments where searching for nested groups with the *1.. query never completes.

Memory usage problem

Hi,

I am having issues with neo4j using too much memory as a result of goodhound execution, I have not been able to get goodhound to finish running at all because of this, even with a low '-r' parameter.

I have set the max heap size to 28GB, even then it fails with the error below, I cannot tell what specific query is causing this. Can the script or query be optimized in anyway to avoid this problem?

DEBUG:Adding connection pool for profile ConnectionProfile('bolt://localhost:7687')
DEBUG:Trying to acquire connection from pool <py2neo.client.ConnectionPool object at 0x000001CEE1CA48D0>
DEBUG:[#0000] C: (Dialing <localhost:7687>)
DEBUG:[#EB39] S: (Accepted)
DEBUG:[#EB39] C: <BOLT>
DEBUG:[#EB39] C: <PROTOCOL> 4.3~4.0 | 4.0 | 3.0 | 2.0
DEBUG:[#EB39] S: <PROTOCOL> 4.3
DEBUG:[#EB39] C: HELLO {'user_agent': 'py2neo/2021.2.3 Python/3.11.1-final-0 (win32)', 'scheme': 'basic', 'principal': 'neo4j', 'credentials': '*******'}
DEBUG:[#EB39] C: (Sent 133 bytes)
DEBUG:[#EB39] S: SUCCESS {'server': 'Neo4j/4.4.12', 'connection_id': 'bolt-138', 'hints': {}}
DEBUG:Releasing connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> from thread <_MainThread(MainThread, started 3432)>
DEBUG:Connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> does not belong to pool <py2neo.client.ConnectionPool object at 0x000001CEE1CA48D0>
DEBUG:Connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> acquired by thread <_MainThread(MainThread, started 3432)>
DEBUG:Releasing connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> from thread <_MainThread(MainThread, started 3432)>
Warming up database
DEBUG:Attempting to acquire read-write connection to default database
DEBUG:Using connection pool <py2neo.client.ConnectionPool object at 0x000001CEE1CA48D0>
DEBUG:Trying to acquire connection from pool <py2neo.client.ConnectionPool object at 0x000001CEE1CA48D0>
DEBUG:Connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> acquired by thread <_MainThread(MainThread, started 3432)>
DEBUG:[#EB39] C: RUN 'MATCH (n) OPTIONAL MATCH (n)-[r]->() RETURN count(n.name) + count(r.isacl)' {} {}
DEBUG:[#EB39] C: PULL {'n': -1, 'qid': -1}
DEBUG:[#EB39] C: (Sent 99 bytes)
DEBUG:[#EB39] S: SUCCESS {'t_first': 15, 'fields': ['count(n.name) + count(r.isacl)']}
DEBUG:[#EB39] S: RECORD * 1
DEBUG:[#EB39] S: SUCCESS {'bookmark': 'FB:', 'type': 'r', 't_last': 31939, 'db': 'neo4j'}
DEBUG:Releasing connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> from thread <_MainThread(MainThread, started 3432)>
INFO:Setting cost.
DEBUG:Attempting to acquire read-write connection to default database
DEBUG:Using connection pool <py2neo.client.ConnectionPool object at 0x000001CEE1CA48D0>
DEBUG:Trying to acquire connection from pool <py2neo.client.ConnectionPool object at 0x000001CEE1CA48D0>
DEBUG:Connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> acquired by thread <_MainThread(MainThread, started 3432)>
DEBUG:[#EB39] C: RUN 'MATCH (n)-[r:MemberOf]->(m:Group) SET r.cost = 0' {} {}
DEBUG:[#EB39] C: PULL {'n': -1, 'qid': -1}
DEBUG:[#EB39] C: (Sent 73 bytes)
DEBUG:[#EB39] S: SUCCESS {'t_first': 12547, 'fields': []}
DEBUG:[#EB39] S: FAILURE {'code': 'Ne
o.TransientError.General.OutOfMemoryError', 'message': "There is not enough memory to perform the current task. Please try increasing 'dbms.memory.heap.max_size' in the neo4j configuration (normally in 'conf/neo4j.conf' or, if you are using Neo4j Desktop, found through the user interface) or if you are running an embedded installation increase the heap by using '-Xmx' command line flag, and then restart the database."}
DEBUG:[#EB39] C: RESET
DEBUG:[#EB39] C: (Sent 6 bytes)
DEBUG:[#EB39] S: SUCCESS {}
DEBUG:Releasing connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> from thread <_MainThread(MainThread, started 3432)>
DEBUG:Releasing connection <py2neo.client.bolt.Bolt4x3 object at 0x000001CEE2085510> from thread <_MainThread(MainThread, started 3432)>
WARNING:Error setting cost!

allow filtering of non-highvalue admins

Currently Goodhound regards all non-highvalue users to be regular non-admin users.

If a domain has tiered admin structures there should be a way to point goodhound to a set of standard users as part of the custom schema option.

DCSync false positives

False positives can occur when there is a GetChanges edge without the GetChangesAll edge.

This might need to be separated out into another query.

db folder creation seems broken

If the default folder structure for the sqlite db isn't present it should be autocreated. This doesn't appear to be the case.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.