CFINGERD root security hole

From: John Goerzen (jgoerzenat_private)
Date: Thu Jul 23 1998 - 21:48:21 PDT

  • Next message: Roscinante: "Re: CFINGERD root security hole"

    SUMMARY
    -------
    
    I have found out that cfingerd 1.3.2 contains a security hole that
    could lead to easy root compromise for any user that has an account on
    the local machine, but only if ALLOW_EXECUTION is set in
    /etc/cfingerd/cfingerd.conf.  By default, this option is DISABLED in
    Debian GNU/Linux.
    
    DETAILS
    -------
    
    The ALLOW_EXECUTION option permits any user on the system to execute a
    program when their username is fingered.  cfingerd needs to run as
    root but doesn't properly throw away root permissions when it starts
    up the user's script.
    
    When it is told to invoke /usr/bin/id from a user's script, it
    produces:
    
    uid=0(root) gid=0(root) euid=65534(nobody) groups=0(root)
    
    EXPLOIT
    -------
    
    Have it exec this:
    
    void main(void) {
      setreuid(0, 0);
      system("/usr/bin/id");
    }
    
    Of course, system can exec any more devious command you chose -- ie,
    marking a shell setuid root, etc.  (Can also be done with C calls.)
    No, I am NOT going to tell you how to make a setuid shell.  If you
    don't know, you shouldn't be reading this.
    
    To test the exploit, put something like this in ~/.project:
    
    $exec /home/jgoerzen/test
    
    and set the ALLOW_EXECUTION to be enabled.  This will give root for
    everything.
    
    Additionally, as you can tell, it fails to relenquish group
    permissions at all.  After applying the below fix, the new output is:
    
    uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
    
    Much better!
    
    FIX
    ---
    
    Debian GNU/Linux comes with cfingerd, but in its default
    configuration, it is safe.  For maximum security, please install the
    upgraded packages anyway.  cfingerd greater than or equal to
    1.3.2-11.0 will have the fix.  I have uploaded the fixed packages to
    Incoming; before they propogate to the mirrors, you may find them at
    http://happy.cs.twsu.edu/~jgoerzen/cfingerd/ along with the new
    sources.
    
    374531a02be81021ca9a12059a3c4515  cfingerd_1.3.2-11.0.diff.gz
    f8819601f85115c063d5cace970554d6  cfingerd_1.3.2-11.0.dsc
    2f943297e0b73fe32345e932f11b6a58  cfingerd_1.3.2-11.0_i386.changes
    b9df424d723da39aa9c0067171822d56  cfingerd_1.3.2-11.0_i386.deb
    4a3403d2519fea6b829bdeda9026c8ad  cfingerd_1.3.2-11.0_i386.upload
    
    Those of you not using Debian may apply the following diff.
    
    --- cfingerd-1.3.2.orig/src/privs.h
    +++ cfingerd-1.3.2/src/privs.h
    @@ -29,6 +29,7 @@
     #ifndef _USE_BSD
     #define _USE_BSD 1
     #include <unistd.h>
    +#include <grp.h>
     #undef _USE_BSD
     #else
     #include <unistd.h>
    @@ -72,14 +73,20 @@
     extern
     #endif
     gid_t real_gid, effective_gid;
    +#ifndef MAIN
    +extern
    +#endif
    +gid_t grouplist[1];
    
     #define RELINQUISH_PRIVS { \
                                  real_uid = getuid(); \
                                  effective_uid = NOBODY_UID; \
                                  real_gid = getgid(); \
                                  effective_gid = NOBODY_GID; \
    -                             setregid(real_gid, effective_gid); \
    -                             setreuid(real_uid, effective_uid); \
    +                             grouplist[0] = effective_gid; \
    +                             setgroups(1, grouplist); \
    +                             setregid(effective_gid, effective_gid); \
    +                             setreuid(effective_uid, effective_uid); \
                              }
    
     #define PRIV_ROOT_START {\
    @@ -87,25 +94,29 @@
                                setregid(effective_gid, real_gid); \
    
     #define PRIV_ROOT_END \
    -                           setregid(real_gid, effective_gid); \
    -                           setreuid(real_uid, effective_uid); \
    +                           setregid(effective_gid, effective_gid); \
    +                           setreuid(effective_uid, effective_uid); \
                            }
    
     #define USER_PRIVS(a,b) {\
    -                       setreuid(real_uid, 0); \
    -                       setregid(real_gid, 0); \
    +                       setreuid(0, 0); \
    +                       setregid(0, 0); \
                            effective_uid = (a); \
                            effective_gid = (b); \
    -                       setregid(real_gid, effective_gid); \
    -                       setreuid(real_uid, effective_uid); \
    +                       grouplist[0] = effective_gid; \
    +                       setgroups(1, grouplist); \
    +                       setregid(effective_gid, effective_gid); \
    +                       setreuid(effective_uid, effective_uid); \
                        }
    
     #define NOBODY_PRIVS \
    -                       setreuid(real_uid, 0); \
    -                       setregid(real_gid, 0); \
    +                       setreuid(0, 0); \
    +                       setregid(0, 0); \
                            effective_uid = NOBODY_UID; \
                            effective_gid = NOBODY_GID; \
    -                       setreuid(real_uid, effective_uid); \
    -                       setregid(real_gid, effective_gid);
    +                       grouplist[0] = NOBODY_GID; \
    +                       setgroups(1, grouplist); \
    +                       setgid(NOBODY_GID); \
    +                       setuid(NOBODY_UID);
    
     #endif  /* _PRIVS_H_ */
    
    ADDITIONAL CREDIT goes to Jakob Bohm Jensen <jbjat_private>.  He
    reported some other things (not these in particular) that didn't turn
    out to be a hole but lead me to examine the code carefully.
    
    --
    John Goerzen   Linux, Unix consulting & programming   jgoerzenat_private |
    Developer, Debian GNU/Linux (Free powerful OS upgrade)       www.debian.org |
    ----------------------------------------------------------------------------+
    Visit the Air Capital Linux Users Group on the web at http://www.aclug.org
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:07:52 PDT