OpenBSD 6.0 httpd Content-Length remote DoS

2017.02.02
Credit: Pierre Kim
Risk: Medium
Local: No
Remote: Yes
CWE: CWE-770


CVSS Base Score: 7.8/10
Impact Subscore: 6.9/10
Exploitability Subscore: 10/10
Exploit range: Remote
Attack complexity: Low
Authentication: No required
Confidentiality impact: None
Integrity impact: None
Availability impact: Complete

Log message: Reimplement httpd's support for byte ranges. The previous implementation loaded all the output into a single output buffer and used its size to determine the Content-Length of the body. The new implementation calculates the body length first and writes the individual ranges in an async way using the bufferevent mechanism. This prevents httpd from using too much memory and applies the watermark and throttling mechanisms to range requests. Problem reported by Pierre Kim (pierre.kim.sec at gmail.com) Patch: =================================================================== RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v retrieving revision 1.111 retrieving revision 1.112 diff -u -r1.111 -r1.112 --- src/usr.sbin/httpd/server_http.c 2017/01/31 12:21:27 1.111 +++ src/usr.sbin/httpd/server_http.c 2017/01/31 14:39:47 1.112 @@ -1,7 +1,7 @@ -/* $OpenBSD: server_http.c,v 1.111 2017/01/31 12:21:27 reyk Exp $ */ +/* $OpenBSD: server_http.c,v 1.112 2017/01/31 14:39:47 reyk Exp $ */ /* - * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org> + * Copyright (c) 2006 - 2017 Reyk Floeter <reyk@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -604,6 +604,101 @@ done: server_close(clt, "last http chunk read (done)"); + return; + fail: + server_close(clt, strerror(errno)); +} + +void +server_read_httprange(struct bufferevent *bev, void *arg) +{ + struct client *clt = arg; + struct evbuffer *src = EVBUFFER_INPUT(bev); + size_t size; + struct media_type *media; + struct range_data *r = &clt->clt_ranges; + struct range *range; + + getmonotime(&clt->clt_tv_last); + + if (r->range_toread > 0) { + size = EVBUFFER_LENGTH(src); + if (!size) + return; + + /* Read chunk data */ + if ((off_t)size > r->range_toread) { + size = r->range_toread; + if (server_bufferevent_write_chunk(clt, src, size) + == -1) + goto fail; + r->range_toread = 0; + } else { + if (server_bufferevent_write_buffer(clt, src) == -1) + goto fail; + r->range_toread -= size; + } + if (r->range_toread < 1) + r->range_toread = TOREAD_HTTP_RANGE; + DPRINTF("%s: done, size %lu, to read %lld", __func__, + size, r->range_toread); + } + + switch (r->range_toread) { + case TOREAD_HTTP_RANGE: + if (r->range_index >= r->range_count) { + if (r->range_count > 1) { + /* Add end marker */ + if (server_bufferevent_printf(clt, + "\r\n--%llu--\r\n", + clt->clt_boundary) == -1) + goto fail; + } + r->range_toread = TOREAD_HTTP_NONE; + break; + } + + range = &r->range[r->range_index]; + + if (r->range_count > 1) { + media = r->range_media; + if (server_bufferevent_printf(clt, + "\r\n--%llu\r\n" + "Content-Type: %s/%s\r\n" + "Content-Range: bytes %lld-%lld/%zu\r\n\r\n", + clt->clt_boundary, + media->media_type, media->media_subtype, + range->start, range->end, r->range_total) == -1) + goto fail; + } + r->range_toread = range->end - range->start + 1; + + if (lseek(clt->clt_fd, range->start, SEEK_SET) == -1) + goto fail; + + /* Throw away bytes that are already in the input buffer */ + evbuffer_drain(src, EVBUFFER_LENGTH(src)); + + /* Increment for the next part */ + r->range_index++; + break; + case TOREAD_HTTP_NONE: + case 0: + break; + } + + if (clt->clt_done) + goto done; + + if (EVBUFFER_LENGTH(EVBUFFER_OUTPUT(clt->clt_bev)) > (size_t) + SERVER_MAX_PREFETCH * clt->clt_sndbufsiz) { + bufferevent_disable(clt->clt_srvbev, EV_READ); + clt->clt_srvbev_throttled = 1; + } + + return; + done: + (*bev->errorcb)(bev, EVBUFFER_READ, bev->cbarg); return; fail: server_close(clt, strerror(errno));

References:

http://marc.info/?l=openbsd-cvs&m=148587359420912&w=2
http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.sbin/httpd/server_http.c
http://seclists.org/oss-sec/2017/q1/248


Vote for this issue:
50%
50%


 

Thanks for you vote!


 

Thanks for you comment!
Your message is in quarantine 48 hours.

Comment it here.


(*) - required fields.  
{{ x.nick }} | Date: {{ x.ux * 1000 | date:'yyyy-MM-dd' }} {{ x.ux * 1000 | date:'HH:mm' }} CET+1
{{ x.comment }}

Copyright 2024, cxsecurity.com

 

Back to Top