COMMAND

    proftpd

SYSTEMS AFFECTED

    proftpd 1.2.0 <= pre10

PROBLEM

    Following is based on Security Advisory by lamagra.

    Bug1:
    =====
    void set_proc_title(char *fmt,...) in src/main.c

        memset(statbuf, 0, sizeof(statbuf));
        vsnprintf(statbuf, sizeof(statbuf), fmt, msg);
        
        #ifdef HAVE_SETPROCTITLE
	        setproctitle(statbuf);
        #endif /* HAVE_SETPROCTITLE */

    setproctitle,   defined   setproctitle(char   *fmt,...);,    calls
    vsnprintf().   This  makes  it  vulnerable  for formatattacks.  By
    carefully outlining  the attackbuffer  it's possible  to gain root
    priviledges.

    Bug2:
    =====
    MODRET pam_auth(cmd_rec *cmd) in modules/mod_pam.c:

        /* Allocate our entries...we don't free this because PAM does this for us.
         */
        pam_user = malloc(strlen(cmd->argv[0]) + 1);
        if(pam_user == (char *)0)
          return pam_return_type ? ERROR(cmd) : DECLINED(cmd);
        sstrncpy(pam_user, cmd->argv[0], strlen(cmd->argv[0]) + 1);
        
        pam_pass = malloc(strlen(cmd->argv[1]) + 1);
        if(pam_pass == (char *)0)
          return pam_return_type ? ERROR(cmd) : DECLINED(cmd);
        sstrncpy(pam_pass, cmd->argv[1], strlen(cmd->argv[1]) + 1);

    PAM doesn't do it for you though. Which leaves a nice  memoryleak.
    But since USER/PASS is limited to 3 tries and user changing  isn't
    supported.   This  can't  be  used  as  a Denial of service attack
    against  proftpd,  unless  the  administartor  sets  a   different
    (higher) limit.

    Bug3:
    =====
    void  logformat(char   *nickname,  char   *fmts)  doesn't    check
    boundaries on  it's local  variable 'format'.  As a  result custom
    logformats  could  overflow  the  buffer.   Just  a  really  small
    thingie. Could cause some problems though.

    Bug4:
    =====
    int  dolist(cmd_rec  *cmd,  const  char  *opt,  int clearflags) in
    modules/mod_ls.c

     char   pbuffer[MAXPATHLEN];

     if(*arg == '~') {
        struct passwd *pw;
        int i;
        const char *p;

        i = 0;
        p = arg;
        p++;

        while(*p && *p != '/')
          pbuffer[i++] = *p++;
        pbuffer[i] = '\0';

    This  function  gets  called  by  cmd_stat,  with  'arg' being the
    argument  of  STAT.   This  looks  really  bad and ugly. But isn't
    really exploitable since the input buffer is only 1024 bytes.  But
    it's still insecure programming.

SOLUTION

    Fix 1: use setproctitle("%s",statbuf);

        --- src/main.c  2000/01/13 01:47:02     1.3
        +++ src/main.c  2000/04/29 19:22:18
        @@ -377,7 +377,7 @@
           vsnprintf(statbuf, sizeof(statbuf), fmt, msg);
        
         #ifdef HAVE_SETPROCTITLE
        -  setproctitle(statbuf);
        +  setproctitle("%s", statbuf);
         #endif /* HAVE_SETPROCTITLE */
        
           va_end(msg);

    Note that this is a problem  only if you have a setproctitle()  in
    libc (or libutil).  Linux does not (glibc 2.x).

    Fix 2: pstrdup() or just use cmd->argv[0] and cmd->argv[1].

    ProFTPD 1.20 fixed all this.