xorl %eax, %eax

CVE-2009-1191: Apache mod_proxy_ajp Invalid Reply Buffer

leave a comment »

This design bug (it’s not a vulnerability) was reported on 1 April 2009 by Sander de Boer and affects Apache 2.2.11 release. This module is a support module of the popular mod_proxy Apache module and provides support for JServ Protocol version 1.3 (AJP stands for Apache JServ Protocol). Here is the buggy function of that module:

17 /* AJP routines for Apache proxy */
   ...
157 /*
158  * process the request and write the response.
159  */
160 static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
161                                 proxy_conn_rec *conn,
162                                 conn_rec *origin,
163                                 proxy_dir_conf *conf,
164                                 apr_uri_t *uri,
165                                 char *url, char *server_portstr)
166 {
      ...
172     ajp_msg_t *msg;
173     apr_size_t bufsiz = 0;
      ...
228     /* allocate an AJP message to store the data of the buckets */
229     bufsiz = maxsize;
230     status = ajp_alloc_data_msg(r->pool, &buff, &bufsiz, &msg);
      ...
286         if (bufsiz > 0) {
      ...
305         else if (content_length > 0) {
306             ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
307                          "proxy: read zero bytes, expecting"
308                          " %" APR_OFF_T_FMT " bytes",
309                          content_length);
310             status = ajp_send_data_msg(conn->sock, msg, 0);
311             if (status != APR_SUCCESS) {
312                 /* We had a failure: Close connection to backend */
313                 conn->close++;
314                 ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
315                             "proxy: send failed to %pI (%s)",
316                             conn->worker->cp->addr,
317                             conn->worker->hostname);
318                 return HTTP_INTERNAL_SERVER_ERROR;
319             }
320             else {
321                 /* Client send zero bytes with C-L > 0
322                  */
323                 return HTTP_BAD_REQUEST;
324             }
325         }
326     }
327
328     /* read the response */
      ...
584 }

The bug on the above code from modules/proxy/mod_proxy_ajp.c appears when client sends data where bufsize (line 286) isn’t greater than zero and their content length is greater than zero, this module will reply (line 310) with msg which was allocated at line 230 using ajp_alloc_data_msg() routine from modules/proxy/ajp_header.c. This is a simple function that does this:

747 /*
748  * Allocate a msg to send data
749  */
750 apr_status_t  ajp_alloc_data_msg(apr_pool_t *pool, char **ptr, apr_size_t *len,
751                                  ajp_msg_t **msg)
752 {
753     apr_status_t rc;
754
755     if ((rc = ajp_msg_create(pool, *len, msg)) != APR_SUCCESS)
756         return rc;
757     ajp_msg_reset(*msg);
758     *ptr = (char *)&((*msg)->buf[6]);
759     *len =  *len - 6;
760
761     return APR_SUCCESS;
762 }


It is clear that msg is allocated at line 755 using ajp_msg_create() which is a wrapper around apr_pcalloc(), and buff is initialized to point to the address of (*msg)->buf[6]. This means that if a client is able to reach the code of line 310 he will receive an empty message (because of apr_pcalloc() which zeroes out the buffer). Obviously, this cannot lead to an information leak but every vulnerability database has listed this bug as an information leak (including CVE). This was patched simply by applying this patch:

-            status = ajp_send_data_msg(conn->sock, msg, 0);
-            if (status != APR_SUCCESS) {
-                /* We had a failure: Close connection to backend */
-                conn->close++;
-                ap_log_error(APLOG_MARK, APLOG_ERR, status, r->server,
-                            "proxy: send failed to %pI (%s)",
-                            conn->worker->cp->addr,
-                            conn->worker->hostname);
-                return HTTP_INTERNAL_SERVER_ERROR;
-            }
-            else {
-                /* Client send zero bytes with C-L > 0
-                 */
-                return HTTP_BAD_REQUEST;
-            }
+            /*
+             * We can only get here if the client closed the connection
+             * to us without sending the body.
+             * Now the connection is in the wrong state on the backend.
+             * Sending an empty data msg doesn't help either as it does
+             * not move this connection to the correct state on the backend
+             * for later resusage by the next request again.
+             * Close it to clean things up.
+             */
+            conn->close++;
+            return HTTP_BAD_REQUEST;
         }


Even though this is indeed a design flaw I don’t think it is by any means a security bug…

Written by xorl

April 25, 2009 at 00:18

Posted in bugs

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s