joeware - never stop exploring... :)

Information about joeware mixed with wild and crazy opinions...

LDAP Ping and Determining Your Machine’s Site

by @ 8:09 pm on 3/31/2019. Filed under tech

Microsoft has a specific method for returning basic information that can be used for finding what site (and what is the next closest site) for any given machine that reaches out to a domain controller with a LDAP query. Originally the query had to be performed over CLDAP (connectionless LDAP aka UDP LDAP) but sometime in the Windows Server 2003 timeframe it became available via both UDP and TCP. Personally I like the TCP ping over the UDP ping because no applications are actually using UDP to use AD and this functionality.

The "ping" is a specially crafted anonymous LDAP query that retrieves the NetLogon attribute from the RootDSE of a Domain Controller which then returns the attribute in one of several available BLOB formats. The information returned useful for bootstrapping and validation and in particular for this specific topic, finding out which AD site the client is in. The "LDAP Ping" is documented fully in section 6.3 “Publishing and Locating a Domain Controller” of the Microsoft MS-ADTS Protocol Documentation including the various BLOB structures. Note that when it says something is Big-Endian, pay attention, it is critical to getting a response back.

The key pages are:

6.3 Publishing and Locating a Domain Controller   — Base of all of the documentation

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/8ebcf782-87fd-4dc3-8585-1301569dfe4f

6.3.1 Structures and Constants

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/b3006506-4338-45ef-ac52-1e7d5c9c46e9

6.3.3. LDAP Ping

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/895a7744-aff3-4f64-bcfa-f8c05915d2e9

6.3.7 Name Compression and Decompression

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/b0ef9479-78d8-40c1-b6d2-0baad834ed39

I will be releasing a full platform agnostic anonymous DC Locator perl script in the relatively near term that has this implemented as part of the code along with the DNS lookups and some validation tests. I also have generated some notes and a DCR to implement the decoding of this data in AdFind as well. As it is, this is what AdFind will show you right now if you attempt to query for this information:

[Fri 03/29/2019 23:07:04.51]
E:\DEV\Schema>adfind -rootdseanon -f "&(host=k16tst-dc1)(ntver=\04\00\00\00)" -s one netlogon

AdFind V01.51.00cpp Joe Richards (support@joeware.net) October 2017

Using server: K16TST-DC1.k16tst.test.loc:389
Directory: Windows Server 2016

dn:
> netlogon: 1700 0000 FDF1 0100 9011 FD98 67E1 3447 A585 7981 238A 135E 066B 3136 7473 7404 7465 7374 036C 6F63 00C0 180A 4B31 3654 5354 2D44 4331 C018 064B 3136 5453 5400 0A4B 3136 5453 542D 4443 3100 0017 4465 6661 756C 742D 4669 7273 742D 5369 7465 2D4E 616D 6500 136A 6F65 6E65 746C 6F67 6F6E 7465 7374 7369 7465 0005 0000 00FF FFFF FF

1 Objects returned

This is what WireShark will show you:

SNAGHTML4475a203

Now you can also implement the “next closest site” functionality as well with the following query (and this is what jwDCLocator.pl uses)… With this one I needed to specify a specific DC in another site as well as change the ntver attribute value to include NETLOGON_NT_VERSION_WITH_CLOSEST_SITE so that the proper extra info would be sent along…

[Fri 03/29/2019 23:08:14.64]
E:\DEV\Schema>adfind -hh k16tst-scdc1.k16tst.test.loc -rootdseanon -f "&(host=k16tst-scdc1)(ntver=\14\00\00\00)" -s one netlogon

AdFind V01.51.00cpp Joe Richards (support@joeware.net) October 2017

Using server: K16TST-SCDC1.k16tst.test.loc:389
Directory: Windows Server 2016

dn:
> netlogon: 1800 0000 7CF1 0100 9011 FD98 67E1 3447 A585 7981 238A 135E 066B 3136 7473 7404 7465 7374 036C 6F63 00C0 180C 4B31 3654 5354 2D53 4344 4331 C018 064B 3136 5453 5400 0C4B 3136 5453 542D 5343 4443 3100 0005 5369 7465 3200 136A 6F65 6E65 746C 6F67 6F6E 7465 7374 7369 7465 0017 4465 6661 756C 742D 4669 7273 742D 5369 7465 2D4E 616D 6500 1500 0000 FFFF FFFF

1 Objects returned

Unfortunately WireShark gets lost for this extra data and so it doesn’t display really anything…

SNAGHTML4478f6bb

But if you look down in the packet bytes data you will see it…

SNAGHTML4479c064

which you can see three site names in it…

And of course jwDCLocator.pl knows how to decode it properly…

Dynamically determining site…
  Sending LDAP Ping to LDAP://k16tst-scdc1.k16tst.test.loc:389…
  AutoDetected Server Site             : Site2
  AutoDetected Client Site             : joenetlogontestsite
  AutoDetected Client Next Closest Site: Default-First-Site-Name
Determining site specific DNS records…

The binary (with and without the closest site flag in the query) is described by the structure that can be found at

6.3.1.9 NETLOGON_SAM_LOGON_RESPONSE_EX

https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/8401a33f-34a8-40ca-bf03-c3484b66265f

Extracting the information from this structure is not quite as straightforward as what you normally get in that they are compressing the names as described in RFC 1035 – “Domain Names – Implementation and Specification” which is further described in the page mentioned above, 6.3.7 Name Compression and Decompression. Note that when I was writing my perl script I hadn’t seen this page yet so I just looked at the binary and shook my head a few times to clear cobwebs and reversed it out. That means that my original perl script may be implemented slightly differently than what is described and it also means I cannot actually vouchsafe for the pseudocode given on the page so if you use it directly, validate it versus just assume it is 100%. But that goes for all documentation from all vendors at all times. Smile 

Note that Perl has some functionality in the Net::DNS module that will decode these for you but I wanted to be as raw as possible in the code to allow people to be able to take the code and change to any language, framework, platform they wanted and be able to do something. Hiding some of the details like this by using other modules defeats that mindset a little.

Now for some samples from jwDCLocator.pl decoding some of compressed string in the structure. As the structure is decoded, a table will be created with strings that are referred to, this is used for the “compression” functionality. If the string isn’t in the table already you will get a length value and the string. If part of the string is in the table (as part of another string response) then you will get whatever part is unique as the length and string and then a pointer to the rest of the string. For clarity of the following examples, this is the table that gets built in memory as the structure is unpacked:

’24’ => ‘k16tst.test.loc’,
’41’ => ‘k16tst.test.loc’,
’43’ => ‘K16TST-SCDC1.k16tst.test.loc’,
’58’ => ‘K16TST’,
’66’ => ‘K16TST-SCDC1’
’80’ => ”,
’81’ => ‘Site2’,
’88’ => ‘joenetlogontestsite’,
‘109’ => ‘Default-First-Site-Name’,

First, the DNS Forest Name.

SNAGHTML4cf5c580

20190331-144158.89286: DEBUG: NETLOGON REMAINING=066b31367473740474657374036c6f6300c0180a4b313654535
                                                  42d444332c018064b3136545354000a4b31365453542d444332
                                                 000005536974653200136a6f656e65746c6f676f6e746573747
                                                  3697465001744656661756c742d46697273742d536974652d4e
                                                  616d650015000000ffffffff
  20190331-144158.89290: DEBUG: Enter GetCompressedName…
  20190331-144158.89293: DEBUG: +++++++++++++++++++++
  20190331-144158.89296: DEBUG: Start Data     : 066b31367473740474657374036c6f6300c0180a4b3136545354
                                                 2d444332c018064b3136545354000a4b31365453542d44433200
                                                 0005536974653200136a6f656e65746c6f676f6e746573747369
                                                 7465001744656661756c742d46697273742d536974652d4e616d
                                                 650015000000ffffffff
  20190331-144158.89299: DEBUG: Enter GetXChars…
  20190331-144158.89303: DEBUG: Short Hint     : 0
  20190331-144158.89306: DEBUG: Enter GetXChars…
  20190331-144158.89309: DEBUG: Full Hint      : 06
  20190331-144158.89313: DEBUG: Enter GetXChars…
  20190331-144158.89317: DEBUG: Enter HexToASCII…
  20190331-144158.89322: DEBUG: String         : k16tst
  20190331-144158.89330: DEBUG: Full String    : k16tst.
  20190331-144158.89338: DEBUG: ———————
  20190331-144158.89346: DEBUG: +++++++++++++++++++++
  20190331-144158.89352: DEBUG: Start Data     : 0474657374036c6f6300c0180a4b31365453542d444332c018064
                                                 b3136545354000a4b31365453542d444332000005536974653200
                                                 136a6f656e65746c6f676f6e74657374736974650017446566617
                                                 56c742d46697273742d536974652d4e616d650015000000ffffff
                                                ff
  20190331-144158.89357: DEBUG: Enter GetXChars…
  20190331-144158.89364: DEBUG: Short Hint     : 0
  20190331-144158.89370: DEBUG: Enter GetXChars…
  20190331-144158.89376: DEBUG: Full Hint      : 04
  20190331-144158.89382: DEBUG: Enter GetXChars…
  20190331-144158.89388: DEBUG: Enter HexToASCII…
  20190331-144158.89395: DEBUG: String         : test
  20190331-144158.89401: DEBUG: Full String    : k16tst.test.
  20190331-144158.89407: DEBUG: ———————
  20190331-144158.89413: DEBUG: +++++++++++++++++++++
  20190331-144158.89418: DEBUG: Start Data     : 036c6f6300c0180a4b31365453542d444332c018064b313654535
                                                 4000a4b31365453542d444332000005536974653200136a6f656e
                                                65746c6f676f6e7465737473697465001744656661756c742d466
                                                 97273742d536974652d4e616d650015000000ffffffff
  20190331-144158.89424: DEBUG: Enter GetXChars…
  20190331-144158.89431: DEBUG: Short Hint     : 0
  20190331-144158.89437: DEBUG: Enter GetXChars…
  20190331-144158.89451: DEBUG: Full Hint      : 03
  20190331-144158.89456: DEBUG: Enter GetXChars…
  20190331-144158.89459: DEBUG: Enter HexToASCII…
  20190331-144158.89463: DEBUG: String         : loc
  20190331-144158.89466: DEBUG: Full String    : k16tst.test.loc.
  20190331-144158.89468: DEBUG: ———————
  20190331-144158.89471: DEBUG: +++++++++++++++++++++
  20190331-144158.89474: DEBUG: Start Data     : 00c0180a4b31365453542d444332c018064b3136545354000a4b3
                                                1365453542d444332000005536974653200136a6f656e65746c6f
                                                 676f6e7465737473697465001744656661756c742d46697273742
                                                 d536974652d4e616d650015000000ffffffff
  20190331-144158.89478: DEBUG: Enter GetXChars…
  20190331-144158.89481: DEBUG: Short Hint     : 0
  20190331-144158.89484: DEBUG: Enter GetXChars…
  20190331-144158.89486: DEBUG: Full Hint      : 00
  20190331-144158.89490: DEBUG: FINAL Full String: k16tst.test.loc

And here is the cool part… On the next bit, getting the DNS Domain Name

SNAGHTML4d0097b4

20190328-220801.19632: DEBUG: Enter GetCompressedName…
20190328-220801.19635: DEBUG: +++++++++++++++++++++
20190328-220801.19638: DEBUG: Start Data     : c0180a4b31365453542d444331c018064b3136545354000a4b3136
                                               5453542d44433100001744656661756c742d46697273742d536974
                                                652d4e616d6500136a6f656e65746c6f676f6e7465737473697465
                                                00c04d15000000ffffffff
20190328-220801.19641: DEBUG: Enter GetXChars…
20190328-220801.19644: DEBUG: Short Hint     : c
20190328-220801.19646: DEBUG: Enter GetXChars…
20190328-220801.19649: DEBUG: Compression Offset — 0x0018 — 24
20190328-220801.19652: DEBUG: FINAL Full String: k16tst.test.loc

And then the Host’s FQDN…

SNAGHTML4d029b74

20190328-220801.19666: DEBUG: Enter GetCompressedName…
20190328-220801.19667: DEBUG: +++++++++++++++++++++
20190328-220801.19668: DEBUG: Start Data     : 0a4b31365453542d444331c018064b3136545354000a4b31365453
                                                542d44433100001744656661756c742d46697273742d536974652d
                                                4e616d6500136a6f656e65746c6f676f6e746573747369746500c0
                                                4d15000000ffffffff
20190328-220801.19669: DEBUG: Enter GetXChars…
20190328-220801.19670: DEBUG: Short Hint     : 0
20190328-220801.19671: DEBUG: Enter GetXChars…
20190328-220801.19672: DEBUG: Full Hint      : 0a
20190328-220801.19673: DEBUG: Enter GetXChars…
20190328-220801.19674: DEBUG: Enter HexToASCII…
20190328-220801.19676: DEBUG: String         : K16TST-DC1
20190328-220801.19677: DEBUG: Full String    : K16TST-DC1.
20190328-220801.19678: DEBUG: ———————
20190328-220801.19679: DEBUG: +++++++++++++++++++++
20190328-220801.19680: DEBUG: Start Data     : c018064b3136545354000a4b31365453542d444331000017446566
                                                61756c742d46697273742d536974652d4e616d6500136a6f656e65
                                                746c6f676f6e746573747369746500c04d15000000ffffffff
20190328-220801.19681: DEBUG: Enter GetXChars…
20190328-220801.19682: DEBUG: Short Hint     : c
20190328-220801.19683: DEBUG: Enter GetXChars…
20190328-220801.19684: DEBUG: Compression Offset — 0x0018 — 24
20190328-220801.19685: DEBUG: FINAL Full String: K16TST-DC1.k16tst.test.loc

Rating 4.60 out of 5

Comments are closed.

[joeware – never stop exploring… :) is proudly powered by WordPress.]