ASA-0001: OpenBSD chpass/chfn/chsh file content leak

From: Marc Bevand (bevand_mat_private)
Date: Mon Feb 03 2003 - 01:58:33 PST

  • Next message: Marc Ruef: "Denial of service against Kazaa Media Desktop v2"

                          "After" Security Advisory
    
            Title: OpenBSD chpass/chfn/chsh file content leak
          Affects: chpass/chfn/chsh from OpenBSD (from 2.0 to 3.2)
      Advisory ID: ASA-0001
     Release Date: 2003-02-03
           Author: Marc Bevand <bevand_m (at) epita.fr>
              URL: http://www.epita.fr/~bevand_m/asa/asa-0001
    
    
    --oOo-- 0. Table of Contents
    
    0. Table of Contents
    1. Introduction
    2. Problem
    3. Solution
    4. Conclusion
    5. References
    6. Attached files
    
    
    --oOo-- 1. Introduction
    
      OpenBSD [1] provides a setuid-root tool, chpass(1) (or chfn, or
    chsh, which are hard links to the same binary file), that allows
    editing of the user database information. This tool can be exploited
    to partially display the content of any file. But to make this
    happen, the content of the file has to match a very particular
    format, making the vulnerability practically useless in real-world
    situations.
    
    
    --oOo-- 2. Problem
    
      chpass writes user database information in a temporary file, and
    supplies it to an editor for changes. While the editor is running, the
    user can suspend it (^Z), replace the temporary file by a hard link to
    any file, resume the editor in the foreground, quit it without saving
    the file, and let chpass process the file for further operations.
    
      At this point, chpass will open the file (with root permissions
    since it is setuid-root), read it line by line and for each of them:
      - if it is longer than 2048 bytes, abort the reading
      - if it begins by '#', ignore it
      - else check the validity of the line
    Many conditions have to be respected to make a line valid, I will not
    list them here, they are too many. If the line is valid, chpass
    processes the next one. Else, if it is invalid and if it begins by
    "shell:" (whatever the case is) and if the rest of the line contains
    only printable characters (according to isprint(3)) and if none of
    them is ':' or ' ', the rest of the line is displayed in an error
    message. Here is a concrete example, create a file as root:
    
    	# echo "shell: secret_data" >/tmp/sec
    	# chmod 600 /tmp/sec
    
    Then run chpass under ordinary user privileges (lets say that the
    temporary filename you are editing is ``/var/tmp/pw.Loi22925''):
    
    	$ chpass				# ^Z in the editor
    	[1]+  Stopped                 chpass
    	$ rm /var/tmp/pw.Loi22925
    	$ ln /tmp/sec /var/tmp/pw.Loi22925
    	$ fg					# then quit the editor
    	chpass
    	chpass: secret_data: non-standard shell
    	        ^^^^^^^^^^^
    The string "secret_data" is contained in a file owned by root and
    readable only by root, but is displayed in this error message.
    
    FreeBSD and NetBSD implementations of chpass have been checked. They
    are not vulnerable since the temporary file is created in the
    directory ``/etc''.
    
    
    --oOo-- 3. Solution
    
      OpenBSD maintainers have been contacted on 2003-02-02 about this
    issue. The same day, a fix has been committed to the cvs (see the
    attached file ``asa-0001.openbsd-chpass.cvs-diff'').
    
      The new code solves the problem by requiring that the link count
    be one.
    
    
    --oOo-- 4. Conclusion
    
      A fix has been applied to OpenBSD-current. The attached file
    ``asa-0001.openbsd-chpass.cvs-diff'' contains the related cvs diff.
    
    
    --oOo-- 5. References
    
    [1] OpenBSD
        http://www.openbsd.org
    
    --oOo-- 6. Attached files
    
    The following file is also available at:
    http://www.epita.fr/~bevand_m/asa/asa-0001.openbsd-chpass.cvs-diff
    
    ---8<-------------- asa-0001.openbsd-chpass.cvs-diff -----------------
    Index: edit.c
    ===================================================================
    RCS file: /cvs/src/usr.bin/chpass/edit.c,v
    retrieving revision 1.23
    diff -u -r1.23 edit.c
    --- edit.c	31 Jul 2002 22:08:42 -0000	1.23
    +++ edit.c	2 Feb 2003 18:34:02 -0000
    @@ -48,6 +48,7 @@
     #include <ctype.h>
     #include <err.h>
     #include <errno.h>
    +#include <fcntl.h>
     #include <paths.h>
     #include <pwd.h>
     #include <stdio.h>
    @@ -152,12 +153,14 @@
     	char *p, *q;
     	ENTRY *ep;
     	FILE *fp;
    +	int fd;
     
    -	if (!(fp = fopen(tempname, "r")))
    +	if ((fd = open(tempname, O_RDONLY|O_NOFOLLOW)) == -1 ||
    +	    (fp = fdopen(fd, "r")) == NULL)
     		pw_error(tempname, 1, 1);
    -	if (fstat(fileno(fp), &sb))
    +	if (fstat(fd, &sb))
     		pw_error(tempname, 1, 1);
    -	if (sb.st_size == 0) {
    +	if (sb.st_size == 0 || sb.st_nlink != 1) {
     		warnx("corrupted temporary file");
     		goto bad;
     	}
    
    ---8<-------------- asa-0001.openbsd-chpass.cvs-diff -----------------
    
    -- 
    Marc Bevand                          http://www.epita.fr/~bevand_m
    Computer Science School EPITA - System, Network and Security Dept.
    



    This archive was generated by hypermail 2b30 : Mon Feb 03 2003 - 09:28:36 PST