Posts Active Directory Fundamentals (Part 4)- NTDS.DIT, LDAP, Schema, Attributes
Post
Cancel

Active Directory Fundamentals (Part 4)- NTDS.DIT, LDAP, Schema, Attributes

Introduction

In this particular post, we’ll look into the Protocols and technologies that make an Active Directory work. At its very core, Active Directory is a distributed database stored on the domain controllers and the changes made on these domain controllers are replicated to each other in a forest. Now, the question is where does AD stores all the data? Well, it stores it inside a database which is stored in NTDS.DIT file. And it is accessed by a protocol called as LDAP (Lightweight Directory Access Protocol). So in simple words, Active Directory is a simple database and LDAP is a way of accessing the database. Let’s discuss these in details.

NTDS.DIT

NTDS stands for NT Directory Services
DIT stands for Directory Information Tree

This is named as NTDS because the Active Directory was called NT Directory Services originally. Directory Information Tree (DIT) in the Active Directory was implemented as a X.500 database and the primary database file is NTDS.DIT, which is stored by default in the %SystemRoot%\NTDS folder (except if the location is changed at initial setup at the time of promoting domain controller).

As we know that Active directory contains folders called organisational units that contain users, computers or other AD objects and since it is a distributed database, it can be replicated and stored at multiple locations at same time. When there are multiple domains, the data in NTDS.DIT for these domains is replicated and the resources in these domains are shared with each other. NTDS.DIT file is a database that stores Active Directory data, including information about user objects, groups, and group membership. LDAP (Lightweight Directory Access Protocol) is used to access the information from the directory. Active Directory database is based on Lightweight Directory Access Protocol (LDAP) and supports the LDAP version 3 specification defined in RFC 2251.

LDAP

NTDS.DIT file also includes the password hashes for all users in the domain.

LDAP (Lightweight Directory Access Protocol)

LDAP protocol is used for accessing directory services and provides a mechanism for applications and other systems to communicate and interact with the directory servers. It is responsible for keeping track of what is on the network and applications can use LDAP to retrieve any object and property of the Active Directory database and can even modify it. When we enumerate information from AD, LDAP is used in the backend. Not only this, LDAP also allows us to modify objects, like modifying groups members, changing attributes of an object. Many enumeration tools have used LDAP to query the information from AD- for example Powerview or Sharpound etc. Anyone who is working with active directory like administrators, red team operators, or developers writing programs to interact with AD, then a thorough understanding of LDAP is very important to fully utilize Active Directory.

LDAP Ports

LDAP port is 389
LDAP Secure (LDAPS) port is 636

LDAP Syntax

Having an understanding of the basic syntax of LDAP would be helpful in order to access a hierarchy of objects using LDAP.

LDAP uses canonical name or cn. If you want to access an object called John, we use cn=john. If there are multiple objects with cn=John, then we need to distinguish this particular john from others by providing more details like where the object is located, so that we can locate that object uniquely. This is achived using the DN (Distinguished Name). DN is the most important LDAP attribute because it uniquely identifies an entry. Like cn=john,ou=users,dc=rootdse,dc=lab

In case of LDAP, each entry consists of three components:

  1. Distinguished Name (DN)
  2. Object Classes
  3. Attributes

Distinguished name (DN) qualifies each entry uniquely. Here’s an example. For the user object SQLServiceAccount, below is the distinguished name:

1
CN=SQLServiceAccount,CN=Users,DC=rootdse,DC=lab

objectClass is a special type of attribute. All objects in LDAP must have an objectClass attribute. The objectClass definition specifies which attributes are required for each LDAP object, and it specifies the object classes of an entry. The values of this attribute may be modified by clients, but the objectClass attribute itself cannot be removed. The objectClass definitions are themselves stored in schema files. Will discuss about Schema later in this post.

Attributes hold data for an entry. Each attribute has a type, options, and a set of values. Attributes values can be customized. Below is the list of some of the attributes that are available from the top class, and subsequently are defined on every object that is created in Active Directory.

Attribute Description
cn RDN attribute for most object classes, also referred to as the common name.
whenCreated Timestamp when the object was created. See Recipe 4.26 for more information.
description attribute that can be used as a generic field for storing a description of the object
displayName Name of the object displayed in administrative interfaces.
distinguishedName Distinguished name of the object.
whenChanged Timestamp when the object was last changed by the local server.
name RDN of the object. The value of this attribute will mirror the naming attribute (e.g., cn, ou, dc).
nTSecurityDescriptor Security descriptor assigned to the object.
objectCategory Used as a grouping mechanism for objects with a similar purpose (e.g., Person).
objectClass List of classes from which the object’s class was derived.
objectGUID Globally unique identifier for the object.
uSNChanged Update sequence number (USN) assigned by the local server after the last change to the object
uSNCreated USN assigned by the local server when the object was created.

objectClass Property

objectClass property of a user object would identify the top, person, organizationalPerson, and user classes. The system sets the objectClass value when the object instance is created and it cannot be changed.

objectCategory Property

Each instance of an object class also has an objectCategory property, which is a single-valued property that contains the distinguished name of either the class of which the object is an instance or one of its superclasses. When an object is created, the system sets its objectCategory property to the value specified by the defaultObjectCategory property of its object class. An object’s objectCategory property cannot be changed.

The cobinations of the ObjectClass vs ObjectCategory are a little complex and not intuitive, the following table documents the result of various combinations of clauses specifying values for objectCategory and objectClass:

objectCategory objectClass Result
person user user objects
person   user and contact objects
person contact contact objects
  user user and computer objects
computer   computer objects
user   user and contact objects
  contact contact objects
  computer computer objects
  person user, computer, and contact objects
contact user and contact objects  
group   group objects
group group objects  
person organizationalPerson user and contact objects
  organizationalPerson user, computer, and contact objects
organizationalPerson   user and contact objects

Powershell can also perform LDAP queries through built-in .NET interfaces. Using [adsisearcher] type accelerator, we can pass a LDAP query and get results since this allows us to access Active Directory objects without importing additional PowerShell modules.

Below is an example of how we can run the LDAP query (objectCategory=computer) to find all domain computer objects :

PS C:\> ([adsisearcher]'(objectCategory=computer)').FindAll()

    Path                                                      Properties
    ----                                                      ----------
    LDAP://CN=RDSEDC01,OU=Domain Controllers,DC=rootdse,DC=lab {ridsetreferences, logoncount, codepage, objectcategory...}
    LDAP://CN=APPSRV01,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=APPSRV02,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=APPSRV03,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=APPSRV04,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=APPSRV05,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=SQLSRV01,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=SQLSRV02,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=SQLSRV03,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=SQLSRV04,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=SQLSRV05,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=VNCSRV01,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=VNCSRV02,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=VNCSRV03,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=VNCSRV04,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=VNCSRV05,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=WEBSRV01,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=WEBSRV02,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=WEBSRV03,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=WEBSRV04,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=WEBSRV05,CN=Computers,DC=rootdse,DC=lab         {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=BCKUPSRV01,CN=Computers,DC=rootdse,DC=lab       {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=BCKUPSRV02,CN=Computers,DC=rootdse,DC=lab       {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=BCKUPSRV03,CN=Computers,DC=rootdse,DC=lab       {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=BCKUPSRV04,CN=Computers,DC=rootdse,DC=lab       {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    LDAP://CN=BCKUPSRV05,CN=Computers,DC=rootdse,DC=lab       {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    

Common LDAP Filters

Below is an example of few common LDAP filters:

Task description LDAP Filter
All accounts with a SPN (serviceprincipalname=*)
All Group Policy Objects (objectcategory=groupPolicyContainer)
All the domains (objectClass=domain)
All the security groups in AD (samaccounttype=268435456)
All the organizational units (objectcategory=organizationalUnit)

LDAP query to get all service accounts which have the value of serviceprincipalname attribute enabled.

PS C:\> ([adsisearcher]'(serviceprincipalname=*)').FindAll()

    Path                                                              Properties
    ----                                                              ----------
    LDAP://CN=RDSEDC01,OU=Domain Controllers,DC=rootdse,DC=lab         {ridsetreferences, logoncount, codepage, objectcategory...}
    LDAP://CN=krbtgt,CN=Users,DC=rootdse,DC=lab                       {logoncount, codepage, objectcategory, description...}
    LDAP://CN=mssql_svc,CN=Managed Service Accounts,DC=rootdse,DC=lab {logoncount, codepage, objectcategory, iscriticalsystemobject...}
    
    

We can get more details in JSON using ConvertTo-JSON. It is very helpful in getting all details of all properties.

PS C:\> ([adsisearcher]'(serviceprincipalname=*)').FindAll() | ConvertTo-Json

Schema

Schema in an Active Directory forest is the blueprint of how data should be stored in AD and it contains the definitions of all object classes that can be created, the definitions of all attribute for those objects. Let’s take an example- We want to create an user account and add information to it by filling its attributes. Here, a user account is an instance of the user class, it uses attributes to store information about that object and display it when the user account is queried. The definitions for user class and many other known classes (like user, computer, organizationalUnit) and attributes (such as telephoneNumber and objectSID) are all defined in the Active Directory Schema.

Note: In an AD forest, there is only a single schema, so if changes are made to schema definition in a forest, it affects all the domains.

Following are some important attributes in Active Directory:

User Attribute Description
userPrincipalName A common logon name (format is similar to email like scarred.monk@rootdse.org)
objectGUID Uniquely identifies a user account. Even if account is moved/renamedd, objectGUID never changes
sAmAccountName Used for account logons to a domain. Used to support clients running on older windows versions
objectSID Security identifier (SID) of the user, used by servers to identify user and their group memberships to authorize users access to domain resources
sIDHistory This attribute contains previous SIDs for the user object. This is only needed if a user has moved to another domain
Distinguished Name (DN) Used to locate objects in Active Directory (by services and applications)

AD schema is composed of a hierarchy of classes that define the types of objects that can be created within Active Directory, as well as the different attributes they can possess. These classes support inheritance, which enables developers to reuse existing class definitions for more than one type of object; for example, the description attribute is available with every type of AD object, but the attribute itself is defined only once within the schema. At the top of the inheritance tree is the top class, from which every class in the schema is derived.

RootDSE

rootDSE is the root of the directory data tree on a directory server and the purpose of the rootDSE is to provide data about the directory server. Checking the attributes of the RootDSE is useful for discovering basic information about a forest, domain, or domain controller.

To view attributes of the RootDSE, we can use below command

PS C:\> Get-ADRootDSE


configurationNamingContext    : CN=Configuration,DC=rootdse,DC=lab
currentTime                   : 6/29/2020 5:09:22 PM
defaultNamingContext          : DC=rootdse,DC=lab
dnsHostName                   : RDSEDC01.rootdse.lab
domainControllerFunctionality : Windows2016
domainFunctionality           : Windows2016Domain
dsServiceName                 : CN=NTDS Settings,CN=RDSEDC01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=rootdse,DC=lab
forestFunctionality           : Windows2016Forest
highestCommittedUSN           : 16513
isGlobalCatalogReady          : {TRUE}
isSynchronized                : {TRUE}
ldapServiceName               : rootdse.lab:rdsedc01$@ROOTDSE.LAB
namingContexts                : {DC=rootdse,DC=lab, CN=Configuration,DC=rootdse,DC=lab, CN=Schema,CN=Configuration,DC=rootdse,DC=lab, DC=DomainDnsZones,DC=rootdse,DC=lab...}
rootDomainNamingContext       : DC=rootdse,DC=lab
schemaNamingContext           : CN=Schema,CN=Configuration,DC=rootdse,DC=lab
serverName                    : CN=RDSEDC01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=rootdse,DC=lab
subschemaSubentry             : CN=Aggregate,CN=Schema,CN=Configuration,DC=rootdse,DC=lab
supportedCapabilities         : {1.2.840.113556.1.4.800 (LDAP_CAP_ACTIVE_DIRECTORY_OID), 1.2.840.113556.1.4.1670 (LDAP_CAP_ACTIVE_DIRECTORY_V51_OID), 1.2.840.113556.1.4.1791 (LDAP_CAP_ACTIVE_DIRECTORY_LDAP_INTEG_OID),
                                1.2.840.113556.1.4.1935 (LDAP_CAP_ACTIVE_DIRECTORY_V61_OID)...}
supportedControl              : {1.2.840.113556.1.4.319 (LDAP_PAGED_RESULT_OID_STRING), 1.2.840.113556.1.4.801 (LDAP_SERVER_SD_FLAGS_OID), 1.2.840.113556.1.4.473 (LDAP_SERVER_SORT_OID), 1.2.840.113556.1.4.528
                                (LDAP_SERVER_NOTIFICATION_OID)...}
supportedLDAPPolicies         : {MaxPoolThreads, MaxPercentDirSyncRequests, MaxDatagramRecv, MaxReceiveBuffer...}
supportedLDAPVersion          : {3, 2}
supportedSASLMechanisms       : {GSSAPI, GSS-SPNEGO, EXTERNAL, DIGEST-MD5}

To check the number of directory objects using an LDAP query, we can use below:

PS C:\> Get-ADObject -Filter {(objectClass -eq "user") -and (objectCategory -eq "person")} | Measure-Object | FL Count

Count : 148


References

https://ldapwiki.com/wiki/ObjectClass%20vs%20ObjectCategory