CVE:CVE-2006-5815
CNNVD:CNNVD-200611-144
ProFTPD是一款开放源代码FTP服务程序。
ProFTPD的src/support.c文件中的sreplace()函数在处理特制请求时存在单字节溢出漏洞。漏洞分析代码如下：
"""
char *sreplace(pool *p, char *s, ...) {
  va_list args;
  char *m,*r,*src = s,*cp;
  char **mptr,**rptr;
  char *marr[33],*rarr[33];
  char buf[PR_TUNABLE_PATH_MAX] = {'\0'}, *pbuf = NULL;
  size_t mlen = 0, rlen = 0, blen;
  int dyn = TRUE;
  cp = buf;
  *cp = '\0';
  memset(marr, '\0', sizeof(marr));
  memset(rarr, '\0', sizeof(rarr));
  blen = strlen(src) + 1;
  va_start(args, s);
  while ((m = va_arg(args, char *)) != NULL  & & mlen < sizeof(marr)-1) {
    char *tmp = NULL;
    size_t count = 0;
    if ((r = va_arg(args, char *)) == NULL)
      break;
    /* Increase the length of the needed buffer by the difference between
     * the given match and replacement strings, multiplied by the number
     * of times the match string occurs in the source string.
     */
    tmp = strstr(s, m);
    while (tmp) {
      pr_signals_handle();
      count++;
      /* Be sure to increment the pointer returned by strstr(3), to
       * advance past the beginning of the substring for which we are
       * looking.  Otherwise, we just loop endlessly, seeing the same
       * value for tmp over and over.
       */
      tmp += strlen(m);
      tmp = strstr(tmp, m);
    }
    /* We are only concerned about match/replacement strings that actually
     * occur in the given string.
     */
    if (count) {
      blen += count * (strlen(r) - strlen(m));
      marr[mlen] = m;
      rarr[mlen++] = r;
    }
  }
  va_end(args);
  /* Try to handle large buffer situations (i.e. escaping of
 * PR_TUNABLE_PATH_MAX
   * (>2048) correctly, but do not allow very big buffer sizes, that may
   * be dangerous (BUFSIZ may be defined in stdio.h) in some library
   * functions.
   */
#ifndef BUFSIZ
# define BUFSIZ 8192
#endif
  if (blen < BUFSIZ)
[1]  cp = pbuf = (char *) pcalloc(p, ++blen);  if (!pbuf) {
[2]  cp = pbuf = buf;
    dyn = FALSE;
    blen = sizeof(buf);
  }
  while (*src) {
    for (mptr = marr, rptr = rarr; *mptr; mptr++, rptr++) {
      mlen = strlen(*mptr);
      rlen = strlen(*rptr);
      if (strncmp(src, *mptr, mlen) == 0) {
[3]     sstrncpy(cp, *rptr, blen - strlen(pbuf));
        if (((cp + rlen) - pbuf + 1) > blen) {
          pr_log_pri(PR_LOG_ERR,
                  "WARNING: attempt to overflow internal ProFTPD buffers");
          cp = pbuf + blen - 1;
          goto done;
        } else {
          cp += rlen;
        }
        src += mlen;
        break;
      }
    }
    if (!*mptr) {
[4]    if ((cp - pbuf + 1) > blen) {
         pr_log_pri(PR_LOG_ERR,
                "WARNING: attempt to overflow internal ProFTPD buffers");
         cp = pbuf + blen - 1;
      }
      *cp++ = *src++;
    }
  }
 done:
  *cp = '\0';
  if (dyn)
    return pbuf;
  return pstrdup(p, buf);
}
"""
blen的值是可控的，如果将其设置为小于BUFSIZ的值的话(见[1])就可以触发堆溢出，否则可以触发栈溢出(见[2])。 
由于在[4]行的错误计算，攻击者可以控制pbuf最后的空字节，这样strlen(pbuf)就会大于blen。由于第三个参数为负数时sstrncpy函数仍可运行，因此[3]行的代码会使用攻击者的数据覆盖pbuf缓冲区。
目前已知至少有两种攻击方式：
1. MKD命令
2. pr_display_file
solution:Upgrade proftpd_project proftpd to a higher version than 1.3.0,and avoid the version (,1.3.0]