Date: Sat, 13 Nov 1999 09:54:29 -0800 From: Blue Boar <BlueBoar@THIEVCO.COM> Subject: thttpd 2.04 stack overflow (VD#6) To: BUGTRAQ@SECURITYFOCUS.COM ------------------------------------------------------------------- Periodically, the moderator of of the vuln-dev mailing list will post summaries of issues discussed there to Bugtraq and possibly other relevant lists. This will usually happen when an issue has been resolved, or it appears that there will be no further discussion on vuln-dev. Each separate issue will be given it's own posting to facilitate referencing them separately, for discussion, forwarding, or appearance in vulnerability databases. To subscribe to vuln-dev, send an e-mail to listserv@securityfocus.com, with SUBSCRIBE VULN-DEV in the body of the message. A FAQ and archive can be found at www.securityfocus.com-->forums-->vuln-dev (click on these sections, the web pages are forms-based.) ------------------------------------------------------------------- Sorry to take so long getting this one out, especially after how quickly the author had a fix. Check out the times on the messages (My mail reader calculates those out to be 5:05 P.M. and 5:58 P.M., my time). I've been wiped out for a few days with a nasty case of strep throat. Anyway, I'm including the two messages in their entirety. If you run thttpd, you'll want to take immediate action. I commend the package author on his handling of this issue. No whining, no excuses, no attacking the person who found the holes, just a very timely fix. BB ------------------------------------------------------------------- Subject: thttpd 2.04 stack overflow Date: Wed, 10 Nov 1999 01:05:04 -0000 From: "D. J. Bernstein" <djb@CR.YP.TO> To: VULN-DEV@SECURITYFOCUS.COM 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 I know, 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? Today I glanced at the thttpd 2.04 source code, wondering how seriously thttpd parsed HTTP If-Modified-Since fields. I was horrified to see that tdate_parse() scans %[a-zA-Z] into a fixed-size stack buffer. I 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. But I haven't spent any more time looking at the code. Perhaps other people here would be interested in investigating thttpd's security in more detail. (Disclaimer: I'm writing my own HTTP server.) ---Dan ------------------------------------------------------------------- Subject: Re: thttpd 2.04 stack overflow Date: Tue, 9 Nov 1999 17:58:45 -0800 From: Jef Poskanzer <jef@ACME.COM> To: VULN-DEV@SECURITYFOCUS.COM >Today I glanced at the thttpd 2.04 source code, wondering how seriously >thttpd parsed HTTP If-Modified-Since fields. I was horrified to see that >tdate_parse() scans %[a-zA-Z] into a fixed-size stack buffer. You're right, that's pretty bad. Thanks for the note. Fortunately the fix is trivial, and I had a new version of thttpd ready to go, so I went ahead and released it. The patch I applied is below, and you can find the full tarchive at the usual place, http://www.acme.com/software/thttpd/ I was hoping to delay this release until I solve www.acme.com's current bandwidth problems, but this is urgent enough to require an immediate fix. By the way, this: >According to Netcraft, it's used >on 1.82% of all HTTP servers, behind only Apache, IIS, Enterprise, and >Rapidsite. is somewhat of an overstatement. There are actually only a hundred or so sites running thttpd. One of them is Demon Internet, a British company which serves over 100,000 domains on a single SGI box running their modified version of thttpd. --- Jef Jef Poskanzer jef@acme.com http://www.acme.com/jef/ *** 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 ) &&