{"id":21988096,"url":"https://github.com/nvisosecurity/pycobalthound","last_synced_at":"2025-04-30T11:05:35.204Z","repository":{"id":47959571,"uuid":"406451744","full_name":"NVISOsecurity/pyCobaltHound","owner":"NVISOsecurity","description":"pyCobaltHound is an Aggressor script extension for Cobalt Strike which aims to provide a deep integration between Cobalt Strike and Bloodhound. ","archived":false,"fork":false,"pushed_at":"2023-05-25T10:27:20.000Z","size":697,"stargazers_count":136,"open_issues_count":1,"forks_count":22,"subscribers_count":4,"default_branch":"main","last_synced_at":"2023-11-07T18:51:59.725Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/NVISOsecurity.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-09-14T16:53:35.000Z","updated_at":"2023-11-03T07:52:01.000Z","dependencies_parsed_at":"2022-08-12T15:10:53.087Z","dependency_job_id":null,"html_url":"https://github.com/NVISOsecurity/pyCobaltHound","commit_stats":null,"previous_names":[],"tags_count":0,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NVISOsecurity%2FpyCobaltHound","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NVISOsecurity%2FpyCobaltHound/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NVISOsecurity%2FpyCobaltHound/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/NVISOsecurity%2FpyCobaltHound/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/NVISOsecurity","download_url":"https://codeload.github.com/NVISOsecurity/pyCobaltHound/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":227196131,"owners_count":17746178,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-29T19:15:45.193Z","updated_at":"2024-11-29T19:15:46.000Z","avatar_url":"https://github.com/NVISOsecurity.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cimg src=\"./images/pyCobaltHound_Logo.png\" style=\"zoom:200%;\" /\u003e\n\n## Quick summary\n\n`pyCobaltHound` is an Aggressor script extension for Cobalt Strike which aims to provide a deep integration between `Cobalt Strike` and `Bloodhound`.\n\n`pyCobaltHound` strives to assists red team operators by:\n\n- Automatically querying the `BloodHound` database to discover escalation paths opened up by newly collected credentials.\n- Automatically marking compromised users and computers as owned. \n- Allowing operators to quickly and easily investigate the escalation potential of beacon sessions and users.\n\nTo accomplish this, `pyCobaltHound` uses a set of built-in queries. Operators are also able to add/remove their own queries to fine tune `pyCobaltHound's` monitoring capabilities. This grants them the flexibility to adapt `pyCobaltHound` on the fly during engagements to account for engagement-specific targets (users, hosts etc..).\n\n## Installation \u0026 usage\n\nTo install `pyCobaltHound` clone this repository. Do not forget to also clone the included submodule!\n\nYou can use the following command:\n\n- `git clone https://github.com/NVISOsecurity/pyCobaltHound.git --recurse-submodules`\n\n### Dependencies\n\nEnsure that the following dependencies are correctly installed:\n\n#### PyCobalt\n\n`PyCobalt` is a Python API for `Cobalt Strike`. It exposes many Aggressor functions to be used directly from Python.\n\n##### Setup\n\nEnsure that you have `Python3+` installed. While `PyCobalt` may work on macOS and Windows as well, we have only really tested it on Linux.\n\nThere are two ways to use the `PyCobalt` Python library:\n\n1. Run it straight out of the repository using [PYTHONPATH](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH). `pyCobaltHound` takes this approach, setting the search path from within the Python program using the variable [`sys.path`](https://docs.python.org/3/library/sys.html#sys.path) variable.\n2. Install the `PyCobalt` Python library. To do so, run `python3 setup.py install`. You will have to modify `pycobalthound.py` to ensure that it used the installed library instead of the one in  the included repository.\n\n##### Remarks\n\n- Note that there is no guarantee that the `PyCobalt` project will be maintained in the future. In fact,  the latest update to the project was to incorporate the changes made in `Cobalt Strike 4.2`. Since `pyCobaltHound` only really uses basic Aggressor functions to interface with `Cobalt Strike` and its operator however this is not a big problem for `pyCobaltHound`.\n- The  `PyCobalt`  submodule used in this project is a fork done by us. We do not control the `PyCobalt` repository however. \n\n##### Tips \u0026 tricks\n\n- `PyCobalt` comes with some Script Console commands to manage the running Python scripts. When you reload your Aggressor script you should explicitly stop the Python scripts first. Otherwise they'll run forever doing nothing. During `pyCobaltHound's` development we noticed that this can also lead to undefined behavior.\n\n  Reloading `pyCobaltHound` can be done as follows:\n\n  ```\n  aggressor\u003e python-stop-all`\n  [pycobalt] Asking script to stop: /root/pycobalthound/pycobalthound.py\n  [pycobalt] Script process exited: /root/pycobalthound/pycobalthound.py\n  \n  aggressor\u003e reload example.cna`\n  [pycobalt] Executing script /root/pycobalthound/pycobalthound.py\n  ```\n\n- For `PyCobalt` to work properly you can only call `PyCobalt` in one Aggressor script. Keep this in mind if you want to use `pyCobaltHound` together with other Aggressor scripts that use `PyCobalt`. Our approach is to have an Aggressor script with a calls to python() and include() for every `PyCobalt` based tool.\n\n#### notify2 (Optional)\n\n[`notify2`](https://notify2.readthedocs.io/en/latest/) is - or was - a package to display desktop notifications on Linux. As we will see later `pyCobaltHound` supports a few ways of notifying the operator.  `notify2` is used on Linux to send notifications  to the notification daemon over D-Bus.\n\nTo enable this, `notify2` needs to be installed using:\n\n`pip install notify2`\n\n### Usage in Cobalt Strike\n\nUsing `pyCobaltHound` in `Cobalt Strike` is as simple as importing the `pycobalthound.cna` Aggressor script into your client. Once this is done you should see a`pyCobaltHound` menu appear in your `Cobalt Strike` menubar.\n\n![](./images/aggressor_menu_without_queries.png)\n\n## Usage\n\n### Credential store monitoring\n\n`pyCobaltHound's` initial goal was to monitor `Cobalt Strike's` credential cache (`View` \u003e `Credentials`) for new entries. It does this by reacting to the *on_credentials* event that `Cobalt Strike` fires when changed to the credential store are made.\n\nWhen this event is fired, `pyCobaltHound` will:\n\n1. Parse and validate the data recieved from `Cobalt Strike`\n2. Check if it has already investigated these entities by reviewing it's cache\n3. Add the entities to a cache for future runs\n4. Check if the entities exist in the `BloodHound` database\n5. Mark the entities as owned\n6. Query the `BloodHound` database for each new entity using both built-in and custom queries.\n7. Parse the returned results, notify the operator of any interesting findings and write them to a basic HTML report.\n\nSince all of this takes place asynchronously from the main `Cobalt Strike` client this process should not block your UI so you can keep working while `pyCobaltHound` investigates away in the background.\n\n`pyCobaltHound` uses seperate caches per teamserver to prevent issues when using multiple teamservers.\n\n#### Removing entities from the cache\n\nSometimes there are situations where you would want to investigate specific users (or the entire credential store) again. This might be the case when you've uploaded new data into the `BloodHound` database. \n\nSince `pyCobaltHound` should have investigated (and therefore cached) all entities in your credential store already it will not evaluate them against this new data without some operator intervention.\n\nTwo methods are available to operators to control which entities are cached.\n\n##### Removing specific entities\n\nIn cases where you wish to remove a specific entity (or multiple) from the cache you can do so in the credential viewer (`View` \u003e `Credentials`). Simply select your target(s) and click the *remove from cache* option under the `pyCobaltHound` menu entry.![](./images/credentials_remove_from_cache.png)\n\n##### Removing the entire cache\n\nIn cases where you wish to remove all entities from the cache you can do so in `pyCobaltHound's` main menu (`Cobalt Strike` \u003e `pyCobaltHound` \u003e `Wipe cache`). This is most helpful when you want to reevaluate your entire credential store.\n\n![](./images/aggressor_wipe_cache_prompt.png)\n\n##### Manually triggering an investigation\n\nAfter removing your targets from the cache you can manually prompt `pyCobaltHound`  to re-investigate the contents of the credential store. This follows exactly the same process as above.\n\n### Beacon management\n\n`pyCobaltHound` contains functionality to interact with existing beacon sessions. This can be found in the beacon context menu. Note that these commands can be executed on a single beacon or a selections of beacons.\n\n![](./images/beacon_menu.png)\n\nThis functionality is especially useful when dealing with users and computers whose credentials have not been compromised (yet), but that are effectively under our control (e.g because we have a beacon running under their session token).\n\n#### Mark as owned\n\nThe *Mark as owned* functionality (`pyCobaltHound` \u003e `Mark as owned`) can be used to mark a beacon (or collection of beacons) as owned in the `BloodHound` database.\n\n![](./images/beacon_mark_as_owned.png)\n\nThis dialog will ask the operator for the following information:\n\n- **Nodetype**\n  - **Both:** If this is selected, both the user and computer associated with the beacon context will be marked as owned. `pyCobaltHound` will only mark computers as owned if the beacon session is running as local admin, SYSTEM or a high integrity session as another user.\n  - **User:** If this is selected the user associated to the beacon context will be marked as owned.\n  - **Computer:** If this is selected the computer associated to the beacon context will be marked as owned, regardless of the integrity level of  the associated session.\n- **Domain**\n  - Since a beacon's context does not contain any reference to the domain, operators need to specify this themselves \n\n#### Investigation\n\nThe *Investigate* functionality (`pyCobaltHound` \u003e `Mark as owned`) can be used to investigate the users and hosts associated with a beacon (or collection of beacons).\n\n![](./images/beacon_investigate.png)\n\nThis dialog will ask the operator for the following information:\n\n- **Nodetype**\n  - **Both:** If this is selected, both the user and computer associated with the beacon context will be investigated. `pyCobaltHound` will only investigate computers if the beacon session is running as local admin, SYSTEM or a high integrity session as another user.\n  - **Both without logic:** If this is selected, both the user and computer associated with the beacon context will be investigated. `pyCobaltHound` will investigate all entities without checking for integrity levels.\n  - **User:** If this is selected the user associated to the beacon context will be marked as owned.\n  - **Computer:** If this is selected the computer associated to the beacon context will be marked as owned, regardless of the integrity level of  the associated session.\n- **Domain**\n  - Since a beacons context does not contain any reference to the domain, operators need to specify this themselves\n- **Generate a report**\n  - If this option is selected a basic HTML report will be generated\n\n### Entity investigation\n\n`pyCobaltHound` contains functionality to freely investigate entities. This can be found in the main menu (`Cobalt Strike` \u003e `pyCobaltHound` \u003e `Investigate` ).\n\nThis functionality is especially useful when dealing with users and computers whose credentials have not been compromised and are not under our control. \n\n![](./images/aggressor_investigate.png)\n\nThis dialog will ask the operator for the following information:\n\n- **Targets**\n  - A CSV-style string of entities the operator wishes to investigate. This can be just user/computer names (e.g user1) **or** FQDNs (user1@domain.local).\n  - **Note:** Do not mix \u0026 match notations. You can do either user/computer names or FQDN's!\n- **Domain included**\n  - This parameter specifies if the provided target string contains just user/computer names or FQDNs.\n- **Domain**\n  - If the targetstring does not contain FQDNs the operator will need to indicate the domain the entities to investigate belong to.\n- **Generate a report**\n  - If this option is selected a basic HTML report will be generated\n\n## Settings\n\n`pyCobaltHound's` settings menu can be found under `Cobalt Strike` \u003e `pyCobaltHound` \u003e `Settings`. \n\n![](./images/aggressor_settings.png)\n\n`pyCobaltHound` will save your settings to disk. Every time `pyCobaltHound` is reloaded, it will check for the existence of a settings file and load the saved settings if it finds one. \n\n`pyCobaltHound` saves a settings file per teamserver, so it is possible to have different settings on different teamservers.\n\n#### Neo4j\n\nTo authenticate to the `BloodHound` database, `pyCobaltHound` will need the following information:\n\n- **Neo4j username**\n- **Neo4j password**\n- **Neo4j URL**\n\n**Note:** if you choose to persistently save your settings (to preserve them across client/host reboots) `pyCobaltHound` will deserialize and store these credentials on disk.\n\n#### Caching\n\nAs discussed before, `pyCobaltHound` uses caching to make sure it does not perform unnecessary work. This caching can be disabled in the settings. This is mostly useful when developing new queries so you don't constantly have to manage/wipe the cache.\n\n#### Notifications\n\n `pyCobaltHound` supports a few different methods of notifying the operator once it has identified an entity of interest. It is possible to disable these notifications.\n\n##### Native notifications\n\nBy default, `pyCobaltHound` will notify the operator using the default Aggressor messagebox. This option can the operators workflow. It is however the default method since it it supported on each platform you can run a `Cobalt Strike` client.\n\n![](./images/aggressor_notify_native.png)\n\n##### Notify2 notifications\n\n`pyCobaltHound` also supports displaying desktop notifications on Linux. This is our preferred option since it does not interrupt the operators workflow.\n\n![](./images/aggressor_notify_pynotify.png)\n\n#### Reporting\n\nDuring some of its workflows, `pyCobaltHound` will generate an HTML report. This design choice was made to avoid spamming the operator with giant notifications in case a lot of entities were investigated. These reports will be generated in the *reports* folder. It is possible to disable the report generation.\n\n![](./images/aggressor_html.png)\n\n#### Query synchronization\n\nBy default, `pyCobaltHound` will synchronize queries across teamservers by using a central file for all query related settings. This means that queries that are enabled, added or deleted on one teamserver will also be enabled, added, delete to the queries made by other teamservers. This is mostly a convenience option and can be disabled, which is useful in cases where you are running engagement specific queries that do not apply to all the teamservers you are connected to.\n\n#####  Disabling\n\nWhen query synchronization is disabled, `pyCobaltHound` will check for the existence of unique query files. If these exists, it will load these and use these queries during its workflows. If the files do not exists, it will create and load them . This setting will persist through reloads\n\n##### Enabling\n\nWhen query synchronization is enabled, `pyCobaltHound` will check for the existence of unique query files. If these exists, the operator will be prompted for a choice.\n\n![](./images/aggressor_enable_query_sync.png)\n\nThe operator has the following choices:\n\n- **Delete**\n  - If chosen, `pyCobaltHound` will simply remove the unique query files. All custom queries will be lost.\n- **Merge**\n  - If chosen, `pyCobaltHound` will attempt to merge the unique query files into the general query files. Before merging a query, it will check if there is no query in the general file that has the same name or the same Cypher statement. If any merge conflicts occur, the operator will be asked if they want to keep the non-merged queries. They will be saved in a separate file. The unique query files will then be removed.\n- **Keep**\n  - If chosen, `pyCobaltHound` will just leave the unique query files. All custom queries will be preserved and the files will be loaded again if query synchronization is disabled again.\n\n## Queries\n\n### Built-in queries\n\n`pyCobaltHound` currently supports the following built-in queries:\n\n- **User** **(user-queries.json)**\n  - Path to Domain Admins\n  - Path to High Value Targets\n- **Computer** **(computer-queries.json)**\n  - Path to High Value Targets\n\n### Managing queries\n\nManaging the various queries that `pyCobaltHound` uses can be done through the main menu (`Cobalt Strike` \u003e `pyCobaltHound` \u003e `Queries`).\n\n![](./images/aggressor_menu_with_queries.png)\n\n#### Enabling/Disabling queries\n\nThe *Update queries* dialog allows operators to enable/disable specific queries. When using the this dialog, the operator will first be asked what type of queries they want to update. This is done to dynamically render/load the correct queries during this workflow.\n\n![](./images/aggressor_query_update_choice.png)\n\nAfter answering the first dialog, the operator will then be presented with a list of all available queries of that type. Here they can choose which queries they wish to enable/disable.\n\n![aggressor_query_update](./images/aggressor_query_update.png)\n\nThe query type option is an ugly workaround to pass the query type to the next function in the workflow and is of no concern to the operator.\n\n#### Adding custom queries\n\nThe *Add query* functionality allows operators to add/remove their own queries to fine tune `pyCobaltHound's` investigation capabilities. This grants them the flexibility to adapt `pyCobaltHound` on the fly during engagements to account for engagement-specific targets (users, hosts etc..).\n\n![](./images/aggressor_query_add.png)\n\nThis dialog will ask the operator for the following information:\n\n- **Name**\n  - The name of the custom query. This will be used in various menus \u0026 reports during `pyCobaltHounds` workflows.\n- **Cypher query**\n  - The Cypher query `pyCobaltHound` needs to execute. Operators are quite free to define their queries. The only requirements are the following:\n    - `pyCobaltHound` dynamically generates the following Cypher string based on the entity names it is investigating:\n      - `WITH [account names here] AS samAccountNames UNWIND samAccountNames AS names`.\n      - The **{statement}** placeholder will be replaced with this string.\n      - This Cypher string takes the samAccountNames of the targets and assigns them to the \"names\" variable.\n      - To make your query work with this you must ensure that it starts with the following statement:\n        - `MATCH (x) WHERE x.name STARTS WITH names`\n        - I recommend filtering (e.g `(x:User)`) depending on which query type you are adding.\n    - `pyCobaltHound` expects the query to return a distinct set of usernames.\n      - To do so, end your query with `RETURN DISTINCT (x.name)`\n    - For some examples, refer to the built-in queries.\n- **Report headline**\n  - The headline that `pyCobaltHound` uses for the custom query. This will be used in  notifications \u0026 reports during `pyCobaltHounds` workflows.\n    - The only requirement is the the sentence contains a **{number}** placeholder which `pyCobaltHound` will replace with the amount of results for this query.\n- **Status**\n  - This parameter determines if the query is created in an enabled or disabled state.\n- **Query type**\n  - The type of query you are adding. This will determine which set of queries is edited.\n\n#### Deleting custom queries\n\nThe *Delete query* dialog allows operators to remove specific custom queries from `pyCobaltHound`. When using the this dialog, the operator will first be asked what type of query they want to remove. This is done to dynamically render/load the correct queries during this workflow.\n\n![](./images/aggressor_query_remove_choice.png)\n\nAfter answering the first dialog, the operator will then be presented with a list of all available queries of that type. Here they can choose which queries they wish to remove.\n\n![aggressor_query_remove](./images/aggressor_query_remove.png)\n\nThe query type option is an ugly workaround to pass the query type to the next function in the workflow and is of no concern to the operator.\n\n## References\n\n`pyCobaltHound` uses/takes inspiration from the following:\n\n- [pycobalt](https://github.com/dcsync/pycobalt.git) by dcsync\n- [Vampire](https://github.com/Coalfire-Research/Vampire.git) by Coalfire-Research\n- [ANGRYPUPPY](https://github.com/vysecurity/ANGRYPUPPY.git) by vysecurity\n- [Max](https://github.com/knavesec/Max.git) by knavesec\n- [BloodHound](https://github.com/BloodHoundAD/BloodHound.git) by SpecterOps\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvisosecurity%2Fpycobalthound","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnvisosecurity%2Fpycobalthound","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvisosecurity%2Fpycobalthound/lists"}