COMMAND

    tkserv

SYSTEMS AFFECTED

    IRCd's tkserv

PROBLEM

    Paul Starzetz  found following.   There are  3 major  bugs in  the
    current IRCd  distribution (as  used on  the IRCnet  for example).
    The  included  service  daemon  'tkserv'  (tkserv.c v1.3.0 and all
    previous versions) suffers from:
        a) remote exploitable buffer overflow while querying tklines
        b) memory leck due to strdup'ing a string and not freeing  the
           mem
        c) format string bug while reading the ircd's config file

    a) There  is an  buffer overflow  in the  'void squery_tkline(char
       **args)' from tkserv.c. The bad part is (*):

           /* User wants to add tkline(s). */
            if (lifetime > 0)
            {
                passwd  = args[4];
                pattern = args[6];
        
        (*)     strcpy(reason, args[7]);
        
                i = 8;
        
                /* I know... */
                while(args[i] && *args[i])
                {
                    strncat(reason, " ", TKS_MAXKILLREASON - strlen(reason) - 1);
                    strncat(reason, args[i], TKS_MAXKILLREASON - strlen(reason) - 1);
                    i++;
                }

       where  reason  is  defined  to  be  a  static char buffer 'char
       reason[TKS_MAXKILLREASON]' and TKS_MAXKILLREASON is defined  to
       be only 128  characters.  Sending  an carefully crafted  tkline
       squery to vulnerable tkserv may result in remote code execution
       and  further  compromise.   Indeed  after  looking at a running
       tkserv in gdb, Paul found that exploitation of this flaw should
       be very easy.  There are only few conditions to meet, e.g.  the
       *args[i] part...

       We also need to meet the condition 'must_be_opered()' which  is
       checked before the vulnerable code is entered by tkserv.   This
       occurs, if  in the  tkserv.access file  there is  at least  one
       access line _not_ containing "!" as the first character,  which
       means that the  corresponding user@host pair  do _not_ need  to
       have OPER priviledges prior to use tkserv.  Or in other  words,
       requesting at least one user@host pair in tkserv.access to have
       OPER  priviledges  prior  to  using  tkserv  results  in remote
       buffer overflow vulnerability.

       Of  course,  having  a  matching  user@host pair, but no tkserv
       access (which is not so  uncommon, believe me.. there are  some
       configuration pitfalls  concerning the  user@host lines,  which
       Paul don't want to  reveal, the vulnerability can  be exploited
       too.

       So overflowing 'reason' results  in overwriting saved EIP  with
       well known consequences.

       One needs at  least one _non_  OPERED line in  tkserv.access in
       order to be vulnerable to the mentioned buffer overflow attack.

    b) The bad part is (**):

        int must_be_opered()
        {
            FILE *fp;
        
            /* if the access file exists, check for auth */
            if ((fp = fopen(TKSERV_ACCESSFILE, "r")) != NULL)
            {
                char buffer[TKS_MAXBUFFER];
                char *access_uh, *token, *uh;
        
                while (fgets(buffer, TKS_MAXBUFFER, fp))
                {
                    uh    = (char *) (strchr(nuh, '!') + 1);
                    token = (char *) strtok(buffer, " ");
        
                    if (token)
	            {
        (**)              access_uh  = (char *) strdup(token);
	            }

       the pointer  returned by  strdup is  never a  subject a  free()
       call.   So  stressing  the  tkserv  with  many unauthorized (!)
       squery's results  in excessive  memory usage  in effectively in
       denying the  service and  maybe other  services running  on the
       vulnerable box.

    c) While  the  tkserv  parses  the  ircd.conf  file,  e.g.   after
       requesting  a  new  k-line  (the  original  ircd.conf  is  read
       line-by-line and  the modified  copy written  to ircd.conf.tmp,
       which is copied to ircd.conf after tkserv has finished  reading
       the original config file) there is a vulnerable call to fprintf
       (***):

        int check_tklines(char *host, char *user, int lifetime)
        {
            FILE *iconf, *iconf_tmp;
        
            if ((iconf = fopen(CPATH, "r")) && (iconf_tmp = fopen(TKSERV_IRCD_CONFIG_TMP, "w")))
            {
                int count = 0, found = 0;
                time_t now;
                char buffer[TKS_MAXBUFFER];
                char buf_tmp[TKS_MAXBUFFER];
        
                /* just in case... */
                chmod(TKSERV_IRCD_CONFIG_TMP, S_IRUSR | S_IWRITE);
        
                now = time(NULL);
        
                while (fgets(buffer, TKS_MAXBUFFER, iconf))
                {
                    if ((*buffer != 'K') || (!strstr(buffer, "tkserv")))
	            {
        (***)             fprintf(iconf_tmp, buffer);
	            }

       the original ircd.conf is fprint'ed line by line to a temporary
       copy, so if  one can include  some format conversion  operators
       there, the code  will fail (hm,  what about /timer1234  99999 5
       /msg someoper hey  moron... ok, we  know, with current  BIND it
       wouldn't work...).  This should not be exploitable in the wild.

SOLUTION

    See discussion.   Do not  request opered  access to  your  tkserv.
    Update as soon as possible.  This is NOT current IRCnet IRCD, that
    is vulnerable.   All files in  contrib/ directory are  not part of
    IRCD daemon, they are related to it.