Full_Name: Ryan Tandy Version: master, commit 141f1680 OS: Ubuntu 14.04 URL: ftp://ftp.openldap.org/incoming/rtandy_20140511_fix-passwd-b64-buffer.patch Submission from: (NULL) (24.68.121.206)
The password checkers call lutil_b64_pton like this:
rc = lutil_b64_pton(passwd->bv_val, orig_pass, passwd->bv_len);
However, the size of orig_pass is actually only 3/4 of passwd->bv_len.
Normally this isn't a problem; however, if the length of the password hash is not a multiple of 4, then LUTIL_BASE64_DECODE_LEN rounds down, orig_pass gets a shorter buffer allocated than is actually needed, and it's possible for lutil_b64_pton to write past its end.
(How can that happen? An admin could mess up copy-pasting from slappasswd to userPassword/olcRootPW, as could a user with write access to their own userPassword who decided to set it manually.)
Example:
$ slappasswd -s secret -h '{SSHA}' {SSHA}86ks4vJqfruLKer9skuEpTmgPxcaqSLe
If we lose the last character ('e') and try to authenticate against the length 31 string, clang's AddressSanitizer notices:
==15335==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000049736 at pc 0xef0720 bp 0x7fa9b38d1c10 sp 0x7fa9b38d1c08 WRITE of size 1 at 0x603000049736 thread T2 #0 0xef071f in lutil_b64_pton (libraries/liblutil/base64.c:225) #1 0xe9547c in chk_ssha1 (libraries/liblutil/passwd.c:508) #2 0xe90a09 in lutil_passwd (libraries/liblutil/passwd.c:327) #3 0x7d5e1c in slap_passwd_check (servers/slapd/passwd.c:529) [snip ...] 0x603000049736 is located 0 bytes to the right of 22-byte region [0x603000049720,0x603000049736) allocated by thread T2 here: #0 0x43c9a4 in malloc (/opt/openldap/libexec/slapd+0x43c9a4) #1 0x112903f in ber_memalloc_x (libraries/liblber/memory.c:228) #2 0x1129396 in ber_memalloc (libraries/liblber/memory.c:244) #3 0xe952ea in chk_ssha1 (libraries/liblutil/passwd.c:503) #4 0xe90a09 in lutil_passwd (libraries/liblutil/passwd.c:327) #5 0x7d5e1c in slap_passwd_check (servers/slapd/passwd.c:529) [snip...]
(Built with ./configure CC=clang CFLAGS="-O0 -g -fsanitize=address")
Patch in URL. (Apparently the apr1 passwd module has CRLF endings; sorry for the noisy diff.)
BTW, I noticed in the same routines that orig_pass is allocated with + 1 to the required length, as if it were to be null-terminated, but that's never done. Is that intentional? (AFAICS ber_memalloc doesn't zero memory, maybe I'm wrong.)
thanks, Ryan