diff options
| author | Guilhem Moulin <guilhem@fripost.org> | 2020-08-03 20:27:38 +0200 | 
|---|---|---|
| committer | Guilhem Moulin <guilhem@fripost.org> | 2020-08-03 20:50:08 +0200 | 
| commit | 3b2939febdeb7f92051f95a3b08cf86e221ce21d (patch) | |
| tree | 5af420e5db686b913e2f5126b5d026e5d79e3fa3 | |
| parent | bc43c0d9468a8d50ba141c8a965f9f07ed0456ff (diff) | |
libinterimap: abort on PREAUTH greeting received on plaintext connections
Set "STARTTLS = NO" to ignore.  This is similar to CVE-2020-12398 and
CVE-2020-14093.
| -rw-r--r-- | Changelog | 3 | ||||
| -rw-r--r-- | lib/Net/IMAP/InterIMAP.pm | 11 | ||||
| -rw-r--r-- | tests/list | 1 | ||||
| -rwxr-xr-x | tests/preauth-plaintext/imapd | 44 | ||||
| l--------- | tests/preauth-plaintext/interimap.remote | 1 | ||||
| -rw-r--r-- | tests/preauth-plaintext/t | 19 | 
6 files changed, 78 insertions, 1 deletions
@@ -5,6 +5,9 @@ interimap (0.5.2) UNRELEASED;     and \[rq] in the groff output anyway).   - libinterimap: fix response injection vulnerability after STARTTLS.     For background see https://gitlab.com/muttmua/mutt/-/issues/248 . + - libinterimap: abort on PREAUTH greeting received on plaintext +   connections (set "STARTTLS = NO" to ignore).  This is similar to +   CVE-2020-12398 and CVE-2020-14093.   * libinterimap: fail when a capability to ENABLE is missing from the     server's CAPABILITY listing. diff --git a/lib/Net/IMAP/InterIMAP.pm b/lib/Net/IMAP/InterIMAP.pm index f0dd2df..b01e1a9 100644 --- a/lib/Net/IMAP/InterIMAP.pm +++ b/lib/Net/IMAP/InterIMAP.pm @@ -464,6 +464,7 @@ sub new($%) {              $self->logger('S: xxx ', $IMAP_text);              $self->{debug} = $dbg;          } +        $self->{_STATE} = 'AUTH';          unless ($IMAP_text =~ /\A\Q$IMAP_cond\E \[CAPABILITY /) {              # refresh the CAPABILITY list since the previous one had only pre-login capabilities @@ -471,7 +472,15 @@ sub new($%) {              $self->capabilities();          }      } -    $self->{_STATE} = 'AUTH'; +    elsif ($IMAP_cond eq 'PREAUTH') { +        if ($self->{type} eq 'imap' and $self->{STARTTLS} != 0) { +            $self->fail("PREAUTH greeting on plaintext connection? MiTM in action? Aborting, set \"STARTTLS = NO\" to ignore."); +        } +        $self->{_STATE} = 'AUTH'; +    } +    else { +        $self->panic(); +    }      # Don't send the COMPRESS command before STARTTLS or AUTH, as per RFC 4978      if ($self->{compress} // 1 and @@ -38,6 +38,7 @@ repair  --repair      auth-login              LOGIN      auth-logindisabled      LOGINDISABLED      auth-noplaintext        abort when STARTTLS is not offered +    preauth-plaintext       abort on MiTM via PREAUTH greeting  compress    COMPRESS=DEFLATE  condstore   CONDSTORE diff --git a/tests/preauth-plaintext/imapd b/tests/preauth-plaintext/imapd new file mode 100755 index 0000000..8f3ac30 --- /dev/null +++ b/tests/preauth-plaintext/imapd @@ -0,0 +1,44 @@ +#!/usr/bin/perl -T + +use warnings; +use strict; + +use Errno qw/EINTR/; +use Socket qw/INADDR_LOOPBACK AF_INET SOCK_STREAM pack_sockaddr_in +    SOL_SOCKET SO_REUSEADDR SHUT_RDWR/; + +socket(my $S, AF_INET, SOCK_STREAM, 0) or die; +setsockopt($S, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or die; +bind($S, pack_sockaddr_in(10143, INADDR_LOOPBACK)) or die "bind: $!\n"; +listen($S, 1) or die "listen: $!"; + +while (1) { +    my $sockaddr = accept(my $conn, $S) or do { +        next if $! == EINTR; +        die "accept: $!"; +    }; + +    # minimum CAPABILITY list, see tests/snippets/dovecot/interimap-required-capabilities.conf +    $conn->printflush("* PREAUTH [CAPABILITY IMAP4rev1 ENABLE UIDPLUS LIST-EXTENDED QRESYNC LIST-STATUS] IMAP4rev1 Server\r\n"); +    my $x; + +    $x = $conn->getline() // next; +    $x =~ /\A(\S+) ENABLE QRESYNC\r\n/ or die; +    $conn->printflush("* ENABLED QRESYNC\r\n$1 OK ENABLE completed\r\n"); + +    $x = $conn->getline() // next; +    $x =~ /\A(\S+) LIST .*\r\n/ or die; +    $conn->print("* LIST (\\Noselect) \"~\" \"\"\r\n"); +    $conn->print("* LIST () \"~\" INBOX\r\n"); +    $conn->print("* STATUS INBOX (UIDNEXT 1 UIDVALIDITY 1 HIGHESTMODSEQ 1)\r\n"); +    $conn->printflush("$1 OK LIST completed\r\n"); + +    close($conn); +} + +END { +    if (defined $S) { +        shutdown($S, SHUT_RDWR) or warn "shutdown: $!"; +        close($S) or print STDERR "Can't close: $!\n"; +    } +} diff --git a/tests/preauth-plaintext/interimap.remote b/tests/preauth-plaintext/interimap.remote new file mode 120000 index 0000000..ad49677 --- /dev/null +++ b/tests/preauth-plaintext/interimap.remote @@ -0,0 +1 @@ +../starttls/interimap.remote
\ No newline at end of file diff --git a/tests/preauth-plaintext/t b/tests/preauth-plaintext/t new file mode 100644 index 0000000..427d57b --- /dev/null +++ b/tests/preauth-plaintext/t @@ -0,0 +1,19 @@ +# Test IMAP MiTM via PREAUTH greeting +# For background see CVE-2020-12398, CVE-2020-14093 and +# https://gitlab.com/muttmua/mutt/commit/3e88866dc60b5fa6aaba6fd7c1710c12c1c3cd01 + +env -i USER="remote" HOME="$HOME_remote" "$TESTDIR/imapd" & PID=$! +trap "ptree_abort $PID" EXIT INT TERM + +! interimap --debug || error +grep -Fx 'remote: ERROR: PREAUTH greeting on plaintext connection? MiTM in action? Aborting, set "STARTTLS = NO" to ignore.' <"$STDERR" || error +! grep '^remote: C: ' <"$STDERR" || error "wrote command in MiTM'ed PREAUTH connection!" + + +# Ignore the warning when STARTTLS is explicitely disabled +echo "STARTTLS = NO" >>"$XDG_CONFIG_HOME/interimap/config" +interimap --debug || true + +grep -Fx "remote: S: * STATUS INBOX (UIDNEXT 1 UIDVALIDITY 1 HIGHESTMODSEQ 1)" <"$STDERR" || error + +# vim: set filetype=sh :  | 
