LDAP and Citrix ADC / NetScaler

last update: October 2nd 2018

This is the first part of debugging logon problems. The second one, an explanation of aaad.debug log, may be found here.

Recently I had to debug LDAP authentication on Citrix ADC / NetScaler and I started digging deeper.

I wanted to know how LDAP authentication really works, so I did what I always do in a case like that: I started with a network trace.

Citrix ADC / NetScaler: LDAP trace

This is a trace done on my NetScaler.

Attention! Different to default, my NetScaler is load-balancing LDAP-Servers. Therefore all packets don’t origin from NetScaler IP (NSIP) but from subnet-IP (SNIP). Usually all authentication is done by BSD and therefore origins from NSIP. I recommend load balancing LDAP servers!

I did analysis on all of these packets.

  1. bindRequest(1) “LDAP@intern.norz.at” simple
  2. bindResponse(1) success
  3. searchRequest(2) “dc=…” wholeSubtree
  4. seachResEntry(2) “dc=…” | seachResEntry(2) “CN=…”
  5. bindRequest(3) “CN=…” simple
  6. bindResponse(3) success
    bindResponse(3) failed
  7. unbindRequest(4)

1st Packet (266), bindRequest(1)

network trace for a bind request on Citrix ADC / NetScaler

So this is a bind request for LDAP2@intern.norz.at (called Administrator Bind DB, a miss-leading word as this should not be an admin at all for security reasons). In this case it is a service user. It’s permissions would be read only to the whole Active Directory, a permission usually every domain user has. It does not even need the user right log on locally.

Minimum requirements for Administrator Bind DN would be following:

  • read for the Base DN (and the tree below) and the user object itself.
  • read attributes like UPN or sAMAccountName containing the user name or attributes used in filters
  • read for groups (only if you need group extraction)
  • read for attributes PwdLastSet, UserAccountControl, msDS-User-Account-Control-Computed if you need to know if passwords are expired (and trigger password change from Citrix ADC / NetScaler)

In last line we see the MD5 hashed password (simple: …) belonging to this administrative bind DN user.

2nd packet, response from LDAP server, bindResponse(1)

network trace for a bind request on Citrix ADC / NetScalerThis is a simple success message. No more words needed here.

3rd packet, searching for the user’s LDAP name,

network trace for a bind request on Citrix ADC / NetScaler

As mentioned above, we have to locate the user object to get the LDAP name for this user. The Base DN is the top most location in AD, where this user may be found, and of course we will search the whole AD below this location. In my case I search all of a LDAP-directory called intern.norz.at. To restrict to an OU called Enterprise Users we would set Base DN to: ou=Enterprise Users, dc=intern, dc=norz, dc=at.

4th packet, user’s LDAP name and group membership, seachResEntry(2)

network trace for LDAP a bind request on Citrix ADC / NetScalerFor reasons of readability I collapsed some results of minor interest.

The first section is about active directory properties needed. But we are interested in the second section: That’s where user object is located!

First of all, we located a user with LDAP name CN=Johannes Norz, OU=Users, OU=Our’s, DC=intern, DC=norz, DC=at. This user is located in an OU called users which is located in an other OU called Our’s. Normal users would not be able to remember user names like that, that’s why we have to do this step.

We also see, this user is member of two groups: PublishedApps and FaNorz (we see the LDAP names of these groups). This groups will be available from Citrix ADC / NetScaler. This user is also member of Domain Users, but we don’t see this group due to AD internal reasons. That’s why it’s not available in Citrix ADC / NetScaler.

5th packet: Logging on, bindRequest(3)

network trace for LDAP a bind request on Citrix ADC / NetScalerThis one is an important one. We see, we ask to log on a user called CN=Johannes Norz, OU=Users, OU=Our’s, DC=intern, DC=norz, DC=at and a password “top secret Password”

The password is transferred in plain test!

Maybe you don’t like it, but that’s what it is. So you should never use security type TCP PLAINTEXT (TCP 389) for LDAP authentication! Rather use SSL (TCP 636) or TLS (TCP 398) instead! This will encrypt all communication and therefore protect passwords.

6th packet: Success or fail, bindResponse(3)

network trace for LDAP a bind request on Citrix ADC / NetScalerThis is just a message telling us: We had been lucky guessing this highly sophisticated password.

network trace for failed LDAP a bind request on Citrix ADC / NetScaler
Well, this one is the one we won’t like as it’s a failed logon. But we can clearly see: It failed due to invalid credentials!

7th packet: Closing the door, unbindRequest(4)

We are finished, so we tell LDAP to close the connection.

Leave a Reply

Your email address will not be published. Required fields are marked *