Guam allows unencrypted plaintext authentication
Open, 60Public

Description

When the connection to the backend imap server is already a tls encrypted connection guam doesn't really care about what's being entered into unencrypted imap port 143

The default configuration provided by the Kolab:16 packages always proxies to the SSL cyrus imapd and therefore it is possible to authentication without the connection between client and guam gets encrypted.

port 143 is served from guam

# netstat -lanp | grep :::.*beam
tcp6       0      0 :::993                  :::*                    LISTEN      26956/beam.smp
tcp6       0      0 :::143                  :::*                    LISTEN      26956/beam.smp

netcat session:

$ nc localhost 143
* OK [CAPABILITIES IMAP4rev1 STARTTLS LITERAL+ ID ENABLE SASL-IR LOGINDISABLED] kolab Cyrus IMAP 2.5.10-49-g2e214b4-Debian-2.5.10.49-0~kolab1 server ready
a0001 AUTHENTICATE PLAIN xxxxxxxxxxxxxxxxxxxxxx
a0001 OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA MAILBOX-REFERRALS NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLAUTH=BINARY LOGINDISABLED X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE] Success (tls protection) SESSIONID=<kolab-26555-1481325756-1-17824217024115701091>
a0004 LSUB "" "*"
* LSUB (\Noinferiors) "/" INBOX
* LSUB () "/" Drafts
* LSUB () "/" Sent
* LSUB () "/" Spam
* LSUB () "/" Trash
a0004 OK Completed (0.000 secs 15 calls)

default configuration provided by Kolab:16 package:
https://git.kolab.org/file/data/iinxl4zrxlxuxve57rmi/PHID-FILE-jdmamxgvbwwgd5wfsuis/guam.sys.config.tpl

Workaround:

When iI configure two seperated backends (143 --> 1143 and 993 --> 1993) and assign them correctly I can force the need for an encrypted connection. To fix the default installation we would have to enable imap instances for Port 1143 in cyrus.conf and add a second backend

Other Problem

If you want to offload the ssl encryption and only talk plaintext to the backend there's no chance to disallow plaintext encryption.

Possible Solution/Enhancement

adding a filter/rule to disallow plaintext over unencrypted sessions. This could be done in a similar fashion compared to the groupware folder filterset.

Details

Ticket Type
Task
dhoffend added projects: Guam, PyKolab.
dhoffend added subscribers: Restricted Project, PyKolab Developers.
dhoffend updated the task description. (Show Details)Dec 10 2016, 12:48 AM

Known issue.

However, from https://tools.ietf.org/html/rfc3501#section-6.2.3

A client implementation MUST NOT send a LOGIN command if the LOGINDISABLED capability is advertised.

So in both theory and practice, this only impacts non-RFC compliant clients.

The solution to this involves more tracking overhead in Guam itself. It could indeed be added, and I would happily accept such a patch. It would best be implemented as a rule, which would make the overhead optional as well as allow it to be ordered as desired within larger rule sets, while also preventing more code in kolab_guam_session. This, however, requires being able to see the state of the socket's TLS .. this is possible with the slightly dirty:

try ssl:connection_information(Socket, protocol) of

_ -> is_ssl

catch

_:_ -> not_an_ssl_connection

end.

Otherwise, that information could be explicitly passed into kolab_guam_rule:applies/3, since the sesssion does know this. Currently the ConnectionDetails parameter is unused, but was intended for this purpose. Making that clean in kolab_guam_session would be a small amount of work, but nothing big: kolab_guam_session:apply_ruleset_clientside/6 should take a State object instead of the individual unpacked variables. This would have the nice side-effect of hiding the parameter requires of apply_ruleset_clientside, turning it into apply_ruleset_clientside/2. But then it could pick out the SSL/TLS status easily and pass that on to rules.

More interestingly (but which I mean, "It is less immediately apparent what the best implementation would be"), is that currently rules are not informed when things like the TLS status changes in a session. In fact, once a rule goes active, there is currently no mechanism by which to deactivate it. This would be easy to add as a recognized return from apply_to_client_message and apply_to_server_message (e.g. { { change_application_state, true|false|notyet}, ProcessedCommand :: binary(), State :: any() }). Which still leaves the question of how to let a rule know it should deactivate. Perhaps a better solution would be introduce a conditionally response for kolab_guam_rule:apply which puts the rule into the active pipeline but which also calls apply on it as well, allowing it to potentially alter its apply status. This would allow rules to deactive via apply_to returns, or to be repeatedly asked if they reply or not.

So that would be the bulk of the work. From there, implementing a rule that denies LOGIN from clients when the client socket is not in a good state would be trivial.

The fact is that the clients may respond to the availability of authentication capabilities before TLS is started (notably URLAUTH, SASL-IR, while AUTH= parameters are already stripped):

$ imtest -t "" guam.example.org
S: * OK [CAPABILITIES IMAP4rev1 STARTTLS LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLX-NETSCAPE MUPDATE=mupdate://imapm01.example.org/ SASL-IR X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE LOGINDISABLED] imapf01.example.org Cyrus IMAP Murder 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el7.kolab_14 server ready
C: S01 STARTTLS
S: S01 OK Begin TLS negotiation now
verify error:num=20:unable to get local issuer certificate
TLS connection established: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
C: C01 CAPABILITY
S: * CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLAUTH=BINARY X-NETSCAPE MUPDATE=mupdate://imapf01.example.org/ AUTH=PLAIN AUTH=LOGIN SASL-IR X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE
S: C01 OK Completed

It is Guam that forwards a set of capabilities that is associated with a post-STARTTLS connection's capabilities response from the upstream server, albeit moderated, whereas we would expect such pre-STARTTLS capabilities to look as follows:

$ imtest -t "" imap.example.org
S: * OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE MUPDATE=mupdate://imapm01.example.org/ STARTTLS LOGINDISABLED] imapf01.example.org Cyrus IMAP Murder 2.5.10-49-g2e214b4-Kolab-2.5.10-8.1.el6.kolab_14 server ready
C: S01 STARTTLS
S: S01 OK Begin TLS negotiation now
verify error:num=20:unable to get local issuer certificate
TLS connection established: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
C: C01 CAPABILITY
S: * CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLAUTH=BINARY X-NETSCAPE MUPDATE=mupdate://imapm01.example.org/ AUTH=LOGIN AUTH=PLAIN SASL-IR X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE
S: C01 OK Completed

Perhaps a solution is as simple as to remove more capabilities from the initial response line, or inversely, disclose only a (very limited) number (that is very likely to not increase)?

A possible workaround (especially for Kolab:16) would be to update the default configurations of Cyrus and Guam.

Cyrus should listen on 1143 (non-ssl) and 9993 (ssl) while guam forwards 143 to 1143 and 993 to 9993 (2 different upstream servers and 2 listeners). This way guam isn't exposing and you wouldn't have to deal with it. But in the long term it would be great of guam could take over this work so you wouldn't need cyrus to listen on 2 different ports and running 2 different sets of worker/threads.

A possible workaround (especially for Kolab:16) would be to update the default configurations of Cyrus and Guam.

Cyrus should listen on 1143 (non-ssl) and 9993 (ssl) while guam forwards 143 to 1143 and 993 to 9993 (2 different upstream servers and 2 listeners). This way guam isn't exposing and you wouldn't have to deal with it. But in the long term it would be great of guam could take over this work so you wouldn't need cyrus to listen on 2 different ports and running 2 different sets of worker/threads.

Have you verified this? I believe Guam does not await the client's STARTTLS before issuing the upstream STARTTLS and using the resulting capabilities even before the client uses STARTTLS.

Yes. I've already played around with this setup. Here're the results. The only thing that's strange are the capabilities after STARTTLS but before! AUTH

# netstat -lanp | egrep "(143|993).*LISTEN"
tcp        0      0 127.0.0.1:1143          0.0.0.0:*               LISTEN      15000/imapd
tcp        0      0 127.0.0.1:9993          0.0.0.0:*               LISTEN      6580/imapd
tcp6       0      0 :::993                  :::*                    LISTEN      26956/beam.smp
tcp6       0      0 :::143                  :::*                    LISTEN      26956/beam.smp

Guam Config

                imap_servers, [
                    {
                        imap, [
                            { host, "127.0.0.1" },
                            { port, 1143 },
                            { tls, no }
                        ]
                    },
                    {
                        imaps, [
                            { host, "127.0.0.1" },
                            { port, 9993 },
                            { tls, true }
                        ]
                    }
                ]
            },
            {
                listeners, [
                    {
                        imap, [
                            { port, 143 },
                            { imap_server, imap },
[...]
                        ]
                    },
                    {
                        imaps, [
                            { port, 993 },
                            { implicit_tls, true },
                            { imap_server, imaps },
[...]
                        ]
                    }
                ]
            }

Cyrus Config

SERVICES {
    imap        cmd="imapd"     listen="127.0.0.1:1143"                 prefork=5
    imaps       cmd="imapd -s"  listen="127.0.0.1:9993"                 prefork=5
[...]

Test @ 143

# nc localhost 143
* OK [CAPABILITIES IMAP4rev1 LITERAL+ ID ENABLE STARTTLS LOGINDISABLED] kolab Cyrus IMAP 2.5.10-49-g2e214b4-Debian-2.5.10.49-0~kolab1 server ready

Test @ 993

# openssl s_client -connect localhost:993
[...]
* OK [CAPABILITIES IMAP4rev1 LITERAL+ ID ENABLE AUTH=PLAIN AUTH=LOGIN SASL-IR] kolab Cyrus IMAP 2.5.10-49-g2e214b4-Debian-2.5.10.49-0~kolab1 server ready

Here's the test using imtest - First without starttls

# echo '. LSUB "" "*"' | imtest -a daniel.hoffend@dotlan.info -u daniel.hoffend@dotlan.info imap.dotlan.info
S: * OK [CAPABILITIES IMAP4rev1 LITERAL+ ID ENABLE STARTTLS LOGINDISABLED] kolab Cyrus IMAP 2.5.10-49-g2e214b4-Debian-2.5.10.49-0~kolab1 server ready
Authentication failed. generic failure
Security strength factor: 0
C: Q01 LOGOUT
. BAD Please login first
* BYE LOGOUT received
Q01 OK Completed
Connection closed.

Now with TLS on port 143 and folder listening!

# echo '. LSUB "" "*"' | imtest -a daniel.hoffend@dotlan.info -u daniel.hoffend@dotlan.info -w xxx -p 143 -t "" imap.dotlan.info
S: * OK [CAPABILITIES IMAP4rev1 LITERAL+ ID ENABLE STARTTLS LOGINDISABLED] kolab Cyrus IMAP 2.5.10-49-g2e214b4-Debian-2.5.10.49-0~kolab1 server ready
C: S01 STARTTLS
S: S01 OK Begin TLS negotiation now
verify error:num=20:unable to get local issuer certificate
verify error:num=27:certificate not trusted
TLS connection established: TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)
C: C01 CAPABILITY
S: * CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA MAILBOX-REFERRALS NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLAUTH=BINARY AUTH=PLAIN AUTH=LOGIN SASL-IR X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE
S: C01 OK Completed
C: A01 AUTHENTICATE PLAIN xxxxx
S: A01 OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA MAILBOX-REFERRALS NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLAUTH=BINARY LOGINDISABLED X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE] Success (tls protection) SESSIONID=<kolab-19331-1481548337-1-7507230494601159912>
Authenticated.
Security strength factor: 256
C: Q01 LOGOUT
* LSUB (\Noinferiors) "/" INBOX
* LSUB () "/" Drafts
* LSUB () "/" Sent
* LSUB () "/" Spam
* LSUB () "/" Trash
. OK Completed (0.000 secs 15 calls)
* BYE LOGOUT received
Q01 OK Completed
Connection closed.

and with on the SSL port

# echo '. LSUB "" "*"' | imtest -a daniel.hoffend@dotlan.info -u daniel.hoffend@dotlan.info -w xxx -p 993 -s imap.dotlan.info
verify error:num=20:unable to get local issuer certificate
verify error:num=27:certificate not trusted
TLS connection established: TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)
S: * OK [CAPABILITIES IMAP4rev1 LITERAL+ ID ENABLE AUTH=PLAIN AUTH=LOGIN SASL-IR] kolab Cyrus IMAP 2.5.10-49-g2e214b4-Debian-2.5.10.49-0~kolab1 server ready
C: A01 AUTHENTICATE PLAIN xxxxx
S: A01 OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA MAILBOX-REFERRALS NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLAUTH=BINARY LOGINDISABLED X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE] Success (tls protection) SESSIONID=<kolab-19330-1481548394-1-7293193142785187231>
Authenticated.
Security strength factor: 256
C: Q01 LOGOUT
* LSUB (\Noinferiors) "/" INBOX
* LSUB () "/" Drafts
* LSUB () "/" Sent
* LSUB () "/" Spam
* LSUB () "/" Trash
. OK Completed (0.000 secs 15 calls)
* BYE LOGOUT received
Q01 OK Completed
Connection closed.

It's interesting to see that the capabilites are way more doing IMAP(143) with STARTTLS compared to IMAPS(993). Where can this difference come from? Some cyrus settings?

Test @ 143

# nc localhost 143
* OK [CAPABILITIES IMAP4rev1 LITERAL+ ID ENABLE STARTTLS LOGINDISABLED] kolab Cyrus IMAP 2.5.10-49-g2e214b4-Debian-2.5.10.49-0~kolab1 server ready

The IMAP backend server configuration for port imap/1143 normally uses { tls, starttls }. In your configuration, it uses { tls, no }.

dhoffend added a comment.EditedDec 12 2016, 4:42 PM

With {tls, no} guam will not initiate the STARTTLS to the backend server and present the non-starttls response. With { tls, starttls } guam will already initialize a STARTTLS Session to the backend resulting in the security problem descriped above and guam allows unencrypted login, Even the LOGIN is stripped from the CAPABILITY afail

See this result:

# nc localhost 143
* OK [CAPABILITIES IMAP4rev1 STARTTLS LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA MAILBOX-REFERRALS NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLSASL-IR X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE LOGINDISABLED] kolab Cyrus IMAP 2.5.10-49-g2e214b4-Debian-2.5.10.49-0~kolab1 server ready
A01 AUTHENTICATE PLAIN xxxxxxxx
A01 OK [CAPABILITY IMAP4rev1 LITERAL+ ID ENABLE ACL RIGHTS=kxten QUOTA MAILBOX-REFERRALS NAMESPACE UIDPLUS NO_ATOMIC_RENAME UNSELECT CHILDREN MULTIAPPEND BINARY CATENATE CONDSTORE ESEARCH SORT SORT=MODSEQ SORT=DISPLAY SORT=UID THREAD=ORDEREDSUBJECT THREAD=REFERENCES ANNOTATEMORE ANNOTATE-EXPERIMENT-1 METADATA LIST-EXTENDED LIST-STATUS LIST-MYRIGHTS WITHIN QRESYNC SCAN XLIST XMOVE MOVE SPECIAL-USE CREATE-SPECIAL-USE URLAUTH URLAUTH=BINARY LOGINDISABLED X-QUOTA=STORAGE X-QUOTA=MESSAGE X-QUOTA=X-ANNOTATION-STORAGE X-QUOTA=X-NUM-FOLDERS IDLE] Success (tls protection) SESSIONID=<kolab-20199-1481557031-1-13709034272015041780>
A02 LSUB "" "*"
* LSUB (\Noinferiors) "/" INBOX
* LSUB () "/" Drafts
* LSUB () "/" Sent
* LSUB () "/" Spam
* LSUB () "/" Trash
A02 OK Completed (0.000 secs 15 calls)
. LOGOUT
* BYE LOGOUT received
. OK Completed

If you set {tls, no} will wait for the switch to starttlsup until to the point when the client asks for it. That's why i explicitly configured {tls, no} to make sure the session isn't preauthorized (aka tls enabled from the viewpoint of the cyrus server.

seigo moved this task from Backlog to Pending on the Guam board.Dec 13 2016, 2:01 PM
pasik added a subscriber: pasik.Nov 25 2017, 2:33 PM