---
layout: post
title: "Tracking a secret LoginTime LDAP attribute with Operational Attributes"
tags: [ldap, security]
description: "Using LDAP operational attributes like modifyTimestamp as a side channel to infer hidden login time fields and user activity patterns."
---

During a recent pentest of an LDAP server, I uncovered a clever trick to disclose a hidden attribute which is used to record the exact time a user logs in. In this post, we'll delve into how this technique works, and how it can be used to expose concealed attributes like a 'VpnLoginTime'.

---

## Operational Attributes

Operational attributes are a special type of attributes that provide metadata about LDAP directory entries. There are multiple common ones, such as the following:

**modifyTimestamp**: This attribute records the date and time when an LDAP entry was last modified. It's often used for auditing and tracking changes to directory entries. \
**createTimestamp**: Similar to **modifyTimestamp**, this attribute records the date and time when an LDAP entry was created. \
**entryUUID**: Each LDAP entry is assigned a unique identifier (UUID), which is stored in this attribute. It's useful for tracking entries even if their Distinguished Name (DN) changes. \
**entryDN**: This attribute contains the DN (Distinguished Name) of the entry itself. \
**structuralObjectClass**: It indicates the structural object class of an entry, which defines the type of entry it is. \
**subschemaSubentry**: This attribute points to the subschema entry in the directory, providing information about the schema used in the LDAP directory. \
**entryCSN**: A unique identifier associated with each change made to an LDAP entry. It is generated by the LDAP server and is used to order and track modifications to directory entries. \
**modifiersName**: It stores the DN of the user or entity that performed the last modification on an LDAP entry.


You can search for operational attributes using the '+' query, such as:
```
ldapsearch -o ldif-wrap=no -x -LLL -H ldaps://ldap.server -b "ou=users,dc=example,dc=com"  '+'
```

where we can see, for example:

**modifyTimestamp**: 20230817124530Z \
**createTimestamp**: 20230722093015Z \
**entryUUID**: 679b8b8a-045b-4e55-8a4c-23c7ec0d0012 \
**entryDN**: cn=john.doe,ou=users,dc=example,dc=com \
**structuralObjectClass**: organizationalPerson \
**subschemaSubentry**: cn=Subschema \
**entryCSN**: 20230818070127.624230Z#000000#002#000000 \
**modifiersName**: cn=root,dc=example,dc=com

---

## The 'modifyTimestamp' Trick

**modifyTimestamp** is an _"operational attribute"_ in LDAP which is specifically designed to track the last modification time for an entry. Each user account has this attribute which looks like **20230809062809Z**. This is the YearMonthDayHourMinuteSecond that the user's account was changed _somehow_.

By regularly querying the LDAP server, we can check whether the **modifyTimestamp** value for a specific user has changed.

If, for example, a hidden attribute for a user tracks their last login (such as to a VPN using 'VpnLoginTime'), then we don't need to see the hidden attribute: we just need to see a new **modifyTimeStamp** and no other attribute change.

If we can see the **modifyTimestamp** value change but we do not see any other change to the user, then we know some type of hidden attribute has been modified. If there is no hidden attribute that is being updated regularly, then we can use this as a heuristic to strongly infer that the user has logged in at the new value of **modifyTimestamp**.

---

While tracking a hidden attribute used to keep track of when a user logs in is interesting, there's a whole other discussion about the usefulness of this. Creepy? Sure. Intentional? No. Useful? Well... Maybe an attacker can identify patterns of when a user is logging in for stalking purposes, or for a future social engineering attack with a more realistic time. Regardless of any of this, I just thought this was a fun discovery worth noting somewhere.

---

Of course, it is possible to hide operational attributes, which would also involve the **entryCSN** attribute, since it also tracks time. It may also be necessary to hide the **modifiersName** operational attribute too, since it can be used to infer a change has happened (and even identify the user which made the change).
