From 4c0657de592139bd37a0c3fb0d07757f1a8bc73c Mon Sep 17 00:00:00 2001 From: Brian Stafford <contact@brianstafford.info> Date: Mon, 24 Aug 2020 14:09:15 +0100 Subject: [PATCH] Fix potential stack corruption. CVE-2019-19977 * a sufficiently long domain, workstation or user name will overwrite the stack. * nt_unicode() called with incorrect argument possibly reads uninitialised memory. See issue #6. Change lm_uccpy() to return number of bytes copied and to acccept NULL source as a zero length string. 2nd argument to lm_uccpy() is now length of buffer. nt_unicode() now returns NULL if passed zero length string. Update DES API for current OpenSSL. --- ntlm/ntlm.h | 2 +- ntlm/ntlmdes.c | 25 ++++++++------- ntlm/ntlmstruct.c | 79 ++++++++++++++--------------------------------- 3 files changed, 38 insertions(+), 68 deletions(-) diff --git a/ntlm/ntlm.h b/ntlm/ntlm.h index 50a49d6..f0a8a94 100644 --- a/ntlm/ntlm.h +++ b/ntlm/ntlm.h @@ -24,7 +24,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -char *lm_uccpy (char *dst, size_t dstlen, const char *src); +int lm_uccpy (char *dst, size_t dstlen, const char *src); unsigned char *nt_unicode (const char *string, size_t len); void lm_hash_password (unsigned char *hash, const char *pass); diff --git a/ntlm/ntlmdes.c b/ntlm/ntlmdes.c index 57a39d1..083f7f4 100644 --- a/ntlm/ntlmdes.c +++ b/ntlm/ntlmdes.c @@ -30,10 +30,10 @@ #include "ntlm.h" static void -lm_deshash (void *result, const_des_cblock *iv, const void *secret) +lm_deshash (void *result, const_DES_cblock *iv, const void *secret) { - des_cblock key; - des_key_schedule ks; + DES_cblock key; + DES_key_schedule ks; unsigned char key_56[8]; size_t len; @@ -55,9 +55,9 @@ lm_deshash (void *result, const_des_cblock *iv, const void *secret) key[6] = (key_56[5] << 2) | (key_56[6] >> 6); key[7] = (key_56[6] << 1); - des_set_odd_parity (&key); - des_set_key (&key, ks); - des_ecb_encrypt (iv, result, ks, DES_ENCRYPT); + DES_set_odd_parity (&key); + DES_set_key (&key, &ks); + DES_ecb_encrypt (iv, result, &ks, DES_ENCRYPT); /* paranoia */ memset (key, 0, sizeof key); @@ -66,26 +66,26 @@ lm_deshash (void *result, const_des_cblock *iv, const void *secret) /* Copy and convert to upper case. If supplied string is shorter than the destination, zero pad the remainder. */ -char * +int lm_uccpy (char *dst, size_t dstlen, const char *src) { char *p; size_t len; - if ((len = strlen (src)) > dstlen) + if ((len = src != NULL ? strlen (src) : 0) > dstlen) len = dstlen; for (p = dst; len > 0; p++, src++, len--) *p = toupper (*src); if (p < dst + dstlen) memset (p, 0, dst + dstlen - p); - return dst; + return len; } /* create LanManager hashed password */ void lm_hash_password (unsigned char *hash, const char *pass) { - static const_des_cblock iv = { 0x4B, 0x47, 0x53, 0x21, + static const_DES_cblock iv = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 }; char lmpass[14]; @@ -101,6 +101,9 @@ nt_unicode (const char *string, size_t len) { unsigned char *uni, *pp; + if (len == 0) + return NULL; + uni = malloc (len * 2); if ((pp = uni) != NULL) while (len-- > 0) @@ -137,7 +140,7 @@ ntlm_responses (unsigned char *lm_resp, unsigned char *nt_resp, const unsigned char *challenge, const char *secret) { unsigned char hash[21]; - des_cblock nonce; + DES_cblock nonce; memcpy (&nonce, challenge, sizeof nonce); diff --git a/ntlm/ntlmstruct.c b/ntlm/ntlmstruct.c index dfb80de..a42c9cf 100644 --- a/ntlm/ntlmstruct.c +++ b/ntlm/ntlmstruct.c @@ -187,7 +187,6 @@ ntlm_build_type_1 (char *buf, size_t buflen, unsigned int flags, { size_t offset = T1SIZE; size_t len; - unsigned char *up; char string[256]; if (buflen < offset) @@ -195,25 +194,13 @@ ntlm_build_type_1 (char *buf, size_t buflen, unsigned int flags, memcpy (buf, NTLMSSP, 8); write_uint32 (buf, MSGTYPE, 1); write_uint32 (buf, T1FLAGS, flags); - up = NULL; - len = 0; - if (domain != NULL) - { - len = strlen (domain); - if (offset + len > buflen) - return 0; - lm_uccpy (string, len, domain); - } + len = lm_uccpy (string, sizeof string, domain); + if (offset + len > buflen) + return 0; write_string (buf, T1DOMAIN, &offset, string, len); - up = NULL; - len = 0; - if (workstation != NULL) - { - len = strlen (workstation); - if (offset + len > buflen) - return 0; - lm_uccpy (string, len, workstation); - } + len = lm_uccpy (string, sizeof string, workstation); + if (offset + len > buflen) + return 0; write_string (buf, T1WKSTN, &offset, string, len); return offset; } @@ -232,16 +219,11 @@ ntlm_build_type_2 (char *buf, size_t buflen, unsigned int flags, return 0; memcpy (buf, NTLMSSP, 8); write_uint32 (buf, MSGTYPE, 2); - up = NULL; - len = 0; - if (domain != NULL) - { - len = strlen (domain); - if (offset + 2 * len > buflen) - return 0; - up = nt_unicode (lm_uccpy (string, len, domain), 2 * len); - } - write_string (buf, T2AUTHTARGET, &offset, up, len); + len = lm_uccpy (string, sizeof string, domain); + if (offset + 2 * len > buflen) + return 0; + up = nt_unicode (string, len); + write_string (buf, T2AUTHTARGET, &offset, up, 2 * len); if (up != NULL) free (up); write_uint32 (buf, T2FLAGS, flags); @@ -267,39 +249,24 @@ ntlm_build_type_3 (char *buf, size_t buflen, unsigned int flags, write_uint32 (buf, MSGTYPE, 3); write_string (buf, T3LMRESPONSE, &offset, lm_resp, 24); write_string (buf, T3NTRESPONSE, &offset, nt_resp, 24); - up = NULL; - len = 0; - if (domain != NULL) - { - len = strlen (domain); - if (offset + 2 * len > buflen) - return 0; - up = nt_unicode (lm_uccpy (string, len, domain), 2 * len); - } + len = lm_uccpy (string, sizeof string, domain); + if (offset + 2 * len > buflen) + return 0; + up = nt_unicode (string, len); write_string (buf, T3DOMAIN, &offset, up, 2 * len); if (up != NULL) free (up); - up = NULL; - len = 0; - if (user != NULL) - { - len = strlen (user); - if (offset + 2 * len > buflen) - return 0; - up = nt_unicode (lm_uccpy (string, len, user), 2 * len); - } + len = lm_uccpy (string, sizeof string, user); + if (offset + 2 * len > buflen) + return 0; + up = nt_unicode (string, len); write_string (buf, T3USER, &offset, up, 2 * len); if (up != NULL) free (up); - up = NULL; - len = 0; - if (workstation != NULL) - { - len = strlen (workstation); - if (offset + 2 * len > buflen) - return 0; - up = nt_unicode (lm_uccpy (string, len, workstation), 2 * len); - } + len = lm_uccpy (string, sizeof string, workstation); + if (offset + 2 * len > buflen) + return 0; + up = nt_unicode (string, len); write_string (buf, T3WKSTN, &offset, up, 2 * len); if (up != NULL) free (up);