]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: http_ana: make the detection of NTLM variants safer
authorWilly Tarreau <w@1wt.eu>
Thu, 7 May 2020 17:27:02 +0000 (19:27 +0200)
committerWilly Tarreau <w@1wt.eu>
Thu, 7 May 2020 17:41:12 +0000 (19:41 +0200)
In issue #511 a problem was reported regarding NTLM and undesired session
sharing. This was caused by an attempt to limit the protection against
NTLM breakage to just NTLM and not properly working schemes in commit
fd9b68c48 ("BUG/MINOR: only mark connections private if NTLM is detected").

Unfortunately as reported in the issue above, the extent of possible
challenges for NTLM is a bit more complex than just the "NTLM" or
"Negotiate" words. There's also "Nego2" and these words can be followed
by a base64 value, which is not validated here. The list of possible
entries doesn't seem to be officially documented but can be reconstructed
from different public documents:

  https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-ntht/7daaf621-94d9-4942-a70a-532e81ba293e
  https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-n2ht/5c1d2bbc-e1d6-458f-9def-dd258c181310
  https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-n2ht/9201ed70-d245-41ce-accd-e609637583bf
  https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-n2ht/02be79f3-e360-475f-b468-b96c878c70c7

This patch tries to fix all this on top of previous attempts by making
as private any connection that returns a www-authenticate header starting
with "Nego" or "NTLM". We don't need to be too strict, we really just
want to leave the connection shared if really sure it can be.

This must be backported to 1.8 but will require some adaptations. In
1.9 and 2.0 the check appears both for legacy and HTX. The simplest
thing to do is to look for "Negotiate" and fix all relevant places.

src/http_ana.c

index 79124e7567a42c04f21ffc5555d94494a498d334..46858c8674aa519692cf0627bc8de9fb55a30abf 100644 (file)
@@ -1823,10 +1823,17 @@ int http_wait_for_response(struct stream *s, struct channel *rep, int an_bit)
 
                ctx.blk = NULL;
                while (http_find_header(htx, hdr, &ctx, 0)) {
-                       if ((ctx.value.len >= 9 && word_match(ctx.value.ptr, ctx.value.len, "Negotiate", 9)) ||
+                       /* If www-authenticate contains "Negotiate", "Nego2", or "NTLM",
+                        * possibly followed by blanks and a base64 string, the connection
+                        * is private. Since it's a mess to deal with, we only check for
+                        * values starting with "NTLM" or "Nego". Note that often multiple
+                        * headers are sent by the server there.
+                        */
+                       if ((ctx.value.len >= 4 && strncasecmp(ctx.value.ptr, "Nego", 4) == 0) ||
                            (ctx.value.len >= 4 && strncasecmp(ctx.value.ptr, "NTLM", 4) == 0)) {
                                sess->flags |= SESS_FL_PREFER_LAST;
                                srv_conn->flags |= CO_FL_PRIVATE;
+                               break;
                        }
                }
        }