Last Update: Sep 24, 2024 | Published: Jan 06, 2009
By default, anonymous LDAP operations, except rootDSE searches and binds, are not permitted on Windows 2003 domain controllers. This means that when trying to perform unauthenticated search in Active Directory, you can query for attributes of the RootDSE object only – any other query will result in domain controller requesting authenticated bind to LDAP and refusing to your query.
Actually this is new behavior compared to Windows 2000 domain controllers which allowed anonymous operations and the query results were based only on the permissions of the objects.
“So what is it good for?” you might ask yourself. Well, one of the reasons is minimizing the impact of potential denial of service (DoS) attacks against AD. Consider a malicious application performing an anonymous LDAP query against domain controller. Theoretically, by crafting a very complicated LDAP filter with a “Sub” scope, an attacker could overload the LDAP server which would result in significant degradation in domain controller performance and even total denial of service.
Why you might want to enable anonymous binds? Usually this is desired when you need to provide an easy access to a subset of information stored in AD to 3rd party applications that are not capable of authenticating to AD or the information is intended to be in public domain from the beginning and you are storing it in AD. The scenarios are infinite, but before enabling anonymous operations make sure that you truly understand the implications of this action – the change (though reversible) does increase the security risks to your environment.
Let’s have a look at what are we allowed to see when we are trying to perform an anonymous lookup against W2K3 domain controller.
The query below is performed from a Linux machine just to eliminate the query tools attempts on Windows to perform GSSAPI authentication in the background.
Just to decipher the syntax above:
-h descartes.antid0t.net | perform the query against host descartes.antid0t.net |
-b ” | Use RootDSE as the search base |
-x | Use simple bind |
-LLL | Print responses in LDIF format without comments and version |
-s base | Do base search (as opposed to subtree or onelevel) |
‘objectClass=*’ | LDAP filter which basically means: return anything you find |
Not much, right? Just enough to be able to negotiate the correct authentication dialect, learn about LDAP protocol versions supported, enumerate the partitions and acquire some more details about the LDAP semantics supported by the server.
Notice that I had to use “base” scope query. Trying to perform “Subtree” or “OneLevel” query would yield the DC requiring authenticated bind:
CN=Directory Service,CN=Windows NT,CN=Services,
Where <forestRoot> is the root domain of your forest (in my case this is DC=antid0t,DC=net)
Warning: if the attribute already contains a value, make sure you are changing only the seventh character from the left – this is the only character that needs to be changed in order to enable anonymous binds. So for example if the current value is “0010000”, you will need to change it to “0010002”.
If the current value is less than 7 characters, you will need to put zeros in the places not used: “001” will become “0010002”
Let’s test it:
As you can see, now we are allowed a little more: we are allowed to perform “Sub” queries against all the AD partitions. Though this step allows unauthenticated operations against AD, only a very small subset of attributes are being exposed. The step can be compared to opening the lobby door of an apartment building – you can travel around, but all the doors to the apartments are closed.
This step involves granting “NT AUTHORITY’ANONYMOUS LOGON” (well know security principal) access to objects you want to be able to be located by the means of anonymous lookups. This can be compared to opening some doors to the apartments inside the building.
Let’s give it a try and expose some details about one of my computers to the public:
Let’s test it:
Hey! This didn’t work! Well, apparently there is a good reason for that: you need to grant at least “List Contents” permission to the “ANONYMOUS LOGON” on the OU the object, you are querying for, resides in.
How do you do that?
Now let’s try it again:
Hurray! Now it works.
Happy binding!