Opened 5 years ago

Closed 4 years ago

#762 closed defect (fixed)

procol version integer overflow, downgrade to 0.9

Reported by: openid.stackexchange.com/user/9a01f091-0d6d-4e99-8f37-dcf99897dd7c Owned by:
Priority: minor Milestone:
Component: nginx-core Version: 1.7.x
Keywords: Cc:
uname -a:
nginx -V: nginx version: nginx/1.9.0
built by gcc 4.9.2 (Debian 4.9.2-10)
configure arguments:

Description

Nginx currently supports the old RFC with :

HTTP / *DIGIT . *DIGIT

But when extracting the major and minor version there's an int16 overflow which means that currently "HTTP/65536.9" or "HTTP/65536.8" can be used and will be detected as HTTP/0.9.

This can be used to generate headless responses from Nginx (like a regular 0.9 query) while using something which does not look like a 0.9 query.

They're two ways of fixing it:

  • use the attached patch to prevent int16 overflow
  • remove the multi-digit part in the automaton parser (as the new rfc 7230 allows only one digit for major and 1 for minor)

Note that this patch is a poc on ngx_http_parse.c which may need to be applied on other places like ngx_event_openssl_stapling.c or  ngx_http_spdy.c where the same issue can also be present.

Attachments (1)

patch_ngx_http_parse_int_overflow_protocol_version.txt (1.9 KB ) - added by openid.stackexchange.com/user/9a01f091-0d6d-4e99-8f37-dcf99897dd7c 5 years ago.

Download all attachments as: .zip

Change History (4)

by openid.stackexchange.com/user/9a01f091-0d6d-4e99-8f37-dcf99897dd7c, 5 years ago

comment:1 by Maxim Dounin, 4 years ago

Status: newaccepted

The restriction in the suggested patch can be easily bypassed: the patch stores number of digits parsed on stack, while the ngx_http_parse_request_line() function can be called multiple times.

Slightly better patch below.

# HG changeset patch
# User Maxim Dounin <mdounin@mdounin.ru>
# Date 1463276652 -10800
#      Sun May 15 04:44:12 2016 +0300
# Node ID bf200866cde2099c1cbff31a5dcb32722ca62fb3
# Parent  f2491b0f35af80c91018c0930cbcfe5556453e35
Added overflow checks for version numbers (ticket #762).

Both minor and major versions are now limited to 999 maximum.  In case of
r->http_minor, this limit is already implied by the code.  Major version,
r->http_major, in theory can be up to 65535 with current code, but such
values are very unlikely to become real (and, additionally, such values
are not allowed by RFC 7230), so the same test was used for r->http_major.

diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -737,6 +737,10 @@ ngx_http_parse_request_line(ngx_http_req
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
 
+            if (r->http_major > 99) {
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+
             r->http_major = r->http_major * 10 + ch - '0';
             break;
 
@@ -770,6 +774,10 @@ ngx_http_parse_request_line(ngx_http_req
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
 
+            if (r->http_minor > 99) {
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+
             r->http_minor = r->http_minor * 10 + ch - '0';
             break;
 
@@ -1680,6 +1688,10 @@ ngx_http_parse_status_line(ngx_http_requ
                 return NGX_ERROR;
             }
 
+            if (r->http_major > 99) {
+                return NGX_ERROR;
+            }
+
             r->http_major = r->http_major * 10 + ch - '0';
             break;
 
@@ -1704,6 +1716,10 @@ ngx_http_parse_status_line(ngx_http_requ
                 return NGX_ERROR;
             }
 
+            if (r->http_minor > 99) {
+                return NGX_ERROR;
+            }
+
             r->http_minor = r->http_minor * 10 + ch - '0';
             break;
 

comment:2 by Maxim Dounin <mdounin@…>, 4 years ago

In 6543:302ff40c9bc9/nginx:

Added overflow checks for version numbers (ticket #762).

Both minor and major versions are now limited to 999 maximum. In case of
r->http_minor, this limit is already implied by the code. Major version,
r->http_major, in theory can be up to 65535 with current code, but such
values are very unlikely to become real (and, additionally, such values
are not allowed by RFC 7230), so the same test was used for r->http_major.

comment:3 by Maxim Dounin, 4 years ago

Resolution: fixed
Status: acceptedclosed
Note: See TracTickets for help on using tickets.