[LOGO]

Memory corruption in Postfix SMTP server Cyrus SASL support (CVE-2011-1720)

Author: Wietse Venema

Last update: May 8, 2011

An on-line version of this text will be available at http://www.postfix.org/CVE-2011-1720.html.

Summary

The Postfix SMTP server has a memory corruption error when the Cyrus SASL library is used with authentication mechanisms other than PLAIN and LOGIN (the ANONYMOUS mechanism is unaffected but should not be enabled for different reasons). See below for instructions to determine what systems are affected.

Examples of affected Cyrus SASL authentication methods are CRAM-MD5, DIGEST-MD5, EXTERNAL, GSSAPI, KERBEROS_V4, NTLM, OTP, PASSDSS-3DES-1, and SRP.

The error was introduced with the Postfix SASL patch, and is present in all Postfix versions where the command "postconf mail_release_date" reports a value of 20000314 (March 14, 2000) or greater.

This problem was discovered by Thomas Jarosch of Intra2net AG.

The memory corruption is known to result in a program crash (SIGSEV). Remote code execution cannot be excluded. Such code would execute as the unprivileged "postfix" user. This user has no control over processes that run with non-postfix privileges including Postfix processes running as root; the impact may be reduced with configurations that enable the Postfix chroot feature or that use platform-dependent privilege-reducing features.

The problem is fixed in Postfix stable releases 2.5.13, 2.6.10, 2.7.4, 2.8.3; in the Postfix 2.9 development release as of May 1, 2011; patches exist for Postfix version 1.1 and later. All this is available from Postfix mirror sites listed at http://www.postfix.org/download.html.

What systems are affected

The Postfix SMTP client is not affected.

Affected are Postfix SMTP server configurations that have SASL authentication turned on, and that use Cyrus SASL authentication mechanisms other than ANONYMOUS, PLAIN and LOGIN. Here,

Although it is not affected, the ANONYMOUS authentication mechanism should not be enabled as it can make an SMTP server an open relay.

What systems are not affected

The Postfix SMTP client is not affected.

Not affected are Postfix SMTP server configurations that have SASL authentication turned off, including configurations without SASL support compiled in. Here, the command "postconf smtpd_sasl_auth_enable" produces as output "smtpd_sasl_auth_enable = no".

Not affected are Postfix SMTP server configurations that use Dovecot SASL instead of Cyrus SASL. Here, the command "postconf smtpd_sasl_type" produces as output "smtpd_sasl_type = dovecot".

Not affected are Postfix SMTP server configurations that enable Cyrus SASL support with only the PLAIN or LOGIN methods, or both. Here,

Not affected is the ANONYMOUS authentication mechanism, but this should not be enabled as it can make an SMTP server an open relay.

Workarounds

Disable Cyrus SASL authentication mechanisms for the Postfix SMTP server other than PLAIN and LOGIN. The mechanisms are specified in a Cyrus SASL smtpd.conf configuration file. This file may be found in /etc/postfix/sasl/, /var/lib/sasl2/, /etc/sasl2/, /usr/lib/sasl2/ or /usr/local/lib/sasl2/.

In this file, update the "mech_list:" entry and remove any methods other than PLAIN and LOGIN. For example, this configuration is not affected:

mech_list: PLAIN LOGIN

Execute the command "postfix reload" to make the change effective, then verify that the "port 25" and "port 587" services no longer announce other SASL mechanisms, as shown in the previous section.

Technical details

The Postfix SMTP server creates a SASL handle for each SMTP session, when SASL authentication is enabled. The Postfix SMTP server will use this SASL handle until it closes the SMTP connection (the Postfix SMTP server may create a new server SASL handle when the client and server agree to switch from a plaintext session to a TLS-encrypted session, but this does not eliminate the memory corruption problem).

According to a comment in a Cyrus SASL include source file, a server must not reuse a Cyrus SASL server handle after client authentication failure. Instead, a server must create a new Cyrus SASL server handle including mechanism list, before processing another client authentication request.

The Postfix SMTP server fails to create a new Cyrus SASL server handle after authentication failure. This causes memory corruption when, for example, a client requests CRAM-MD5 authentication, fails to authenticate, and then invokes some other authentication mechanism except PLAIN (or ANONYMOUS if available). The likely outcome is that the Postfix SMTP server process crashes with a segmentation violation error (SIGSEGV, a.k.a. signal 11).

In the following example, S: indicates server output and C: indicates client input. Line numbers are prepended for reference in the background discussion in the next section.

 1 S: 220 server.example.com ESMTP
 2 C: EHLO client.example.com
 3 S: 250-server.example.com
 4 S: ...other server output skipped...
 5 S: 250-AUTH DIGEST-MD5 LOGIN PLAIN CRAM-MD5
 6 S: 250-AUTH=DIGEST-MD5 LOGIN PLAIN CRAM-MD5
 7 S: ...other server output skipped...
 8 C: AUTH CRAM-MD5
 9 S: 334 PDg5ODE0OTI3MS4xMDQyMTg1OUBzZXJ2ZXIuZXhhbXBsZS5jb20+Cg==
10 C: *
11 S: 501 5.7.0 Authentication aborted
12 C: AUTH DIGEST-MD5
13 Connection closed by foreign host.

In the mail logfile, Postfix will log a warning similar to:

postfix/master[2213]: warning: process /usr/libexec/postfix/smtpd
pid 22585 killed by signal 11

Background

Each Cyrus SASL authentication mechanism is implemented with a) one statically-allocated shared data structure containing data and pointers to functions that implement the mechanism, and b) dynamically-allocated session context data structures with authentication state.

When the Postfix SMTP server receives "AUTH CRAM-MD5" (line 8 above), the Cyrus SASL CRAM-MD5 method initializes one CRAM-MD5 session context data structure, and generates the "step 1" initial client challenge which the Postfix SMTP server sends in line 9 above.

When the SMTP client sends "*" to abort the CRAM-MD5 authentication request (line 10 above), the CRAM-MD5 session context data structure remains attached to the Cyrus SASL server handle. Postfix fails to create a new Cyrus SASL server handle when the client sends the subsequent "AUTH DIGEST-MD5" request (line 12 above); the DIGEST-MD5 method will therefore use the "wrong" session context data structure (which was created after the "AUTH CRAM-MD5" request on line 8), and will skip its "step 1" challenge.

Each Cyrus SASL authentication method has a different context data structure layout. Because of these differences, the bits from the CRAM-MD5 method's context data structure will not work as intended with the DIGEST-MD5 method. As shown in the stack trace below, the Postfix SMTP server process crashes in "step 2" of the DIGEST-MD5 authentication protocol. This happens while attempting to read from a pointer that contains an invalid address.

In this particular example, the Postfix SMTP server crashes while running under control of the GDB debugger (see the Postfix master(5) manpage discussion of the -D option), while processing the SMTP commands shown in the example above.

(gdb) where
#0  0x884bbedf in clear_reauth_entry (reauth=0x206e6f69, type=SERVER,
    utils=0x88534400) at digestmd5.c:1579
#1  0x884be648 in digestmd5_server_mech_step2 (stext=0x88518150,
    sparams=0x8850c840, clientin=0x0, clientinlen=0, serverout=0xbfbfe140,
    serveroutlen=0xbfbfe144, oparams=0x8855e860) at digestmd5.c:2588
#2  0x884be9c5 in digestmd5_server_mech_step (conn_context=0x88518150,
    sparams=0x8850c840, clientin=0x0, clientinlen=0, serverout=0xbfbfe140,
    serveroutlen=0xbfbfe144, oparams=0x8855e860) at digestmd5.c:2689
#3  0x882a51e9 in sasl_server_step (conn=0x8855e000, clientin=0x0,
    clientinlen=0, serverout=0xbfbfe140, serveroutlen=0xbfbfe144)
    at server.c:1430
#4  0x882a5002 in sasl_server_start (conn=0x8855e000, mech=0x8854dc08
    "DIGEST-MD5", clientin=0x0, clientinlen=0, serverout=0xbfbfe140,
    serveroutlen=0xbfbfe144) at server.c:1362
#5  0x08066bf7 in xsasl_cyrus_server_first (xp=0x8851af18,
    sasl_method=0x8854dc08 "DIGEST-MD5", init_response=0x0,
    reply=0x8851aee8) at xsasl_cyrus_server.c:529
[Remainder of stack trace omitted for brevity]

This stack trace was obtained after informing the GDB debugger of SASL authentication methods that are linked in at runtime (example: "add-symbol-file /usr/local/lib/sasl2/libdigestmd5.so.2 0x884b8e50"). Without that information, GDB reports a corrupted stack, because it does not know that the program is executing legitimate code.

Impact analysis

What context data structure bits does the DIGEST-MD5 method inherit from the aborted CRAM-MD5 authentication request? As mentioned earlier, different Cyrus SASL authentication methods have different per-session context data structures. In particular, the CRAM-MD5 method uses a small structure while DIGEST-MD5 uses a larger one.

The DIGEST-MD5 method will therefore access memory outside the block that was allocated during the aborted CRAM-MD5 request. That is, it accesses random memory on the heap. The contents of that memory will depend on the malloc implementation and on the program execution history.

Version 2.1.23 of the Cyrus SASL library implements 12 authentication methods. Of these, 9 methods maintain server session context data structures that contain some mix of data and data pointers. When these are read from random heap memory, or from a structure that was allocated for a different SASL mechanism, all kinds of things could happen. This is why remote code execution cannot be excluded.

Why the Cyrus SASL PLAIN and LOGIN methods are not affected

There is no memory corruption problem with the "AUTH PLAIN" method, because this does not use or create a dynamically-allocated session context data structure. In particular, sending "AUTH LOGIN" after aborting or failing an "AUTH PLAIN" request does not result in memory corruption, because the PLAIN authentication method does not allocate a session context data structure. Also, sending "AUTH PLAIN" after aborting or failing an "AUTH LOGIN" request does not result in memory corruption, because the PLAIN authentication method ignores the per-session context data structure that is created by the LOGIN authentication method. Finally, there is no memory corruption when the LOGIN authentication method inherits a session context data structure from an aborted or failed "AUTH LOGIN" request.

It is for these reasons that Postfix SMTP servers with Cyrus SASL support for only PLAIN and LOGIN are not affected. Fortunately, PLAIN + LOGIN is the most commonly-used configuration, usually combined with TLS encryption to protect passwords on the wire. There will be a minor memory leak, but the Postfix SMTP server limits the number of failed requests and thereby limits the leak.

There is no memory corruption problem with the "AUTH ANONYMOUS" method, because just like "AUTH PLAIN" this does not create or use a dynamically-allocated session context data structure. However, "AUTH ANONYMOUS" support should not be enabled as it can make an SMTP server an open relay.

Timeline