]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
ftp,imap,pop3,smtp: reject STARTTLS server response pipelining
authorPatrick Monnerat <patrick@monnerat.net>
Tue, 7 Sep 2021 11:26:42 +0000 (13:26 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 13 Sep 2021 14:51:31 +0000 (16:51 +0200)
If a server pipelines future responses within the STARTTLS response, the
former are preserved in the pingpong cache across TLS negotiation and
used as responses to the encrypted commands.

This fix detects pipelined STARTTLS responses and rejects them with an
error.

CVE-2021-22947

Bug: https://curl.se/docs/CVE-2021-22947.html

lib/ftp.c
lib/imap.c
lib/pop3.c
lib/smtp.c
tests/data/Makefile.inc
tests/data/test980 [new file with mode: 0644]
tests/data/test981 [new file with mode: 0644]
tests/data/test982 [new file with mode: 0644]
tests/data/test983 [new file with mode: 0644]

index 08d18ca7442b3fb42c4aaf886b1e5c8d8bc21fc7..0b9c9b7322b5e2098da9a93bc2746b18b20b523d 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -2743,6 +2743,9 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
     case FTP_AUTH:
       /* we have gotten the response to a previous AUTH command */
 
+      if(pp->cache_size)
+        return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */
+
       /* RFC2228 (page 5) says:
        *
        * If the server is willing to accept the named security mechanism,
index 923b1d59bd1cc30c10d95ba25f2865a8f7175861..6163899bbeb6fd2dd9f5b130776b3bc0fc284746 100644 (file)
@@ -963,6 +963,10 @@ static CURLcode imap_state_starttls_resp(struct Curl_easy *data,
 
   (void)instate; /* no use for this yet */
 
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.imapc.pp.cache_size)
+    return CURLE_WEIRD_SERVER_REPLY;
+
   if(imapcode != IMAP_RESP_OK) {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
       failf(data, "STARTTLS denied");
index a331d71f7770592390c3b7e2feb603f8133d5964..d3f3de6d49a9e2153c7183580a62418f910faf01 100644 (file)
@@ -771,6 +771,10 @@ static CURLcode pop3_state_starttls_resp(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   (void)instate; /* no use for this yet */
 
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.pop3c.pp.cache_size)
+    return CURLE_WEIRD_SERVER_REPLY;
+
   if(pop3code != '+') {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
       failf(data, "STARTTLS denied");
index 20dc85a5f23b69a204f558dc92895b95727b02cf..02ddaca0a279bcf4124222e200dc4ef8b717b47a 100644 (file)
@@ -834,6 +834,10 @@ static CURLcode smtp_state_starttls_resp(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   (void)instate; /* no use for this yet */
 
+  /* Pipelining in response is forbidden. */
+  if(data->conn->proto.smtpc.pp.cache_size)
+    return CURLE_WEIRD_SERVER_REPLY;
+
   if(smtpcode != 220) {
     if(data->set.use_ssl != CURLUSESSL_TRY) {
       failf(data, "STARTTLS denied, code %d", smtpcode);
index 8e05ee907401074b71cf167dd7ace9f37cd3a550..787c3637510a5d740fc2ff0e38ab0ddb6cefbbbd 100644 (file)
@@ -118,7 +118,7 @@ test954 test955 test956 test957 test958 test959 test960 test961 test962 \
 test963 test964 test965 test966 test967 test968 test969 test970 test971 \
 test972 \
 \
-test984 test985 test986 \
+test980 test981 test982 test983 test984 test985 test986 \
 \
 test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \
 test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \
diff --git a/tests/data/test980 b/tests/data/test980
new file mode 100644 (file)
index 0000000..97567f8
--- /dev/null
@@ -0,0 +1,52 @@
+<testcase>
+<info>
+<keywords>
+SMTP
+STARTTLS
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<servercmd>
+CAPA STARTTLS
+AUTH PLAIN
+REPLY STARTTLS 454 currently unavailable\r\n235 Authenticated\r\n250 2.1.0 Sender ok\r\n250 2.1.5 Recipient ok\r\n354 Enter mail\r\n250 2.0.0 Accepted
+REPLY AUTH 535 5.7.8 Authentication credentials invalid
+</servercmd>
+</reply>
+
+#
+# Client-side
+<client>
+<features>
+SSL
+</features>
+<server>
+smtp
+</server>
+ <name>
+SMTP STARTTLS pipelined server response
+ </name>
+<stdin>
+mail body
+</stdin>
+ <command>
+smtp://%HOSTIP:%SMTPPORT/%TESTNUMBER --mail-rcpt recipient@example.com --mail-from sender@example.com -u user:secret --ssl --sasl-ir -T -
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# 8 is CURLE_WEIRD_SERVER_REPLY
+<errorcode>
+8
+</errorcode>
+<protocol>
+EHLO %TESTNUMBER\r
+STARTTLS\r
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test981 b/tests/data/test981
new file mode 100644 (file)
index 0000000..2b98ce4
--- /dev/null
@@ -0,0 +1,59 @@
+<testcase>
+<info>
+<keywords>
+IMAP
+STARTTLS
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<servercmd>
+CAPA STARTTLS
+REPLY STARTTLS A002 BAD currently unavailable\r\nA003 OK Authenticated\r\nA004 OK Accepted
+REPLY LOGIN A003 BAD Authentication credentials invalid
+</servercmd>
+</reply>
+
+#
+# Client-side
+<client>
+<features>
+SSL
+</features>
+<server>
+imap
+</server>
+ <name>
+IMAP STARTTLS pipelined server response
+ </name>
+ <command>
+imap://%HOSTIP:%IMAPPORT/%TESTNUMBER -T log/upload%TESTNUMBER -u user:secret --ssl
+</command>
+<file name="log/upload%TESTNUMBER">
+Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
+From: Fred Foobar <foobar@example.COM>
+Subject: afternoon meeting
+To: joe@example.com
+Message-Id: <B27397-0100000@example.COM>
+MIME-Version: 1.0
+Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
+
+Hello Joe, do you think we can meet at 3:30 tomorrow?
+</file>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# 8 is CURLE_WEIRD_SERVER_REPLY
+<errorcode>
+8
+</errorcode>
+<protocol>
+A001 CAPABILITY\r
+A002 STARTTLS\r
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test982 b/tests/data/test982
new file mode 100644 (file)
index 0000000..9e07cc0
--- /dev/null
@@ -0,0 +1,57 @@
+<testcase>
+<info>
+<keywords>
+POP3
+STARTTLS
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<servercmd>
+CAPA STLS USER
+REPLY STLS -ERR currently unavailable\r\n+OK user accepted\r\n+OK authenticated
+REPLY PASS -ERR Authentication credentials invalid
+</servercmd>
+<data nocheck="yes">
+From: me@somewhere
+To: fake@nowhere
+
+body
+
+--
+  yours sincerely
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<features>
+SSL
+</features>
+<server>
+pop3
+</server>
+ <name>
+POP3 STARTTLS pipelined server response
+ </name>
+ <command>
+pop3://%HOSTIP:%POP3PORT/%TESTNUMBER -u user:secret --ssl
+ </command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+# 8 is CURLE_WEIRD_SERVER_REPLY
+<errorcode>
+8
+</errorcode>
+<protocol>
+CAPA\r
+STLS\r
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test983 b/tests/data/test983
new file mode 100644 (file)
index 0000000..300ec45
--- /dev/null
@@ -0,0 +1,52 @@
+<testcase>
+<info>
+<keywords>
+FTP
+STARTTLS
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<servercmd>
+REPLY AUTH 500 unknown command\r\n500 unknown command\r\n331 give password\r\n230 Authenticated\r\n257 "/"\r\n200 OK\r\n200 OK\r\n200 OK\r\n226 Transfer complete
+REPLY PASS 530 Login incorrect
+</servercmd>
+</reply>
+
+# Client-side
+<client>
+<features>
+SSL
+</features>
+<server>
+ftp
+</server>
+ <name>
+FTP STARTTLS pipelined server response
+ </name>
+<file name="log/test%TESTNUMBER.txt">
+data
+    to
+      see
+that FTPS
+works
+  so does it?
+</file>
+ <command>
+--ssl --ftp-ssl-control ftp://%HOSTIP:%FTPPORT/%TESTNUMBER -T log/test%TESTNUMBER.txt -u user:secret -P %CLIENTIP
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+# 8 is CURLE_WEIRD_SERVER_REPLY
+<errorcode>
+8
+</errorcode>
+<protocol>
+AUTH SSL\r
+</protocol>
+</verify>
+</testcase>