xorl %eax, %eax

CVE-2011-0411: Postfix STARTTLS Plaintext Command Injection

leave a comment »

This vulnerability was discovered and reported by Wietse Venema and it affects multiple vendors although in this post I will be focusing on Postfix. According to SecurityFocus the vendor list includes:
Ipswitch
Kerio
Postfix
Qmail-TLS
Oracle (unknown product)
SCO Group

The extremely detailed analysis of the original author can be found here. As a quick outline, due to a software bug an attacker performing MITM attack on a TLS session can inject commands during the early plaintext SMTP phase in order to steal victim’s email or SASL (Simple Authentication and Security Layer) username and password.

To demonstrate the issue, Wietse Venema patched OpenSSL in order to start a TLS session using:

STARTTLS\r\nRSET\r\n

Instead of:

STARTTLS\r\n

After processing the first command, Postfix will initiate the TLS session (since it was requested), but then it will execute the RSET (or any other) command inside the encrypted session. By doing this a MITM attacker could inject commands during the plain-text stages that will be executed inside the secure TLS connection.

To fix this bug, src/smtp/smtp_proto.c was patched to discard plaintext commands following STARTTLS in smtp_start_tls() function.

#ifdef USE_TLS

/* smtp_start_tls - turn on TLS and recurse into the HELO dialog */

static int smtp_start_tls(SMTP_STATE *state)
{
    SMTP_SESSION *session = state->session;
    TLS_CLIENT_START_PROPS tls_props;
    VSTRING *serverid;
    SMTP_RESP fake;
  ...
    if (session->tls_context == 0) {
  ...
	    RETRY_AS_PLAINTEXT;
	return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
			       SMTP_RESP_FAKE(&fake, "4.7.5"),
			       "Cannot start TLS: handshake failure"));
    }
  ...
    /*
     * At this point we have to re-negotiate the "EHLO" to reget the
     * feature-list.
     */
    return (smtp_helo(state));
}

#endif

Which was patched to include this:

  
+     /* At this point there must not be any pending plaintext. */
+     vstream_fpurge(session->stream, VSTREAM_PURGE_BOTH);
+ 
      /*
       * At this point we have to re-negotiate the "EHLO" to reget the

The vstream_fpurge() routine is part of src/util/vstream.c and we can read its usage here:

/*	vstream_fpurge() discards the contents of the stream buffer.
/*	If direction is VSTREAM_PURGE_READ, it discards unread data,
/*	else if direction is VSTREAM_PURGE_WRITE, it discards unwritten
/*	data. In the case of a double-buffered stream, if direction is
/*	VSTREAM_PURGE_BOTH, it discards the content of both the read
/*	and write buffers. vstream_fpurge() returns 0 in case of success,
/*	VSTREAM_EOF in case of problems.

Furthermore, src/smtpd/smtpd.c was also updated in a similar manner. More specifically, the following routine responsible for TLS initiation command.

/* starttls_cmd - respond to STARTTLS */

static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv)
{
    const char *err;
    int     rate;
  ...
    smtpd_chat_reply(state, "220 2.0.0 Ready to start TLS");
    /* Flush before we switch the stream's read/write routines. */
    smtp_flush(state->client);
  ...
    /*
     * Turn on TLS, using code that is shared with TLS wrapper mode. This
     * code does not return when the handshake fails.
     */
    smtpd_start_tls(state);
    return (0);
}

Which was also patched.

      /* Flush before we switch the stream's read/write routines. */
      smtp_flush(state->client);
+     /* At this point there must not be any pending plaintext. */
+     vstream_fpurge(state->client, VSTREAM_PURGE_BOTH);
+
 /*

Written by xorl

May 2, 2011 at 20:48

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