daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

commit 7dd3a0f7cbe1b9cb0828ce88360c6f5f5c2f93bf
parent a66d99ebde37c48de68a58284fc18f74da282855
Author: DAEMON <zer0sec.xp@icloud.com>
Date:   Sun, 20 Sep 2026 01:51:40 +0100

Add native Active Directory enumeration cheat sheet page

New active-directory/ad-enumeration-native.md: native Get-AD* and LDAP
enumeration, -Filter/-LDAPFilter fine-tuning, deleted-object / AD Recycle
Bin recovery, ADSI fallback, and a native-vs-PowerView map.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Diffstat:
Asrc/content/sheets/active-directory/ad-enumeration-native.md | 226+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 226 insertions(+), 0 deletions(-)

diff --git a/src/content/sheets/active-directory/ad-enumeration-native.md b/src/content/sheets/active-directory/ad-enumeration-native.md @@ -0,0 +1,226 @@ +--- +title: "Active Directory Enumeration — Native Tooling" +description: "Native Get-AD* and LDAP enumeration: fine-tuning -Filter/-LDAPFilter, finding deleted accounts in the AD Recycle Bin, ADSI when RSAT is missing — without reaching for PowerView." +category: active-directory +subcategory: "Tooling & Recon" +tags: [active-directory, enumeration, powershell, ldap, recycle-bin, deleted-objects] +tools: ["ActiveDirectory module (Get-AD*)", "ldapsearch", "ADSI / adsisearcher", "dsquery", "setspn", "nltest"] +difficulty: intermediate +updated: "2026-09-20" +source: "vault:06PdfCheatSheets/Active Directory/AD-Enumeration-Native" +--- + +# Active Directory Enumeration — Native Tooling + +The Microsoft-signed **`ActiveDirectory`** module (and, when it is missing, raw **ADSI / LDAP**) answers almost every enumeration question on a domain-joined box — who, what, where, which rights, which stale or **deleted** object — with no dropped tooling. PowerView is powerful, but for read-only recon it is an extra artefact you rarely need. This card is about driving `-Filter` and `-LDAPFilter` **precisely**, so you stop pulling the whole directory and grepping, and pull exactly the objects you want. + +> [!tip] When you do NOT need PowerView +> If the task is "find objects / read attributes / list membership / find stale or deleted objects", the native `Get-AD*` cmdlets do it, are already present on any host with RSAT (always on a DC), are signed, and are quieter. Reach for PowerView only for what it genuinely adds: quick object-ACL enumeration (`Get-DomainObjectAcl`), GPO-to-OU mapping, and one-liner delegation/trust hunts — and even those have native equivalents (see the last table). + +## Setup — get the module loaded + +```powershell +Get-Module -ListAvailable ActiveDirectory # present? +Import-Module ActiveDirectory # load it +Get-ADDomain # sanity check: you can reach a DC +(Get-ADDomain).DomainSID # domain SID (handy for RID math) +``` + +No RSAT on the box? Install the capability (admin), or skip to the ADSI section: + +```powershell +# Windows 10/11 client: +Add-WindowsCapability -Online -Name Rsat.ActiveDirectory.DS-LDS.Tools~~~~0.0.1.0 +# Windows Server: +Install-WindowsFeature -Name RSAT-AD-PowerShell +``` + +> [!info] Target a specific DC / creds +> Every `Get-AD*` cmdlet takes `-Server <dc.fqdn>` and `-Credential (Get-Credential)`. From a non-domain host (with `runas /netonly`), that is how you query without being joined. + +## The core cmdlets + +| Cmdlet | Answers | +|---|---| +| `Get-ADUser` | users + attributes (SPNs, UAC flags, lastLogon, description) | +| `Get-ADGroup` / `Get-ADGroupMember` | groups; who is IN a group (`-Recursive` for nested) | +| `Get-ADComputer` | computers; OS, delegation, lastLogon | +| `Get-ADObject` | **any** object by LDAP filter — the universal tool (incl. deleted) | +| `Get-ADDomain` / `Get-ADForest` | functional level, naming contexts, FSMO | +| `Get-ADTrust` | trust relationships (direction, transitivity) | +| `Get-ADServiceAccount` | (g)MSAs and who may retrieve the password | +| `Get-ADOrganizationalUnit` | OU tree (targets for `-SearchBase`) | + +```powershell +Get-ADUser -Identity alfred -Properties * # everything on one user +Get-ADGroupMember "Domain Admins" -Recursive | ft name,objectClass +Get-ADComputer -Filter * -Properties OperatingSystem | ft name,OperatingSystem +Get-ADObject -Filter "name -eq 'alfred'" -Properties * # any object, any class +``` + +## Fine-tuning with `-Filter` (PowerShell syntax) + +`-Filter` takes a PowerShell-ish expression the module translates to LDAP. Quote the whole filter; single-quote literal values; compare booleans to `$true`/`$false`; `*` is the wildcard with `-like`. + +Operators: `-eq -ne -lt -gt -le -ge -like -notlike -and -or -not -bor -band` + +```powershell +Get-ADUser -Filter "Enabled -eq '$true'" # enabled users +Get-ADUser -Filter "Description -like '*pass*'" # creds in descriptions +Get-ADUser -Filter {ServicePrincipalName -like "*"} -Properties ServicePrincipalName # kerberoastable +Get-ADUser -Filter {DoesNotRequirePreAuth -eq $true} # AS-REP roastable +Get-ADUser -Filter "PasswordNeverExpires -eq '$true' -and Enabled -eq '$true'" +Get-ADUser -Filter "adminCount -eq 1" # protected / privileged (AdminSDHolder) +Get-ADComputer -Filter {TrustedForDelegation -eq $true} # unconstrained delegation +Get-ADUser -Filter "LastLogonDate -lt '$((Get-Date).AddDays(-90))'" # stale accounts +``` + +> [!warning] Filter gotchas +> - Default properties are few — if you **filter or display** an attribute that isn't returned by default (SPN, `lastLogon`, `userAccountControl`), add it with `-Properties`. +> - Braces `{ }` let you use `$true` bare; the string form needs `'$true'`. Both work — be consistent. +> - `-Filter *` means "everything" — fine for computers, heavy for a big user base. Prefer a real predicate. + +## Fine-tuning with `-LDAPFilter` (raw LDAP) + +When the PowerShell filter fights you — bitwise UAC flags, negation, exact attribute names — drop to raw LDAP. Operators sit at the front: `(&(a)(b))` = AND, `(|(a)(b))` = OR, `(!(a))` = NOT, `*` = wildcard/presence. + +```powershell +Get-ADObject -LDAPFilter "(servicePrincipalName=*)" -Properties servicePrincipalName # SPNs +Get-ADObject -LDAPFilter "(&(objectClass=user)(objectCategory=person))" +Get-ADObject -LDAPFilter "(&(objectClass=group)(!(member=*)))" # empty groups +Get-ADUser -LDAPFilter "(memberOf=CN=Domain Admins,CN=Users,DC=htb,DC=local)" +``` + +`userAccountControl` bits use the bitwise matching rule OID `1.2.840.113556.1.4.803`: + +```powershell +# disabled accounts (bit 0x2) +Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=2)" +# password never expires (0x10000 = 65536) +Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=65536)" +# don't require pre-auth (0x400000 = 4194304) -> AS-REP roast +Get-ADUser -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=4194304)" +# trusted for delegation (0x80000 = 524288) -> unconstrained +Get-ADObject -LDAPFilter "(userAccountControl:1.2.840.113556.1.4.803:=524288)" +``` + +| UAC bit | Value | Meaning | +|---|---|---| +| 0x0002 | 2 | Account disabled | +| 0x0020 | 32 | Password not required | +| 0x0200 | 512 | Normal account | +| 0x10000 | 65536 | Password never expires | +| 0x80000 | 524288 | Trusted for delegation (unconstrained) | +| 0x100000 | 1048576 | Not delegated (sensitive) | +| 0x400000 | 4194304 | Does not require Kerberos pre-auth | + +## Scope and attributes — pull only what you need + +```powershell +# only the columns you want, not the whole object +Get-ADUser -Filter * -Properties SamAccountName,Description,LastLogonDate | + Select SamAccountName,Description,LastLogonDate + +# restrict the search to one OU (and its children) +Get-ADUser -SearchBase "OU=Servers,DC=htb,DC=local" -Filter * + +# scope: Base (this object) / OneLevel (direct children) / Subtree (default) +Get-ADObject -SearchBase "DC=htb,DC=local" -SearchScope OneLevel -LDAPFilter "(objectClass=organizationalUnit)" +``` + +> [!info] Read it back with the right tool +> `Select`, `Format-Table (ft)`, `Format-List (fl)` and `Sort-Object` shape output; `Export-Csv` banks it for the report. Pull `-Properties *` once on an interesting object to learn its real attribute names, then filter precisely. + +## Deleted / tombstoned objects & the AD Recycle Bin + +This is the case people reach for PowerView on and shouldn't — **deleted objects are native `Get-ADObject` territory**. When something is removed, its tombstone lingers, and if the AD Recycle Bin is enabled it can be **restored with attributes intact**. + +List every deleted object with its old parent and SID: + +```powershell +Get-ADObject -Filter 'isDeleted -eq $true -and name -ne "Deleted Objects"' ` + -IncludeDeletedObjects -Properties objectSid,lastKnownParent,whenChanged,msDS-LastKnownRDN | + ft name,objectSid,lastKnownParent +``` + +Inspect one deleted object fully, then restore it (Recycle Bin must be enabled): + +```powershell +Get-ADObject -LDAPFilter "(msDS-LastKnownRDN=alfred)" -IncludeDeletedObjects -Properties * +Restore-ADObject -Identity "<distinguishedName-with-\0ADEL:GUID>" + +# is the Recycle Bin feature on? +Get-ADOptionalFeature -Filter "name -like 'Recycle Bin Feature'" | ft name,EnabledScopes +``` + +> [!note] Why this matters on a box +> A deleted object can hold a still-valid SID/attributes, a group it belonged to, or a service account that was "removed" but restorable — reading its attributes (or restoring it) can hand you an identity or a path the live tree hides. That is exactly the fine-tuned, native query PowerView is not needed for. + +## Service accounts, gMSA & delegation + +```powershell +Get-ADServiceAccount -Filter * -Properties PrincipalsAllowedToRetrieveManagedPassword +# who can read a gMSA password -> if it's you/your group, you can pull it +Get-ADServiceAccount -Identity gmsaSvc -Properties * | + Select Name,PrincipalsAllowedToRetrieveManagedPassword + +# constrained delegation targets +Get-ADObject -LDAPFilter "(msDS-AllowedToDelegateTo=*)" -Properties msDS-AllowedToDelegateTo +# resource-based constrained delegation (who can act on this computer) +Get-ADComputer -Filter * -Properties PrincipalsAllowedToDelegateToAccount | + Where-Object {$_.PrincipalsAllowedToDelegateToAccount} +``` + +## No RSAT? ADSI / LDAP without the module + +`[adsisearcher]` and `System.DirectoryServices` ship on stock Windows — no module, no dropped binary. + +```powershell +([adsisearcher]"(servicePrincipalName=*)").FindAll() # SPNs +$s = [adsisearcher]"(&(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=4194304))" +$s.PropertiesToLoad.AddRange(@("samaccountname")); $s.FindAll().Properties.samaccountname +``` + +Built-in binaries when PowerShell is awkward: + +```bash +dsquery user -limit 0 # all users (if dsquery present) +net user /domain ; net group "Domain Admins" /domain # quick membership +nltest /dclist:htb.local ; nltest /domain_trusts # DCs and trusts +setspn -T htb.local -Q */* # SPNs (kerberoast targets) +``` + +## From Linux — same filters, different client + +`ldapsearch` speaks the exact same LDAP filters as `-LDAPFilter`: + +```bash +ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \ + '(servicePrincipalName=*)' sAMAccountName servicePrincipalName +# AS-REP roastable +ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \ + '(userAccountControl:1.2.840.113556.1.4.803:=4194304)' sAMAccountName +# deleted objects need the Show Deleted Objects control: +ldapsearch -x -H ldap://$DC -D 'HTB\alfred' -w 'Pass' -b 'DC=htb,DC=local' \ + -E '!1.2.840.113556.1.4.417' '(isDeleted=TRUE)' msDS-LastKnownRDN lastKnownParent +``` + +> [!info] Collectors +> `nxc ldap $DC -u u -p p --query "<ldapfilter>" "<attrs>"` runs the same filters at scale; BloodHound / RustHound-CE ingest the whole graph when you want relationships rather than a targeted lookup. + +## Native vs PowerView — quick map + +| Task | Native | PowerView | +|---|---|---| +| Find users/computers | `Get-ADUser` / `Get-ADComputer` `-Filter`/`-LDAPFilter` | `Get-DomainUser` / `Get-DomainComputer` | +| Group membership | `Get-ADGroupMember -Recursive` | `Get-DomainGroupMember -Recurse` | +| SPNs (kerberoast) | `(servicePrincipalName=*)` | `Get-DomainUser -SPN` | +| AS-REP roastable | UAC bit `4194304` filter | `Get-DomainUser -PreauthNotRequired` | +| Deleted objects | `Get-ADObject -IncludeDeletedObjects` | *(n/a — use native)* | +| Trusts | `Get-ADTrust -Filter *` | `Get-DomainTrust` | +| Delegation | `msDS-AllowedToDelegateTo` / `TrustedForDelegation` | `Get-DomainComputer -Unconstrained` | +| Object ACLs | `Get-Acl "AD:\<DN>"` | `Get-DomainObjectAcl` *(easier)* | +| GPO to OU mapping | `Get-GPO` / `Get-GPInheritance` (GroupPolicy module) | `Get-DomainGPO` / `Get-DomainOU` | + +> [!tip] The habit to build +> Ask "what object and which attribute do I actually want?", write the `-LDAPFilter` for it, add `-Properties` for the attributes, and `-SearchBase` to scope it. That single targeted query — native, signed, already present — is almost always the answer, **deleted objects included**.