[<prev] [next>] [month] [year] [list]
Date: Thu, 05 Mar 2009 10:55:53 +0100
From: Jan Lieskovsky <jlieskov@...hat.com>
To: "Steven M. Christey" <coley@...us.mitre.org>
Cc: oss-security@...ts.openwall.com, Marcus Granado <smurca@...glemail.com>
Subject: CVE Request -- pam
Hello Steve,
Marcus Granado recently reported a security issue in
libpam related to parsing of non-ascii usernames in
the Pam configuration files. Attaching his report for
more details.
Affected version: pam <= 1.0.3
Link to SCM repo: http://pam.cvs.sourceforge.net/viewvc/pam/Linux-PAM/libpam/pam_misc.c?view=log
Patch: http://pam.cvs.sourceforge.net/viewvc/pam/Linux-PAM/libpam/pam_misc.c?r1=1.9&r2=1.10&view=patch
Could you please allocate a new CVE id for it?
Thanks && regards, Jan.
--
Jan iankko Lieskovsky / Red Hat Security Response Team
Hello,
I believe I have found a bug in libpam while trying to make PAM authenticate an ssh login whose username contained unicode/utf-8 characters, and wouldlike to know if it is possible for you to reproduce and patch it if that's the case. The bug only affects the parsing of non-ascii usernames in the PAM configuration files. These files can only be modified by root, so only root can unintentionally trigger the bug.
In a nutshell, there is a faulty char->int type conversion in the function _pam_StrTok at pam_misc.c lines 62, 65 and 95, which results in negative integers when characters values are above 127. This problem seems present in all libpam versions I verified, inclusive the latest 1.0.3 available at http://pam.cvs.sourceforge.net/viewvc/pam/Linux-PAM/libpam/pam_misc.c?view=markup#l_93
An example of this faulty conversion is in line 95 of pam_misc.c, where the code indexes the blank-char 'table' array using the current char value pointed to by 'end':
< } else if (*from) {
< /* simply look for next blank char */
< for (end=from; *end && !table[(int)*end]; ++end);
The problem is that this char value returned by '*end' is signed by default (in gcc 4.1.2 20071124 (Red Hat 4.1.2-42) on a x86 box, see [1] below), and when non-ascii characters (those with values above 127, like many utf-8 characters) are used, it is interpreted as a negative value during the conversion to 'int'. So, instead of indexing the array 'table' from 0-255, the code is indexing it from -128 to 127, accessing memory outside the table (and probably outside the function stack frame as well) and leading to unpredictable results when non-ascii characters are used.
In my case (please see the /var/log/secure and /var/run/pam-debug.log logs below), I was experiencing the unusual result that _pam_StrTok was receiving the string "user = DOMAD\userα" to parse (notice the trailing alpha character, utf-8 representation 0xCE,0xB1 in hex), and outputting "DOMAD\user" as the arg#3 (observe that the alpha character disappeared). That was leading the pam_succeed_if module to receive "DOMAD\user" as the variable 'right' and resolving the variable 'user' to "DOMAD\userα", never matching them and returning a failed authentication result to the sshd daemon .
My patch was to explicitly make sure that the char->int conversion actually happens in the range 0-255, by adding an intermediate (unsigned char) step from 'char' to 'int':
> } else if (*from) {
> /* simply look for next blank char */
> for (end=from; *end && !table[(int)((unsigned char)*end)]; ++end);
That makes the blank-char table be looked up in the correct range, and arg#3 now returns the expected unicode username in argv so that pam_succeed_if works properly. I applied the same unsigned char patch to lines 62 and 65. Line 62 is a bit more worrisome because it allows using the 'format' input parameter of _pam_Strtok to corrupt the frame stack by writing 'y' (0x79) characters around it.
The problems caused by this bug are at least two-fold:
1) It causes the pam_succeed_if module to allow a user without leading/trailing unicode characters in his/her username to be allowed access as another user whose username contains leading/trailing unicode characters in the /etc/pam.d/* config files (I tested that), because one side-effect of this bug (as seen in the logs below) is that leading/trailing unicode characters are potentially removed from the string parameters during username matching requirements.
2) It causes the trusted libpam code to access memory outside the expected table array, causing a buffer overrun, most likely outside the function frame stack, with unpredictable results.
The patch above on lines 62, 65 and 95 of pam_misc.c would be sufficient to fix it. Please let me know what you think or if you suggest a different approach for the fix.
Thanks,
Marcus
--
[1] here is a quick discussion on the signedness of chars in gcc. It says that other compilers/architectures might choose to default 'char' differently between signed and unsigned, though it seems that all gcc versions on x86 will behave similarly and default to signed: An Introduction to GCC - for the GNU compilers gcc and g++ http://www.network-theory.co.uk/docs/gccintro/gccintro_71.html
Please check out the
Open Source Software Security Wiki, which is counterpart to this
mailing list.
Hosted by DataForce ISP -
Powered by Openwall GNU/*/Linux