Information Assurance

Brent Putman


front | classes | research | personal | contact

Information Assurance

Bugtraq Analysis

Format String Vulnerability in Apache auth_ldap module

back to bugtraq analyses page

Listings:
Bugtraq: http://www.securityfocus.com/bid/16177
CVE: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2006-0150

This vulnerability concerns a remote format string attack in the auth_ldap module for the Apache web server. Apache is an open source web server and is the most commonly used web server for Unix and Linux operating systems. The auth_ldap module is a popular and commonly used extension module for Apache that allows authentication of users against a Lightweight Directory Access Protocol (LDAP) server. LDAP servers are commonly used for storing user authentication and authorization data in large enterprise environments.

This vulnerability only affects the auth_ldap 1.6.0 module for version 1.3 of Apache. Apache version 2.0 has been available for several years and bundles a rewritten version of auth_ldap which is apparently not vulnerable to the problem described below. However, many sites still use Apache 1.3 and auth_ldap, and it also continues to be bundled with many vendor products such as Oracle.

The general problem is that of an attack against the format string of the printf() family of functions. This type of attack is described in detail in the article "Format String Attacks". Essentially if a user is able to influence or determine in some way the content of the format string used in the call to printf(), sprintf(), etc., they can essentially read and write data to other memory locations in the process's address space. This occurs because no bounds checking is done to ensure that the number of format specifiers in the format string is equal to the number of variable arguments to the function. The presence of extra format specifiers means that areas on the stack past the genuine arguments may be accessed. Additionally, use of the %n format specifier allows writing to locations that are referenced by pointers stored on the stack. These pointers can easily be setup if the buffer containing the format string is somewhere on the stack above the function call. So in essence this attack allows the attacker to write arbitrary values to almost any arbitrary addresses in memory. This attack would seem to be potentially even more serious than the traditional buffer overflow, in which only values on the stack after the buffer can be overwritten.

The auth_ldap vulnerability occurs because of an improper use of an Apache server logging function ap_log_rerror(). The problem occurs in the following auth_ldap module function:

auth_ldap.c:

void auth_ldap_log_reason(request_rec *r, const char *fmt, ...)
{
  va_list args;
  char buf[MAX_STRING_LEN];

  va_start(args, fmt);
  ap_vsnprintf(buf, sizeof(buf), fmt, args);
  va_end(args);

#if APACHE_RELEASE < 1030000
  log_reason(buf, r->uri, r);
#else
  ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, buf);
#endif
}
The format string in the call to ap_log_rerror (variable buf above) contains string data that is potentially supplied directly by the user. ap_log_error() in turn calls a couple of functions which must process the variable arguments of the format string:
Apache http_log.c

API_EXPORT_NONSTD(void) ap_log_rerror(const char *file, int line, int level,
                               const request_rec *r, const char *fmt, ...)
{
    va_list args;
        
    va_start(args, fmt);
    log_error_core(file, line, level, r->server, r, fmt, args);

    va_end(args);
    va_start(args,fmt);
    if (((level & APLOG_LEVELMASK) <= APLOG_WARNING)
        && (ap_table_get(r->notes, "error-notes") == NULL)) {
        ap_table_setn(r->notes, "error-notes",
                      ap_escape_html(r->pool, ap_pvsprintf(r->pool, fmt,
                      args)));
    }
    va_end(args);
}   
For example, log_error_core() calls ap_vsnprint() to produce a formatted string buffer:
static void log_error_core(const char *file, int line, int level,
                           const server_rec *s, const request_rec *r,
                           const char *fmt, va_list args)
{

	(..... SNIP .......)

#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
    if (ap_vsnprintf(scratch, sizeof(scratch) - len, fmt, args)) {
        len += ap_escape_errorlog_item(errstr + len, scratch,
                                       sizeof(errstr) - len);
    }
#else
    len += ap_vsnprintf(errstr + len, sizeof(errstr) - len, fmt, args);
#endif

	(..... SNIP .......)

}
In turn ap_vsnprintf() must process the variable number of format specifiers, and it is here that extraneous format specifiers may be exploited.

There are several possible vectors of attack which allow a malicious remote user to choose or influence the content of the format string, such as the web URL that is being accessed. These correspond to different places in the module where various pieces of information are logged during request processing. The most obvious and direct way to influence the format string is via the username sent by the user, which is logged by the module here:

auth_ldap_log_reason(r, "LDAP search for %s failed: LDAP error: %s; URI %s",
		filtbuf, ldap_err2string(result), r->uri);
In this case the username supplied by the user for doing HTTP Basic authentication would be included in the filtbuf variable above, e.g. "uid=username". By specifying a specially-crafted username, a format string attack against the logging function is possible. This potentially allows a remote user to run code with the same permissions as the Apache server httpd process.

The problem could have been prevented by not allowing the user-determined string to be used directly as the format string by the ap_log_rerror() function. Instead a fixed format string constant should always be used, for example:

   BAD:  printf(userinput_buffer)
    vs.
   GOOD: printf("%s", userinput_buffer)
The auth_ldap v1.6.1 module patch to fix this vulnerability was a simple change to the ap_log_rerror() call, adding a fixed format string with a single %s string format specifier:
ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r, "%s", buf);

Another workaround or fix to the vulnerability would be to upgrade the server to Apache 2.0 or 2.2. The version of the auth_ldap module included with those versions is not vulnerable to this problem.

Format string attack vulnerabilities can generally be found and avoided by static analysis tools such as Flawfinder. It is usually easy for such tools to flag whether the format string used is a constant string or a variable buffer.