NH-RED-TEAM / RustHound

Active Directory data collector for BloodHound written in Rust. 🦀

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[FeatureRequest] Option to dumps all ldap attributes from root ldap

1mm0rt41PC opened this issue · comments

From a pentest I have found that a owned user was able to read an LAPS entry (new one msLAPS-Password) but not LAPS Legacy.
But Rusthound like Bloodhound doesn't dump all attributes and associated ACE, so this path was not visible, I was blind...

The targeted user also had unusual ACLs in non-standard LDAP paths linked to SCCM in CN=Services,CN=Configuration.

Feature:

  • Add an option to dump all attributes wite ACE --dump-ldap-fields=all
  • Add a feature to dump only custom fields --dump-ldap-fields=default,msLAPS-Password,msLAPS-EncryptedPassword,msLAPS-EncryptedDSRMPassword
  • Add a feature to recursively dump all objects in an LDAP path --dump-ldap-path-recurssiv=CN=Services,CN=Configuration

Hi @1mm0rt41PC,

I'm going to add the LAPS attributes relating to the encrypted version. This will warn the auditor whether or not if the user used can read the LAPS passwords stored for a computer object.
https://learn.microsoft.com/fr-fr/windows-server/identity/laps/laps-technical-reference

As far as the non-standard "Configuration" part is concerned, version 2 of RustHound will automatically retrieve the namingContext in order to retrieve the objects associed (Container,Group,User,etc).

For example, if the domain has the following naming context CN=Configuration,DC=DOMAIN,DC=LOCAL then RustHound will automatically fetch the stored objects (useful for ADCS and SCCM for example) and the associated ACE.

For information, version 2 of RustHound is almost complete. It will feature a complete restructuring of the Rust code and compatibility with BloodHound-CE.

Version 2 of RustHound will also automatically generate the following ADCS-related files:

  • aiacas.json
  • rootcas.json
  • enterprisecas.json
  • certtemplates.json
  • ntauthstores.json

Thanks for your suggestion, I'll take it into account and incorporate it into version 2. 😃

Hi there!

Great news! I can't wait to see version 2.0, is there a channel/tag/branch alpha 2.0?
To avoid multiple modifications of the code what do you think about managing the dump of attributes via a yaml conf file with why not an embedded version in the code.

With the format:

dump:
    objectClass:
        ? attribute_A // Dump attribute_A and ACE write only 
        secretAttribute: read // Dump only ACE ref to read

We can imagine:

version: 2


defaults: &commonAttrib
    ? name
    ? canonicalName
    ? objectSid
    ? objectGUID
    ? objectCategory
    ? displayName

dump:
    user:
        <<: *commonAttrib
        ? accountExpires
        ? adminCount
        ? badPasswordTime
        ? badPwdCount
        ? cn
        ? description
        ? distinguishedName
        ? isCriticalSystemObject
        ? lastLogoff
        ? lastLogon
        ? lastLogonTimestamp
        ? logonCount
        ? logonHours
        ? memberOf
        ? msDS-parentdistname
        ? msDS-PrincipalName
        ? primaryGroupID
        ? pwdLastSet
        ? sAMAccountName
        userAccountControl: {"parser": func_pimpMyParser}
        ? userPassword
        ? whenChanged
        ? whenCreated
        ? serviceprincipalname
        
    computers:
        <<: *commonAttrib
        msLAPS-Password: {"parser": "func_pimpMyPassword", "ACE":"read"}
        msLAPS-EncryptedPassword: read
        msLAPS-EncryptedDSRMPassword: read
        ? serviceprincipalname
        
    group:
        <<: *commonAttrib
        ? groupType

    dns:
        <<: *commonAttrib
    
    pKICertificateTemplate:
        <<: *commonAttrib
        ? msPKI-Cert-Template-OID
        ? msPKI-Enrollment-Flag
        ? msPKI-Minimal-Key-Size
        ? msPKI-Private-Key-Flag
        ? msPKI-RA-Application-Policies
        ? msPKI-RA-Signature
        ? msPKI-Template-Minor-Revision
        ? msPKI-Template-Schema-Version
        ? pKICriticalExtensions
        ? pKIDefaultCSPs
        ? pKIDefaultKeySpec
        ? pKIExpirationPeriod
        ? pKIKeyUsage
        ? pKIMaxIssuingDepth
        ? pKIOverlapPeriod
        
    certificationAuthority:
        <<: *commonAttrib
    
    
    dnsNode:
        <<: *commonAttrib
    
    domainDns:
        <<: *commonAttrib
        ? gPLink
        ? fSMORoleOwner
        ? maxPwdAge
        ? minPwdAge
        ? minPwdLength
        ? ms-DS-MachineAccountQuota
        ? pwdHistoryLength
        ? pwdProperties
        
    groupPolicyContainer:
        <<: *commonAttrib
        ? gPCFileSysPath
        ? gPCFunctionalityVersion
        ? gPCMachineExtensionNames
        
    organizationalUnit:
        <<: *commonAttrib
        ? gPLink

It's a good idea, but it would make version 2, which is almost finished, unusable.

I've changed everything to use structures dedicated to each object in the directory in order to optimise the execution of RustHound.

image

Each object is now structured as follows:

/// User structure
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct User {
   #[serde(rename = "ObjectIdentifier")]
   object_identifier: String,
   #[serde(rename = "IsDeleted")]
   is_deleted: bool,
   #[serde(rename = "IsACLProtected")]
   is_acl_protected: bool,
   #[serde(rename = "Properties")]
   properties: UserProperties,
   #[serde(rename = "PrimaryGroupSID")]
   primary_group_sid: String,
   #[serde(rename = "SPNTargets")]
   spn_targets: Vec<SPNTarget>,
   #[serde(rename = "Aces")]
   aces: Vec<AceTemplate>,
   #[serde(rename = "AllowedToDelegate")]
   allowed_to_delegate: Vec<Member>,
   #[serde(rename = "HasSIDHistory")]
   has_sid_history: Vec<String>,
   #[serde(rename = "ContainedBy")]
   contained_by: Option<Member>,
}

impl User {
   /// New User
   pub fn new() -> Self { 
      Self { ..Default::default() } 
   }
   
   /// Function to parse and replace value for user object.
   pub fn parse(
      &mut self,
      result: SearchEntry,
      domain: &String,
   ) {
      // parse all ldap attribut and change value in User struct
   }
  }

RustHound version 2.0 is out and the output is now compatible with BloodHound-CE

Changes can be find in v2 branch. 🚀

b445723

LAPS arguments: https://github.com/NH-RED-TEAM/RustHound/blob/v2/src/objects/computer.rs#L266

OMG ! Nice job ! Super-fast development speed 🤯

I'm closing the issue.
In version 2, all the attributes are retrieved and can be analysed in debug mode rusthound ....... -vv to trace all the LDAP attributes of the retrieved object.