Skip to content

Commit

Permalink
Dependency Updates (#5)
Browse files Browse the repository at this point in the history
* update typer

* update bloohound-python

* manually merge in parse_binary_acl changes

* update for diff in object counts

* make memberof a common property

* update readme and changelog

* update container to python3.9

* update readme

* Update README.md

* bump version

---------

Co-authored-by: Matthew Creel
  • Loading branch information
Tw1sm authored Feb 10, 2023
1 parent c827910 commit ad6a3e5
Show file tree
Hide file tree
Showing 11 changed files with 454 additions and 444 deletions.
Binary file added .assets/usage.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
container: python:3.6
container: python:3.9
steps:
- uses: actions/checkout@v3

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Changelog
## [v0.1.2] - 2/10/2023
### Changed
- Updated ACL parsing function to current version BloodHound.py
- Updated `typer` and `bloodhound-python` dependencies
- Added the `memberof` attrbute to the common properties displayed for users, computers and groups

## [v0.1.1] - 8/11/2022
### Fixed
- Bug where domain trusts queried more than once would appear duplicated in the BH UI
Expand Down
39 changes: 15 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,38 +20,24 @@ By parsing log files generated by the aforementioned tools, BOFHound allows oper
[Blog - Granularize Your AD Recon Game Part 2](https://www.fortalicesolutions.com/posts/granularize-your-active-directory-reconnaissance-game-part-2)

# Installation
BOFHound can be installed with `pip3 install bofhound` or by cloning this repository and running `pip3 install .`.
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 ldapsearch BOF and
pyldapsearch
Options:
-i, --input TEXT Directory or file containing logs of ldapsearch
results [default: /opt/cobaltstrike/logs]
-o, --output TEXT Location to export bloodhound files [default: .]
-a, --all-properties Write all properties to BloodHound files (instead of
only common properties)
--debug Enable debug output
-z, --zip Compress the JSON output files into a zip archive
--help Show this message and exit.
```
![](.assets/usage.png)


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

### Parse pyldapsearch logs and only include common BloodHound properties
Parse pyldapsearch logs and only include all properties (vs only common properties)
```
bofhound -i ~/.pyldapsearch/logs/ --all-properties
```

# ldapsearch Query Examples
# ldapsearch

## Required Data
The following attributes are required for proper functionality:
Expand All @@ -62,17 +48,18 @@ dn
objectsid
```

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

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

## Retrieve Only the ms-Mcs-AdmPwd schemaIDGUID
Retrieve Only the ms-Mcs-AdmPwd schemaIDGUID
```
ldapsearch (name=ms-mcs-admpwd) name,schemaidguid 1 "" CN=Schema,CN=Configuration,DC=windomain,DC=local
```
Expand All @@ -86,3 +73,7 @@ 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)
19 changes: 14 additions & 5 deletions bofhound/ad/adds.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,12 +565,15 @@ def parse_acl(self, entry:BloodHoundObject):
writeprivs = ace_object.acedata.mask.has_priv(ACCESS_MASK.ADS_RIGHT_DS_WRITE_PROP)
if writeprivs:
# GenericWrite
if entry._entry_type.lower() in ['user', 'group', 'computer'] and not ace_object.acedata.has_flag(ACCESS_ALLOWED_OBJECT_ACE.ACE_OBJECT_TYPE_PRESENT):
if entry._entry_type.lower() in ['user', 'group', 'computer', 'gpo'] and not ace_object.acedata.has_flag(ACCESS_ALLOWED_OBJECT_ACE.ACE_OBJECT_TYPE_PRESENT):
relations.append(self.build_relation(entry, sid, 'GenericWrite', inherited=is_inherited))
if entry._entry_type.lower() == 'group' and can_write_property(ace_object, EXTRIGHTS_GUID_MAPPING['WriteMember']):
relations.append(self.build_relation(entry, sid, 'AddMember', '', inherited=is_inherited))
if entry._entry_type.lower() == 'computer' and can_write_property(ace_object, EXTRIGHTS_GUID_MAPPING['AllowedToAct']):
relations.append(self.build_relation(entry, sid, 'AddAllowedToAct', '', inherited=is_inherited))
# Property set, but ignore Domain Admins since they already have enough privileges anyway
if entry._entry_type.lower() == 'computer' and can_write_property(ace_object, EXTRIGHTS_GUID_MAPPING['UserAccountRestrictionsSet']) and not sid.endswith('-512'):
relations.append(self.build_relation(entry, sid, 'WriteAccountRestrictions', '', inherited=is_inherited))

# Since 4.0
# Key credential link property write rights
Expand Down Expand Up @@ -604,28 +607,34 @@ def parse_acl(self, entry:BloodHoundObject):
# All Extended
if entry._entry_type.lower() in ['user', 'domain'] and not ace_object.acedata.has_flag(ACCESS_ALLOWED_OBJECT_ACE.ACE_OBJECT_TYPE_PRESENT):
relations.append(self.build_relation(entry, sid, 'AllExtendedRights', '', inherited=is_inherited))
if entry._entry_type.lower() == 'computer' and not ace_object.acedata.has_flag(ACCESS_ALLOWED_OBJECT_ACE.ACE_OBJECT_TYPE_PRESENT) and \
'haslaps' in entry.Properties.keys():
if entry._entry_type.lower() == 'computer' and not ace_object.acedata.has_flag(ACCESS_ALLOWED_OBJECT_ACE.ACE_OBJECT_TYPE_PRESENT):
relations.append(self.build_relation(entry, sid, 'AllExtendedRights', '', inherited=is_inherited))
if entry._entry_type.lower() == 'domain' and has_extended_right(ace_object, EXTRIGHTS_GUID_MAPPING['GetChanges']):
relations.append(self.build_relation(entry, sid, 'GetChanges', '', inherited=is_inherited))
if entry._entry_type.lower() == 'domain' and has_extended_right(ace_object, EXTRIGHTS_GUID_MAPPING['GetChangesAll']):
relations.append(self.build_relation(entry, sid, 'GetChangesAll', '', inherited=is_inherited))
if entry._entry_type.lower() == 'domain' and has_extended_right(ace_object, EXTRIGHTS_GUID_MAPPING['GetChangesInFilteredSet']):
relations.append(self.build_relation(entry, sid, 'GetChangesInFilteredSet', '', inherited=is_inherited))
if entry._entry_type.lower() == 'user' and has_extended_right(ace_object, EXTRIGHTS_GUID_MAPPING['UserForceChangePassword']):
relations.append(self.build_relation(entry, sid, 'ForceChangePassword', '', inherited=is_inherited))

if ace_object.ace.AceType == 0x00:
is_inherited = ace_object.has_flag(ACE.INHERITED_ACE)
mask = ace_object.acedata.mask
# ACCESS_ALLOWED_ACE
if not ace_object.has_flag(ACE.INHERITED_ACE) and ace_object.has_flag(ACE.INHERIT_ONLY_ACE):
# ACE is set on this object, but only inherited, so not applicable to us
continue

if mask.has_priv(ACCESS_MASK.GENERIC_ALL):
# Generic all includes all other rights, so skip from here
relations.append(self.build_relation(entry, sid, 'GenericAll', inherited=is_inherited))
continue

if mask.has_priv(ACCESS_MASK.ADS_RIGHT_DS_WRITE_PROP):
# Genericwrite is only for properties, don't skip after
relations.append(self.build_relation(entry, sid, 'GenericWrite', inherited=is_inherited))
if entry._entry_type.lower() in ['user', 'group', 'computer', 'gpo']:
relations.append(self.build_relation(entry, sid, 'GenericWrite', inherited=is_inherited))

if mask.has_priv(ACCESS_MASK.WRITE_OWNER):
relations.append(self.build_relation(entry, sid, 'WriteOwner', inherited=is_inherited))
Expand All @@ -635,7 +644,7 @@ def parse_acl(self, entry:BloodHoundObject):
relations.append(self.build_relation(entry, sid, 'AllExtendedRights', '', inherited=is_inherited))

if entry._entry_type.lower() == 'computer' and mask.has_priv(ACCESS_MASK.ADS_RIGHT_DS_CONTROL_ACCESS) and \
'haslaps' in entry.Properties.keys():
sid != "S-1-5-32-544" and not sid.endswith('-512'):
relations.append(self.build_relation(entry, sid, 'AllExtendedRights', '', inherited=is_inherited))

if mask.has_priv(ACCESS_MASK.WRITE_DACL):
Expand Down
3 changes: 2 additions & 1 deletion bofhound/ad/models/bloodhound_computer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ class BloodHoundComputer(BloodHoundObject):
'pwdlastset', 'operatingsystem', 'description', 'operatingsystemservicepack',
'msds-allowedtoactonbehalfofotheridentity', 'ms-mcs-admpwdexpirationtime',
'domainsid', 'name', 'unconstraineddelegation', 'enabled',
'trustedtoauth', 'domain', 'highvalue', 'haslaps', 'serviceprincipalnames'
'trustedtoauth', 'domain', 'highvalue', 'haslaps', 'serviceprincipalnames',
'memberof'
]

def __init__(self, object):
Expand Down
2 changes: 1 addition & 1 deletion bofhound/ad/models/bloodhound_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class BloodHoundGroup(BloodHoundObject):
'distinguishedname', 'samaccountname', 'samaccounttype', 'objectsid',
'member', 'admincount', 'description', 'whencreated',
'name', 'domain', 'domainsid', 'distinguishedname', 'admincount',
'description', 'whencreated'
'description', 'whencreated', 'memberof'
]

def __init__(self, object):
Expand Down
2 changes: 1 addition & 1 deletion bofhound/ad/models/bloodhound_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class BloodHoundUser(BloodHoundObject):
'highvalue', 'unconstraineddelegation', 'passwordnotreqd', 'enabled',
'dontreqpreauth', 'sensitive', 'trustedtoauth', 'pwdneverexpires',
'dontreqpreauth', 'pwdneverexpires', 'sensitive',
'serviceprincipalnames', 'hasspn', 'email'
'serviceprincipalnames', 'hasspn', 'email', 'memberof'
]

def __init__(self, object=None):
Expand Down
Loading

0 comments on commit ad6a3e5

Please sign in to comment.