```
              _____________________________ __    __    ______    __    __   __   __   _______
             |   _   /  /  __   / |   ____/|  |  |  |  /  __  \  |  |  |  | |  \ |  | |       \
             |  |_)  | |  |  |  | |  |__   |  |__|  | |  |  |  | |  |  |  | |   \|  | |  .--.  |
             |   _  <  |  |  |  | |   __|  |   __   | |  |  |  | |  |  |  | |  . `  | |  |  |  |
             |  |_)  | |  `--'  | |  |     |  |  |  | |  `--'  | |  `--'  | |  |\   | |  '--'  |
             |______/   \______/  |__|     |__|  |___\_\________\_\________\|__| \___\|_________\
           
                                         << @coffeegist | @Tw1sm >>
```

<h1 align="center">

![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54)
![PyPi](https://img.shields.io/pypi/v/bofhound?style=for-the-badge)
</h1>

BOFHound is an offline BloodHound ingestor and LDAP result parser compatible with TrustedSec's [ldapsearch BOF](https://github.com/trustedsec/CS-Situational-Awareness-BOF), the Python adaptation, [pyldapsearch](https://github.com/fortalice/pyldapsearch) and Brute Ratel's [LDAP Sentinel](https://bruteratel.com/tabs/commander/badgers/#ldapsentinel). ldapsearch BOF output can also be parsed from [Havoc](https://github.com/HavocFramework/Havoc) logs, OutflankC2 logs, and [Mythic](https://github.com/its-a-feature/Mythic) callbacks.

By parsing log files generated by the aforementioned tools, BOFHound allows operators to utilize BloodHound's beloved interface while maintaining full control over the LDAP queries being run and the spped at which they are executed. This leaves room for operator discretion to account for potential honeypot accounts, expensive LDAP query thresholds and other detection mechanisms designed with the traditional, automated BloodHound collectors in mind.

Check this [PR](https://github.com/trustedsec/CS-Situational-Awareness-BOF/pull/114) to the SA BOF repo for BOFs that collect session and local group membership data and can be parsed by BOFHound.

### References

Blog Posts:

| Title| Date|
|------|-----|
| [*BOFHound: AD CS Integration*](https://medium.com/specter-ops-posts/bofhound-ad-cs-integration-91b706bc7958) | Oct 30, 2024 |
| [*BOFHound: Session Integration*](https://posts.specterops.io/bofhound-session-integration-7b88b6f18423) | Jan 30, 2024 |
| [*Granularize Your AD Recon Game Part 2*](https://www.fortalicesolutions.com/posts/granularize-your-active-directory-reconnaissance-game-part-2) | Jun 15, 2022 |
| [*Granularize Your AD Recon Game*](https://www.fortalicesolutions.com/posts/bofhound-granularize-your-active-directory-reconnaissance-game) | May 10, 2022  |

Presentations:

| Conference| Materials| Date|
|-----------|----------|-----|
| *SO-CON 2024*| [Slides](https://github.com/SpecterOps/presentations/blob/main/SO-CON%202024/Matt%20Creel%20%26%20Adam%20Brown%20-%20Manually%20Enumerating%20AD%20Attack%20Paths%20with%20BOFHound/Matt%20Creel%20and%20Adam%20Brown%20-%20Manually%20Enumerating%20AD%20Attack%20Paths%20With%20BOFHound%20-%20SO-CON%202024.pdf) & [Recording](https://www.youtube.com/watch?v=Xxm4YktSKVY)| Mar 11, 2024|

# Installation
BOFHound can be installed with `pip3 install bofhound` or by cloning this repository and running `pip3 install .`

# Usage
```
 Usage: bofhound [OPTIONS]

 Generate BloodHound compatible JSON from logs written by the ldapsearch BOF, pyldapsearch and
 specific C2 frameworks

╭─ Options ─────────────────────────────────────────────────────────────────────────────────────╮
│ --input             -i      TEXT                             Directory or file containing     │
│                                                              logs of ldapsearch results       │
│                                                              [default:                        │
│                                                              /opt/cobaltstrike/logs]          │
│ --output            -o      TEXT                             Location to export bloodhound    │
│                                                              files                            │
│                                                              [default: .]                     │
│ --properties-level  -p      [Standard|Member|All]            Change the verbosity of          │
│                                                              properties exported to JSON:     │
│                                                              Standard - Common BH properties  │
│                                                              | Member - Includes MemberOf and │
│                                                              Member | All - Includes all      │
│                                                              properties                       │
│                                                              [default: Member]                │
│ --parser                    [ldapsearch|BRC4|Havoc|Outflank  Parser to use for log files.     │
│                             C2|Mythic]                       ldapsearch parser (default)      │
│                                                              supports ldapsearch BOF logs     │
│                                                              from Cobalt Strike and           │
│                                                              pyldapsearch logs                │
│                                                              [default: ldapsearch]            │
│ --debug                                                      Enable debug output              │
│ --zip               -z                                       Compress the JSON output files   │
│                                                              into a zip archive               │
│ --quiet             -q                                       Suppress banner                  │
│ --help              -h                                       Show this message and exit.      │
╰───────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ Mythic Options ──────────────────────────────────────────────────────────────────────────────╮
│ --mythic-server        TEXT  IP or hostname of Mythic server to connect to                    │
│                              [default: 127.0.0.1]                                             │
│  --mythic-token         TEXT  Mythic API token [default: None]                                │
╰───────────────────────────────────────────────────────────────────────────────────────────────╯
╭─ BloodHound CE Options ───────────────────────────────────────────────────────────────────────╮
│ --bh-token-id         TEXT  BloodHound API token ID [default: None]                           │
│ --bh-token-key        TEXT  BloodHound API token key [default: None]                          │
│ --bh-server           TEXT  BloodHound CE URL [default: http://127.0.0.1:8080]                │
╰───────────────────────────────────────────────────────────────────────────────────────────────╯
```

## Example Usage
Parse ldapseach BOF results from Cobalt Strike logs (`/opt/cobaltstrike/logs` by default) to /data/
```
bofhound -o /data/
```

Parse pyldapsearch logs and only include all properties (vs other property levels)
```
bofhound -i ~/.pyldapsearch/logs/ --properties-level all
```

Parse LDAP Sentinel data from BRc4 logs (will change default input path to `/opt/bruteratel/logs`)
```
bofhound --parser brc4
```

Parse Havoc loot logs (will change default input path to `/opt/havoc/data/loot`) and zip the resulting JSON files
```
bofhound --parser havoc --zip
```

# ldapsearch
Specify `*,ntsecuritydescriptor` as the attributes to return to be able to parse ACL edges. You are missing a ton of data if you don't include this in your `ldapsearch` queries!

#### Required Data
The following attributes are required for proper functionality:
```
samaccounttype
distinguishedname
objectsid
```

Some object classes rely on domain objects being populated within BOFHound. Domains can be queried with either of the following commands
```
ldapsearch (objectclass=domain) --attributes *,ntsecuritydescriptor
ldapsearch (distinguishedname=DC=windomain,DC=local) --attributes *,ntsecuritydescriptor
``` 

## Example ldapsearch Queries
```
# Get All the Data (Maybe Run BloodHound Instead?)
ldapsearch (objectclass=*) --attributes *,ntsecuritydescriptor

# Retrieve All Schema Info
ldapsearch (schemaIDGUID=*) --attributes name,schemaidguid --dn CN=Schema,CN=Configuration,DC=windomain,DC=local

# Retrieve Only the ms-Mcs-AdmPwd schemaIDGUID
ldapsearch (name=ms-mcs-admpwd) --attributes name,schemaidguid --count 1 --dn CN=Schema,CN=Configuration,DC=windomain,DC=local

# Retrieve Domain NetBIOS Names (useful if collecting data via `netsession2/netloggedon2` BOFs)
ldapsearch (netbiosname=*) --dn "CN=Partitions,CN=Configuration,DC=windomain,DC=local"

# Unroll a group's nested members
ldapsearch (memberOf:1.2.840.113556.1.4.1941:=CN=TargetGroup,CN=Users,DC=windomain,DC=local) --attributes *,ntsecuritydescriptor

# Query domain trusts
ldapsearch (objectclass=trusteddomain) --attributes *,ntsecuritydescriptor

# Query across a trust
ldapsearch (objectclass=domain) --attributes *,ntsecuritydescriptor --hostname dc1.trusted.windomain.local --dn "DC=TRUSTED,DC=WINDOMAIN,DC=LOCAL"

#####
# Queries below populate objects for AD CS parsing

# Query the domain object
ldapsearch (objectclass=domain) --attributes *,ntsecuritydescriptor

# Query Enterprise CAs
ldapsearch (objectclass=pKIEnrollmentService) --attributes *,ntsecuritydescriptor --dn "CN=Configuration,DC=domain,DC=local"

# Query AIACAs, Root CAs and NTAuth Stores
ldapsearch (objectclass=certificationAuthority) --attributes *,ntsecuritydescriptor --dn "CN=Configuration,DC=domain,DC=local"

# Query Certificate Templates
ldapsearch (objectclass=pKICertificateTemplate) --attributes *,ntsecuritydescriptor --dn "CN=Configuration,DC=domain,DC=local"

# Query Issuance Policies
ldapsearch (objectclass=msPKI-Enterprise-Oid) --attributes *,ntsecuritydescriptor --dn "CN=Configuration,DC=domain,DC=local"
```

# Versions
Check the tagged releases to download a specific version
- v0.4.0 and onward support parsing AD CS objects and edges
- v0.3.0 and onward support session/local group data 
- v0.2.1 and onward are compatible with BloodHound CE
- v0.2.0 is the last release supporting BloodHound Legacy

# Development
bofhound uses Poetry to manage dependencies. Install from source and setup for development with:

```shell
git clone https://github.com/fortalice/bofhound
cd bofhound
poetry install
poetry run bofhound --help
```

# References and Credits
- [@_dirkjan](https://twitter.com/_dirkjan) (and other contributors) for [BloodHound.py](https://github.com/fox-it/BloodHound.py)
- TrustedSec for [CS-Situational-Awareness-BOF](https://github.com/trustedsec/CS-Situational-Awareness-BOF)
- [P-aLu](https://github.com/P-aLu) for collaboration on bofhoud's [AD CS support](https://github.com/coffeegist/bofhound/pull/8)
