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).