samwyse
samwyse

Reputation: 2996

Unable to parse www-authenticate for NTLM, value seems too short?

I'm trying to authenticate to one of my company's servers. My initial attempt to connect returns a 401 with the header:

www-authenticate: NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAVU9wgQTnlrgAAAAAAAAAAA==

Parsing the base64 portion, I get this:

0000   4E 54 4C 4D 53 53 50 00 02 00 00 00 00 00 00 00    NTLMSSP.........
0010   28 00 00 00 01 82 00 00 B6 70 AC 57 8C D0 07 44    (........p.W...D
0020   00 00 00 00 00 00 00 00                            ........

That in turn parses into this:

Signature = NTLMSSP
msg_type = 2
TargetNameLen = 0
TargetNameMaxLen = 0
TargetNameOffset = 40
NegotiateFlags = 0x8201
ServerChallenge = B6 70 AC 57 8C D0 07 44

This is where I should mention that I'm not parsing this myself. I don't think it matters, but I'm using Python 2.7, with freshly installed copies of python_ntlm-1.0.1 and requests-ntlm 0.0.2.1, and the ntlm module is crashing in its parse_NTLM_CHALLENGE_MESSAGE routine because the packet is too short. Starting at offset 0x0020, there is apparently supposed to be a 16-byte reserved area followed by three more 32-bit integers, instead there's only 8 bytes of hex 00 in the reserved area and the other numbers are missing. This is the first time I've needed anything more that basic authentication. I'm suspecting that the TargetNameLen being 0 means something special, but before I file a bug report with the python_ntlm maintainers, can someone help me interpret the data that I'm getting?

Thanks!

Upvotes: 0

Views: 868

Answers (1)

samwyse
samwyse

Reputation: 2996

It turns out that the problem is with how the NegotiateFlags field is being interpreted. According to Microsoft's published specs, there are two bits of interest. If the NTLMSSP_REQUEST_TARGET flag is not set, no TargetName is required, while if NTLMSSP_NEGOTIATE_TARGET_INFO isn't set, no TargetInfo is required. However, due to the evolution of the packet's format over the years, the TargetName fields preceed the NegotiateFlags, so they must be present and zero-filled even when ignored. The TargetInfo fields, on the other hand, appear after the NegotiateFlags field and so can be elided, leaving one with a shorter packet. I've submited a patch to the python-ntlm project and everything should be fixed soon. I'm providing this solution in case this trips up someone else writing their own authentication code in the future.

Upvotes: 2

Related Questions