|
Neohapsis is currently accepting applications for employment. For more information, please visit our website www.neohapsis.com or email hr@neohapsis.com |
Subject: Re: Demo patch - run telnetd as non-root and chroot()'ed
From: hayward
slothmud.orgDate: Thu Jul 20 2000 - 23:13:39 CDT
- Next message: Chris Evans: "Re: Demo patch - run telnetd as non-root and chroot()'ed"
- Previous message: hayward
slothmud.org: "Re: Demo patch - run telnetd as non-root and chroot()'ed"
- In reply to: Chris Evans: "Demo patch - run telnetd as non-root and chroot()'ed"
- Next in thread: Goense, Jacob: "RE: Demo patch - run telnetd as non-root and chroot()'ed"
- Reply: hayward
slothmud.org: "Re: Demo patch - run telnetd as non-root and chroot()'ed"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Oh - and to answer your question - Yes, send that patch in!
-- BrianOn Thu, 20 Jul 2000, Chris Evans wrote:
> >Hi, > >Well it didn't take long. Patch is however a bit raw and rough around the >edges. It's by no means a finished piece of work; just something I threw >together in a couple of hours. > >However, it runs telnetd as nobody and in a chroot() jail. The jail/priv >drop occurs before _any_ data is read from the untrusted network or local >pty. > >All normal telnetd functionality still works, including /etc/issue, >TERM/USER env. var passing, etc. #define AUTHENTICATE and #define ENCRYPT >are almost certainly broken. > >There is just one difference, though - any future hole in telnetd suddenly >becomes not very useful to attackers. A non-root shell chroot()'ed to an >area[1] without any nice files to open nor, more importantly, any setuid >executables to subvert. > >I really think this is the direction Linux security needs to go in. After >all, a thorough audit may still miss holes, so why not make them >moderately irrelevant? > >If sufficient interest/enthusiasm is generated by this, I'm sure I can >clean it up and get it accepted into the offical netkit. > >Comments? > >Cheers >Chris > >P.S. Note that the majority of daemons can be run with non-root and >chroot(), even if they sometimes need a pipe to a distrusting privileged >helper. And if they were, we would be in a _much_ better security >situation. > >[1] OK - so /tmp is a lousy chroot() destination. Maybe FSSTND needs >/var/empty or something. > > >diff -rubB telnetd.old/ext.h telnetd/ext.h >--- telnetd.old/ext.h Sun Dec 12 14:59:44 1999 >+++ telnetd/ext.h Tue Jul 18 07:47:50 2000 >
-135,9 +135,11
> void sendbrk(void); > void sendsusp(void); > void set_termbuf(void); >-void start_login(const char *, int, const char *); >+/* void start_login(const char *, int, const char *); */ >+void start_login(const char* host, int pipefd); > void start_slc(int); >-void startslave(const char *host, int autologin, char *autoname); >+/* void startslave(const char *host, int autologin, char *autoname); */ >+void startslave(const char* host, int pipefd); > > #if defined(AUTHENTICATE) > void start_slave(char *); >diff -rubB telnetd.old/state.c telnetd/state.c >--- telnetd.old/state.c Sun Jul 16 09:35:00 2000 >+++ telnetd/state.c Tue Jul 18 06:10:30 2000 >
-1340,7 +1340,6
> } > > #ifdef LINEMODE >-#error problems! > if (his_want_state_is_will(TELOPT_LINEMODE)) { > unsigned char *cp, *cpe; > int len; >diff -rubB telnetd.old/sys_term.c telnetd/sys_term.c >--- telnetd.old/sys_term.c Sun Dec 12 14:59:45 1999 >+++ telnetd/sys_term.c Tue Jul 18 07:48:24 2000 >
-557,7 +557,8
> */ > > /* ARGSUSED */ >-void startslave(const char *host, int autologin, char *autoname) { >+/* void startslave(const char *host, int autologin, char *autoname) { */ >+void startslave(const char* host, int pipefd) { > int i; > > #if defined(AUTHENTICATE) >
-579,7 +580,8
> /* child */ > signal(SIGHUP,SIG_IGN); > getptyslave(); >- start_login(host, autologin, autoname); >+ /* start_login(host, autologin, autoname); */ >+ start_login(host, pipefd); > /*NOTREACHED*/ > } > } >
-611,10 +613,46
> static void addarg(struct argv_stuff *, const char *); > static void initarg(struct argv_stuff *); > >-void start_login(const char *host, int autologin, const char *name) { >+/* void start_login(const char *host, int autologin, const char *name) { */ >+void start_login(const char* host, int pipefd) { > struct argv_stuff avs; > char *const *argvfoo; >- (void)autologin; >+ /* (void)autologin; */ >+ >+ /* Currently 5 env. vars allowed */ >+ char envbuf[256*5]; >+ int todo = sizeof(envbuf); >+ char* ptr = envbuf; >+ >+ /* {ce} - Before we consider launching login, we need to nab any >+ * import environment variables the unprivileged client wants to >+ * send >+ */ >+ while(todo > 0) >+ { >+ int got = read(pipefd, ptr, todo); >+ if (got < 0 && errno != EAGAIN) >+ { >+ exit(1); >+ } >+ else if (got <= 0) >+ { >+ sleep(1); >+ } >+ else >+ { >+ todo -= got; >+ ptr += got; >+ } >+ } >+ >+ envbuf[256-1] = envbuf[2*256-1] = envbuf[3*256-1] = >+ envbuf[4*256-1] = envbuf[5*256-1] = '\0'; >+ if (envbuf[256*0]) setenv("TERM", envbuf, 1); >+ if (envbuf[256*1]) setenv("DISPLAY", envbuf+256, 1); >+ if (envbuf[256*2]) setenv("USER", envbuf+256*2, 1); >+ if (envbuf[256*3]) setenv("LOGNAME", envbuf+256*3, 1); >+ if (envbuf[256*4]) setenv("POSIXLY_CORRECT", envbuf+256*4, 1); > > initarg(&avs); > >
-651,11 +689,11
> */ > if (require_SecurID) addarg(&avs, "-s"); > #endif >+#if defined (AUTHENTICATE) > if (*name=='-') { > syslog(LOG_ERR, "Attempt to login with an option!"); > name = ""; > } >-#if defined (AUTHENTICATE) > if (auth_level >= 0 && autologin == AUTH_VALID) { > # if !defined(NO_LOGIN_F) > addarg(&avs, "-f"); >
-665,6 +703,8
> else > #endif > { >+/* {ce} - Arbitrary passing of an argv[] to login isn't smart */ >+#ifndef EXTRA_SECURITY > if (getenv("USER")) { > addarg(&avs, getenv("USER")); > if (*getenv("USER") == '-') { >
-673,6 +713,7
> exit(1); > } > } >+#endif > } > } > closelog(); >Binary files telnetd.old/sys_term.o and telnetd/sys_term.o differ >Binary files telnetd.old/telnetd and telnetd/telnetd differ >diff -rubB telnetd.old/telnetd.c telnetd/telnetd.c >--- telnetd.old/telnetd.c Tue Dec 14 00:43:31 1999 >+++ telnetd/telnetd.c Wed Jul 19 06:00:18 2000 >
-31,6 +31,10
> * SUCH DAMAGE. > */ > >+#if defined(AUTHENTICATE) || defined(ENCRYPT) >+#error cevans - AUTHENTICATE and ENCRYPT probably broken >+#endif >+ > char copyright[] = > "
(#) Copyright (c) 1989 Regents of the University of California.\n" > "All rights reserved.\n"; >
-49,6 +53,10
> /* #include <netinet/ip.h> */ /* Don't think this is used at all here */ > #include <arpa/inet.h> > #include <assert.h> >+ >+#include <pwd.h> >+#include <grp.h> >+ > #include "telnetd.h" > #include "pathnames.h" > #include "setproctitle.h" >
-80,6 +88,9
> char *loginprg = _PATH_LOGIN; > char *progname; > >+/* fd for /etc/issue; need to open before we chroot()! */ >+int issue_fd = -1; >+ > extern void usage(void); > > int >
-306,7 +317,8
> /* NOT REACHED */ > } > >- openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON); >+ /* {ce} - since we're going to run chroot()'ed, open log now */ >+ openlog("telnetd", LOG_PID | LOG_NDELAY, LOG_DAEMON); > fromlen = sizeof (from); > if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { > fprintf(stderr, "%s: ", progname); >
-607,8 +619,9
> { > const char *host; > struct hostent *hp; >- int level; >+ int level = -1; > char user_name[256]; >+ int pipefds[2]; > > /* > * Find an available pty to use. >
-618,11 +631,16
> fatal(net, "All network ports in use"); > > /* get name of connected client */ >+ /* {ce} - Rationale: it's not a cunning plan to pass semi-arbitrary >+ * data to /bin/login in argv[] >+ */ >+#ifndef EXTRA_SECURITY > hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr), > who->sin_family); > if (hp) > host = hp->h_name; > else >+#endif > host = inet_ntoa(who->sin_addr); > > /* >
-634,6 +652,9
> strncpy(remote_host_name, host, sizeof(remote_host_name)-1); > remote_host_name[sizeof(remote_host_name)-1] = 0; > >+ /* {ce} - XXX - need to do the same for user_name if/when >+ * I re-enable it >+ */ > /* Disallow funnies. */ > for (i=0; remote_host_name[i]; i++) { > if (remote_host_name[i]<=32 || remote_host_name[i]>126) >
-642,6 +663,8
> } > host = remote_host_name; > >+ setenv("REMOTEHOST", host, 0); >+ > /* Get local host name */ > { > struct hostent *h; >
-662,21 +685,81
> * get terminal type. > */ > *user_name = 0; >+ >+ /* {ce} - Make a pipe to communicate from no-priv protocol parser >+ * to privileged /bin/login launching child. >+ * We need the communication to pass environment variables which >+ * /bin/login needs to inherit >+ */ >+ pipe(pipefds); >+ >+ /* Start the login slave (needs privs) */ >+ /* startslave(host, level, user_name); */ >+ startslave(host, pipefds[0]); >+ >+ /* {ce} - Before we chroot(), open /etc/issue.net */ >+ issue_fd = open(ISSUE_FILE, O_RDONLY); >+ >+ /* {ce} - Lose privs, and chroot(), before exposing protocol */ >+ { >+ struct passwd* pw; >+ pw = getpwnam("telnetd"); >+ if (pw == NULL) >+ { >+ /* Bah */ >+ pw = getpwnam("nobody"); >+ } >+ if (pw != NULL) >+ { >+ /* Before we drop root */ >+ /* XXX - poor. Need /var/empty in FSSTND */ >+ chdir("/tmp"); >+ chroot("."); >+ >+ initgroups(pw->pw_name, pw->pw_gid); >+ setgid(pw->pw_gid); >+ setuid(pw->pw_uid); >+ } >+ } >+ >+ /* {ce} - This exposes arbitrary telnet protocol to malicious >+ * clients => we need to drop privs/chroot() before here >+ */ > level = getterminaltype(user_name); > setenv("TERM", terminaltype ? terminaltype : "network", 1); > >+ /* {ce} - Now we need to transmit the environment to the slave - >+ * it needs that before it starts login, otherwise TERM, USER >+ * etc. do not work >+ */ >+ { >+ char envbuf[256*5]; >+ char* var; >+ >+ memset(envbuf, '\0', sizeof(envbuf)); >+ var = getenv("TERM"); >+ if (var && *var && strlen(var) < 256) >+ strcpy(envbuf, var); >+ var = getenv("DISPLAY"); >+ if (var && *var && strlen(var) < 256) >+ strcpy(envbuf+256*1, var); >+ var = getenv("USER"); >+ if (var && *var && strlen(var) < 256) >+ strcpy(envbuf+256*2, var); >+ var = getenv("LOGNAME"); >+ if (var && *var && strlen(var) < 256) >+ strcpy(envbuf+256*3, var); >+ var = getenv("POSIXLY_CORRECT"); >+ if (var && *var && strlen(var) < 256) >+ strcpy(envbuf+256*4, var); >+ >+ write(pipefds[1], envbuf, sizeof(envbuf)); >+ } >+ > /* TODO list stuff provided by Laszlo Vecsey <master
internexus.net> */ > >- /* >- * Set REMOTEHOST environment variable >- */ > setproctitle("%s", host); > setenv("REMOTEHOST", host, 0); >- >- /* >- * Start up the login process on the slave side of the terminal >- */ >- startslave(host, level, user_name); > > telnet(net, pty); /* begin server processing */ > >Binary files telnetd.old/telnetd.o and telnetd/telnetd.o differ >diff -rubB telnetd.old/utility.c telnetd/utility.c >--- telnetd.old/utility.c Sun Dec 12 14:59:45 1999 >+++ telnetd/utility.c Wed Jul 19 06:03:13 2000 >
-48,6 +48,9
> > #include "telnetd.h" > >+/* /etc/issue.net fd - opened earlier before we did chroot() */ >+extern int issue_fd; >+ > /* > * utility functions performing io related tasks > */ >
-506,7 +509,8
> FILE *fp; > int p, c; > >- if ((fp = fopen(ISSUE_FILE, "r")) == NULL) >+ if (issue_fd == -1 || >+ (fp = fdopen(issue_fd, "r")) == NULL) > break; > p = '\n'; > while ((c = fgetc(fp)) != EOF) { >Binary files telnetd.old/utility.o and telnetd/utility.o differ >
- Next message: Chris Evans: "Re: Demo patch - run telnetd as non-root and chroot()'ed"
- Previous message: hayward
slothmud.org: "Re: Demo patch - run telnetd as non-root and chroot()'ed"
- In reply to: Chris Evans: "Demo patch - run telnetd as non-root and chroot()'ed"
- Next in thread: Goense, Jacob: "RE: Demo patch - run telnetd as non-root and chroot()'ed"
- Reply: hayward
slothmud.org: "Re: Demo patch - run telnetd as non-root and chroot()'ed"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]