Nginx ngx_http_close_connection function integer overflow exploit + patch

Recently we became aware of a major exploit in nginx that has been around for at least a years time now. As of now it has made it’s way public and has not been patched. Included in this post are some unofficial patches.

I. BACKGROUND
———————

Nginx is an HTTP and reverse proxy server, as well as a mail proxy server, written by Igor Sysoev. For a long time, it has been running on many heavily loaded Russian sites including Yandex, Mail.Ru, VKontakte, and Rambler. According to Netcraft nginx served or proxied 12.96% busiest sites in April 2013. Here are some of the success stories: Netflix, WordPress.com, FastMail.FM.

II. DESCRIPTION
———————

Qihoo 360 Web Security Research Team discovered a critical vulnerability in nginx.

The vulnerability is caused by a int overflow error within the Nginx
ngx_http_close_connection function when r->count is less then 0 or more then 255, which could be exploited
by remote attackers to compromise a vulnerable system via malicious http requests.

III. AFFECTED PRODUCTS
—————————

Nginx all latest version

IV. Exploits/PoCs
—————————————

In-depth technical analysis of the vulnerability and a fully functional remote code execution exploit are available through the safe3q (at) gmail (dot) com [email concealed]
In src\http\ngx_http_request_body.c ngx_http_discard_request_body function,we can make r->count++.

V. VUPEN Threat Protection Program
———————————–

VI. SOLUTION
—————-

Validate the r->count input.

VII. CREDIT
————–

This vulnerability was discovered by Safe3 of Qihoo 360.

VIII. ABOUT Qihoo 360
—————————

Qihoo 360 is the leading provider of defensive and offensive web cloud security of China.

IX. REFERENCES
———————-

http://nginx.org/en/

This following way is a weak validation, which can be used but it would be more ideal to patch the headers.

diff –git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 9f63143..807cbc0 100644
— a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1986,7 +1986,8 @@ static u_char *ngx_http_log_error_handler(ngx_http_request_t *r,
 
         if (r == c->data) {
 
-            r->main->count–;
+        if (r->main->count > 0)
+                r->main->count–;
 
             if (!r->logged) {
 
@@ -2022,7 +2023,8 @@ static u_char *ngx_http_log_error_handler(ngx_http_request_t *r,
         }
 
         if (ngx_http_post_request(pr, NULL) != NGX_OK) {
-            r->main->count++;
+        if (r->main->count < 255)
+                r->main->count++;
             ngx_http_terminate_request(r, 0);
             return;
         }
@@ -2911,7 +2913,8 @@ static u_char *ngx_http_log_error_handler(ngx_http_request_t *r,
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    “post action: \”%V\””, &clcf->post_action);
 
-    r->main->count–;
+    if (r->main->count > 0)
+        r->main->count–;
 
     r->http_version = NGX_HTTP_VERSION_9;
     r->header_only = 1;
@@ -2945,7 +2948,8 @@ static u_char *ngx_http_log_error_handler(ngx_http_request_t *r,
         ngx_log_error(NGX_LOG_ALERT, c->log, 0, “http request count is zero”);
     }
 
-    r->count–;
+    if (r->count > 0)
+        r->count–;
 
     if (r->count || r->blocked) {
         return;
diff –git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index ac09d56..8ea33f4 100644
— a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -37,7 +37,8 @@ static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
     ngx_http_request_body_t   *rb;
     ngx_http_core_loc_conf_t  *clcf;
 
-    r->main->count++;
+    if (r->main->count < 255)
+        r->main->count++;
 
     if (r->request_body || r->discard_body) {
         post_handler(r);
@@ -485,7 +486,8 @@ static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
         r->lingering_close = 0;
 
     } else {
-        r->count++;
+        if (r->count < 255)
+            r->count++;
         r->discard_body = 1;
     }

More ideally, you will want to patch ngx_http_request.h and look for “count:8″ and patch that unsigned int.

You do any of the following:

  • either #include <stdint.h> and make that line ‘uint8_t count;’
  • or you can “typedef unsigned char uint8_t;” and make the line ‘uint8_t count;’
  • OR you can just make the line ‘unsigned char count;’

 

REF:

http://www.securityfocus.com/archive/1/526439/30/0/threaded

http://seclists.org/oss-sec/2013/q2/212

Special thanks goes out to Xires for help in the patching.

None found.
Share on Tumblr

10 thoughts on “Nginx ngx_http_close_connection function integer overflow exploit + patch

  1. Pingback: terry

  2. Pingback: Marshall

  3. Pingback: cody

  4. Pingback: Tyrone

  5. Pingback: kurt

  6. Pingback: Jack

  7. Pingback: Zachary

  8. Pingback: Matt

  9. Pingback: Jordan

  10. Pingback: arturo

Comments are closed.