DEV Community

Pastukhov Aleksey
Pastukhov Aleksey

Posted on

Kestrel v1.2.0 - AD Archaeology

Active Directory is a decade of sediment. Services get uninstalled, admins leave, domains get migrated - but the rights they were granted are almost never cleaned up. v1.2.0 adds a flagship module that digs into that layer.

When you delete a principal, Windows removes the object. It does not walk the domain removing that principal's SID from every ACL it sat in. The permission outlives its owner.

New: --archaeology — dead owners, live rights

A passive, read-only module that reads what a decade of change left behind. Two passes:

Orphaned dangerous ACEs. Walks the DACLs of the highest-value objects (the domain head and AdminSDHolder) and flags any ACE granting a dangerous right - WriteDACL, GenericAll, WriteOwner, WriteProperty, control-access, CreateChild - to a SID that no longer resolves. A trustee SID that resolves to no name is, by definition, a right held by a deleted principal. No host to query, no service to touch - the directory already contains the proof. And a fresh account that lands on a reused RID inherits that right.

Stale privileged accounts. Enabled members of privileged groups whose password hasn't changed in a long time (default threshold: 180 days, deliberately conservative to avoid flagging seasonal-cadence workloads). These are the forgotten service accounts that botnets harvest for quiet lateral movement and domain persistence.

Why this is a clean passive check

The orphaned SID is self-proving from the directory alone - you don't need to query a host to know the owner is dead, you just notice its SID no longer resolves. To avoid false positives, a non-resolving SID is only treated as orphaned when it belongs to this domain (its string form starts with the domain SID prefix). A non-resolving SID from another domain in the forest is not proof of deletion - its DC may simply be unreachable, so it is not flagged.

Why the graph misses it

A reachability graph answers "who can reach Domain Admin." An orphaned ACE and a forgotten privileged account aren't edges to a target — a stale privileged account doesn't reach DA, it is already privileged, quietly, with a weak credential; an orphaned dangerous ACE is a right with no owner that any reused RID inherits. The graph collapses the domain into paths, and these don't express as paths. Kestrel reads the artifacts directly.

Findings carry MITRE ATT&CK tags: orphaned ACE → T1098 (Account Manipulation), stale privileged account → T1078 (Valid Accounts).

The invariant is unchanged

Read-only, ordinary domain user, on-prem, no connection to any host or service it audits. Single native Windows executable — no server, no Python, no agent, no dependencies. --archaeology is part of the core AD audit and runs under --all.

Everything from v1.1 is here too

This release also carries the full v1.1 service-posture layer (Exchange, SCCM, DNS/ADIDNS, domain hardening flags, MITRE ATT&CK tags), including the DNS fix that also scans the forest-wide ForestDnsZones partition.


Kestrel

build license language dependencies

BloodHound shows you the path. Kestrel shows you what's already inside.

Everyone maps the same thing: the attack path - who can reach Domain Admin. It's the right question, and the tools that answer it are excellent. But a graph of "who can reach whom" is blind to an entire class of problem, because some of the worst things in an Active Directory aren't a path at all.

They're a backdoor welded into an attribute. A certificate that keeps authenticating long after the password is reset. A permission stamped into the schema itself, so every object created from now on inherits it silently. A deleted account someone quietly kept the right to bring back. An object hidden from enumeration by a single deny-read ACE.

None of that is an edge in a graph. All of it is sitting in your directory right now. Kestrel reads it - with native…






Apache 2.0. Attached: Kestrel.exe (Release | x64). Build it yourself from source, or grab the binary here.

Top comments (0)