ESE
- libesedb
- Library/toolchain
- GH issue for Impacket ESE DB getNextRow
- How is ntds.dit organized? | Habr
- Best writeup I've seen thus far
- Archive because who knows how reliable this link to an old post in Russian will be (this version is the original Russian - you'll need to plug it into Google Translate manually)
- How the Active Directory - Data Store Really Works (Inside NTDS.dit) - Part 1
MS Docs
- How the Data Store Works
- objectClass, RDN, DN, Constructed Attributes, Secret Attributes
- ESE Deep Dive: Part 1: The Anatomy of an ESE database
- Archive if MS decides to delete for some reason
TODO
NOTE: These are personal scratch notes while trying to deep-dive into the ESE engine/JET API.
In ~/git/Extensible-Storage-Engine/dev/ese/src/eseutil/eseutil.cxx
, look at wmain
. If we search modeDump
, we can see what esentutl
does to init a dump.
For something resembling an info/tutorial, see: ~/git/Extensible-Storage-Engine/test/ese/src/samples/SvcInitSample/SvcInitMainGoo.c
JET error codes: https://learn.microsoft.com/en-us/windows/win32/extensible-storage-engine/extensible-storage-engine-error-codes
For base JET API, see: dev/ese/src/ese/jetapi.cxx
Example funcs:
JetAttachDatabaseW
JetCreateDatabaseW
JetOpenDatabaseW
JetGetColumnInfoW
Don't forget https://github.com/microsoft/ManagedEsent
DumpToCsv.cs: https://github.com/Microsoft/ManagedEsent/blob/master/EsentInteropSamples/DbUtil/DumpToCsv.cs#L108
Extras
Quality isn't quite as good, but still useful
- New features in Active Directory Domain Services in Windows Server 2012, Part 18: DNTs Exposed
- ACTIVE DIRECTORY BACKDOORS: Myth or Reality BTA: an open source framework to analyse AD
- BTA -> open-source AD security audit framework, could be useful for more detailed extraction from ESENT
- BTA repo
- Also see: Airbus security lab publications
- How is ntds.dit structured
- TODO: Dead link
Querying AD dumps
NOTE: I'm assuming the attributes have been translated from the internal ATTx names. I also screwed up the JSON originally (there are trailing commas), so hjson
is used to normalize before passing off to jq
.
Find a specific user by username:
hjson -j < datatable-not-null.json | jq '.[] | select(.sAMAccountName=="NORMAND_VAZQUEZ")'
Find a user by DNT (i.e. distinguishedName, internally the "primary key" of sorts for this user):
hjson -j < datatable-not-null.json | jq '.[] | select(.DNT_Col==5198)'
hjson -j < datatable-not-null.json | jq '.[] | select(.distinguishedName==5198)'
Find this user's parent object (go recursively for the entire human-readable DN!):
PDNT_col=$(hjson -j < datatable-not-null.json | jq '.[] | select(.DNT_col==5198) | .PDNT_col')
hjson -j < datatable-not-null.json | jq '.[] | select(.DNT_Col=='$PDNT_col')'
Find this user's "children":
hjson -j < datatable-not-null.json | jq '.[] | select(.PDNT_col==5198)'
See all group memberships for this user (and possibly others):
cat link_table.5.json | jq '.[] | select(.backlink_DNT=="5198")'
NOTE: Yes, the quotes do matter for the link table even though DNT is numeric.
See all members of a group:
cat link_table.5.json | jq '.[] | select(.link_DNT==7272)'