COMMAND

    thhtpd

SYSTEMS AFFECTED

    thttpd 2.04 (Suse 6.2 and 6.3 plus others)

PROBLEM

    D. J. Bernstein found following.   thttpd is a single-process  web
    server. According  to Netcraft,  it's used  on 1.82%  of all  HTTP
    servers, behind only Apache, IIS, Enterprise, and Rapidsite.   The
    current version is  thttpd 2.04; as  far as known  and in time  of
    writing, the comments below apply to all versions back to 1.90a.

    The thttpd web page says  that thttpd is simple, small,  portable,
    fast, and secure;  it ``goes to  great lengths to  protect the web
    server machine  against attacks  and breakins  from other sites.''
    Sounds good,  doesn't it?   Bernstein glanced  at the  thttpd 2.04
    source  code,   wondering  how   seriously  thttpd   parsed   HTTP
    If-Modified-Since  fields.    He   was  horrified   to  see   that
    tdate_parse() scans %[a-zA-Z] into a fixed-size stack buffer.   He
    tried running  thttpd on  a throwaway  account, and  feeding it an
    If-Modified-Since line  with 1300  x's. It  dumped core.   This is
    something that any attacker on the Internet could do to any thttpd
    server, taking down web service until thttpd is restarted.

    Presumably, at least on little-endian machines, a careful attacker
    can take over the thttpd server---i.e., take over web service, and
    anything else running as  ``nobody''---by overwriting only two  or
    three bytes of the return address.

SOLUTION

    Fortunately the fix is trivial.  The patch applied is below, and
    you can find the full tarchive at the usual place

        http://www.acme.com/software/thttpd/

    Patch:

    *** tdate_parse.c	1999/09/15 16:09:36	1.1
    --- tdate_parse.c	1999/11/10 01:16:39
    ***************
    *** 211,217 ****
          */

          /* DD-mth-YY HH:MM:SS GMT */
    !     if ( sscanf( cp, "%d-%[a-zA-Z]-%d %d:%d:%d GMT",
  		    &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
  		    &tm_sec ) == 6 &&
  	        scan_mon( str_mon, &tm_mon ) )
    --- 211,217 ----
          */

          /* DD-mth-YY HH:MM:SS GMT */
    !     if ( sscanf( cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
  		    &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
  		    &tm_sec ) == 6 &&
  	        scan_mon( str_mon, &tm_mon ) )
    ***************
    *** 225,231 ****
  	    }

          /* DD mth YY HH:MM:SS GMT */
    !     else if ( sscanf( cp, "%d %[a-zA-Z] %d %d:%d:%d GMT",
  		    &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
  		    &tm_sec) == 6 &&
  	        scan_mon( str_mon, &tm_mon ) )
    --- 225,231 ----
  	    }

          /* DD mth YY HH:MM:SS GMT */
    !     else if ( sscanf( cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
  		    &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
  		    &tm_sec) == 6 &&
  	        scan_mon( str_mon, &tm_mon ) )
    ***************
    *** 239,245 ****
  	    }

          /* HH:MM:SS GMT DD-mth-YY */
    !     else if ( sscanf( cp, "%d:%d:%d GMT %d-%[a-zA-Z]-%d",
  		    &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
  		    &tm_year ) == 6 &&
  	        scan_mon( str_mon, &tm_mon ) )
    --- 239,245 ----
  	    }

          /* HH:MM:SS GMT DD-mth-YY */
    !     else if ( sscanf( cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
  		    &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
  		    &tm_year ) == 6 &&
  	        scan_mon( str_mon, &tm_mon ) )
    ***************
    *** 253,259 ****
  	    }

          /* HH:MM:SS GMT DD mth YY */
    !     else if ( sscanf( cp, "%d:%d:%d GMT %d %[a-zA-Z] %d",
  		    &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
  		    &tm_year ) == 6 &&
  	        scan_mon( str_mon, &tm_mon ) )
    --- 253,259 ----
  	    }

          /* HH:MM:SS GMT DD mth YY */
    !     else if ( sscanf( cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
  		    &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
  		    &tm_year ) == 6 &&
  	        scan_mon( str_mon, &tm_mon ) )
    ***************
    *** 267,273 ****
  	    }

          /* wdy, DD-mth-YY HH:MM:SS GMT */
    !     else if ( sscanf( cp, "%[a-zA-Z], %d-%[a-zA-Z]-%d %d:%d:%d GMT",
  		    str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
  		    &tm_sec ) == 7 &&
  	        scan_wday( str_wday, &tm_wday ) &&
    --- 267,273 ----
  	    }

          /* wdy, DD-mth-YY HH:MM:SS GMT */
    !     else if ( sscanf( cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
  		    str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
  		    &tm_sec ) == 7 &&
  	        scan_wday( str_wday, &tm_wday ) &&
    ***************
    *** 283,289 ****
  	    }

          /* wdy, DD mth YY HH:MM:SS GMT */
    !     else if ( sscanf( cp, "%[a-zA-Z], %d %[a-zA-Z] %d %d:%d:%d GMT",
  		    str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
  		    &tm_sec ) == 7 &&
  	        scan_wday( str_wday, &tm_wday ) &&
    --- 283,289 ----
  	    }

          /* wdy, DD mth YY HH:MM:SS GMT */
    !     else if ( sscanf( cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
  		    str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
  		    &tm_sec ) == 7 &&
  	        scan_wday( str_wday, &tm_wday ) &&
    ***************
    *** 299,305 ****
  	    }

          /* wdy mth DD HH:MM:SS GMT YY */
    !     else if ( sscanf( cp, "%[a-zA-Z] %[a-zA-Z] %d %d:%d:%d GMT %d",
  		    str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
  		    &tm_year ) == 7 &&
  	        scan_wday( str_wday, &tm_wday ) &&
    --- 299,305 ----
  	    }

          /* wdy mth DD HH:MM:SS GMT YY */
    !     else if ( sscanf( cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
  		    str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
  		    &tm_year ) == 7 &&
  	        scan_wday( str_wday, &tm_wday ) &&

    Updated the package from SuSE FTP server:

        ftp://ftp.suse.com/pub/suse/i386/update/6.2/n1/thttpd-2.04-31.i386.rpm
        ftp://ftp.suse.com/pub/suse/i386/update/6.3/n1/thttpd-2.04-31.i386.rpm