Date: Mon, 13 Jul 1998 04:22:15 -0400
From: Richard Thomas <[email protected]>
To: [email protected]Subject: Slackware Shadow Insecurity
Discovered by Ted Hickman:
Recently I noticed something rather "insecure" about the slackware 3.4
/bin/login (and probably other versions). If the /etc/group file does not
exist, any user who logs into the system is given uid 0 gid 0.
buglord login: meek
Password:
initgroups: No such file or directory
Linux 2.0.34.
Last login: Fri Jul 10 20:56:17 on tty6.
You have mail.
buglord:~# id
uid=0(root) gid=0
The following is recorded in the syslog:
Jul 10 22:28:42 buglord login[25795]: initgroups failed for user `meek`:
No such file or directory
Analysis by Richard Thomas:
An examination of shadow-971001 shows the following in libmisc/setugid.c:
/*
* setup_uid_gid() performs the following steps -
*
* set the supplementary group IDs
* optionally call specified function which may add more groups
* set the group ID to the value from the password file entry
* set the user ID to the value from the password file entry
*
* Returns 0 on success, or -1 on failure.
*/
int
setup_uid_gid(info, is_console)
const struct passwd *info;
int is_console;
{
#ifdef HAVE_INITGROUPS
/*
* For systems which support multiple concurrent groups, go get
* the group set from the /etc/group file.
*/
if (initgroups (info->pw_name, info->pw_gid) == -1) {
perror("initgroups");
SYSLOG((LOG_ERR, "initgroups failed for user `%s': %m\n",
info->pw_name));
closelog();
return -1;
}
[snip]
And src/login.c line 960:
setup_uid_gid(&pwent, is_console);
Does this look bad to anyone else? The call to setup_uid_gid() in login.c
does no checking of the return value. If initgroups cannot open /etc/group,
the setup_uid_gid() function returns before it gets around to the setgid()
and setuid() calls (hence the uid and gid are both still 0). This threw me
off for quite some time because I thought setup_uid_gid() was being called
from the setup() function in libmisc/setup.c, which DOES check the return
value and exits if there is a problem. I make no special claims to know
what is happening in shadow, but it appears that they decided to do the
calls in setup() individually, directly in login.c. Seems to me that if
setup_uid_gid is nice enough to return the success or failure status, the
least we could do is check it (ESPECIALLY since this is also the status of
the setgid and setuid calls!). Why do they still include the setup()
function if its not used? Beats me.
So whats the fix? Well first of all, change src/login.c to:
if (setup_uid_gid(&pwent, is_console))
exit(1);
If we wanted to be fancy we could continue to login even if initgroups()
fails (most likely you don't "need" those extra groups to get into the
system and fix it), but we gotta save something for the shadow authors. =)
How does this become a security hole? Well if you can find a way to delete
the /etc/group file things could become rather messy. Finding a way to do
that is left as an exercise for the reader (don't feel too bad I couldn't
find one off the top of my head either). Sorry kids, nothing you can cut
and paste to become a "pH34Rs0m3 hAx0r" today.
Some extra tidbits:
This does not affect redhat
The file has to actually be non-existent (chmod 000 don't cut it).
This seems to be a problem with all modern shadows, including the one
in slackware 3.5 (980529).
Shameless Plug:
Visit http://shell.sy.net for the best shells available this side of heaven.
- Ted Hickman <[email protected]>
- Richard Thomas <[email protected]>