CVE-2021-32749: Improper Control of Generation of Code ('Code Injection') (CWE-94)
value: fail2ban is a daemon to ban hosts that cause multiple authentication errors. In versions 0.9.7 and prior, 0.10.0 through 0.10.6, and 0.11.0 through 0.11.2, there is a vulnerability that leads to possible remote code execution in the mailing action mail-whois. Command `mail` from mailutils package used in mail actions like `mail-whois` can execute command if unescaped sequences (`\n~`) are available in "foreign" input (for instance in whois output). To exploit the vulnerability, an attacker would need to insert malicious characters into the response sent by the whois server, either via a MITM attack or by taking over a whois server. The issue is patched in versions 0.10.7 and 0.11.3. As a workaround, one may avoid the usage of action `mail-whois` or patch the vulnerability manually.
CWE description: The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
CVSS v3 base score: 8.1
Published: 2021-07-16T18:15Z
Repository: https://github.com/fail2ban/fail2ban
Language: Other
Files changed: config/action.d/complain.conf, config/action.d/dshield.conf, config/action.d/mail-buffered.conf, config/action.d/mail-whois-lines.conf, config/action.d/mail-whois.conf, config/action.d/mail.conf
Commit date: 2021-07-07 11:46:28 +0200
Commit message: fixed possible RCE vulnerability, unset escape variable (default tilde) stops consider "~" char after new-line as composing escape sequence
closes GHSA-m985-3f3v-cwmm for 0.9

Diff: diff --git a/config/action.d/complain.conf b/config/action.d/complain.conf
index 9247803e..993a31e4 100644
--- a/config/action.d/complain.conf
+++ b/config/action.d/complain.conf
@@ -77,11 +77,11 @@ logpath = /dev/null
 
 # Option:  mailcmd
 # Notes.:  Your system mail command. Is passed 2 args: subject and recipient
 # Values:  CMD
 #
-mailcmd = mail -s
+mailcmd = mail -E 'set escape' -s
 
 # Option:  mailargs
 # Notes.:  Additional arguments to mail command. e.g. for standard Unix mail:
 #          CC reports to another address:
 #              -c me@example.com
diff --git a/config/action.d/dshield.conf b/config/action.d/dshield.conf
index a0041986..ae7014fa 100644
--- a/config/action.d/dshield.conf
+++ b/config/action.d/dshield.conf
@@ -174,11 +174,11 @@ tcpflags =
 
 # Option:  mailcmd
 # Notes.:  Your system mail command. Is passed 2 args: subject and recipient
 # Values:  CMD
 #
-mailcmd = mail -s
+mailcmd = mail -E 'set escape' -s
 
 # Option:  mailargs
 # Notes.:  Additional arguments to mail command. e.g. for standard Unix mail:
 #          CC reports to another address:
 #              -c me@example.com
diff --git a/config/action.d/mail-buffered.conf b/config/action.d/mail-buffered.conf
index 914d4a5a..f530e958 100644
--- a/config/action.d/mail-buffered.conf
+++ b/config/action.d/mail-buffered.conf
@@ -12,28 +12,28 @@
 #
 actionstart = printf %%b "Hi,\n
               The jail <name> has been started successfully.\n
               Output will be buffered until <lines> lines are available.\n
               Regards,\n
-              Fail2Ban"|mail -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
+              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
 
 # Option:  actionstop
 # Notes.:  command executed once at the end of Fail2Ban
 # Values:  CMD
 #
 actionstop = if [ -f <tmpfile> ]; then
                  printf %%b "Hi,\n
                  These hosts have been banned by Fail2Ban.\n
                  `cat <tmpfile>`
                  Regards,\n
-                 Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary from `uname -n`" <dest>
+                 Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: Summary from `uname -n`" <dest>
                  rm <tmpfile>
              fi
              printf %%b "Hi,\n
              The jail <name> has been stopped.\n
              Regards,\n
-             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
+             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
 
 # Option:  actioncheck
 # Notes.:  command executed once before each actionban command
 # Values:  CMD
 #
@@ -50,11 +50,11 @@ actionban = printf %%b "`date`: <ip> (<failures> failures)\n" >> <tmpfile>
             if [ $LINE -ge <lines> ]; then
                 printf %%b "Hi,\n
                 These hosts have been banned by Fail2Ban.\n
                 `cat <tmpfile>`
                 \nRegards,\n
-                Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary" <dest>
+                Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: Summary" <dest>
                 rm <tmpfile>
             fi
 
 # Option:  actionunban
 # Notes.:  command executed when unbanning an IP. Take care that the
diff --git a/config/action.d/mail-whois-lines.conf b/config/action.d/mail-whois-lines.conf
index 6e39c605..39f78957 100644
--- a/config/action.d/mail-whois-lines.conf
+++ b/config/action.d/mail-whois-lines.conf
@@ -15,20 +15,20 @@ before = mail-whois-common.conf
 # Values:  CMD
 #
 actionstart = printf %%b "Hi,\n
               The jail <name> has been started successfully.\n
               Regards,\n
-              Fail2Ban"|mail -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
+              Fail2Ban" | <mailcmd> "[Fail2Ban] <name>: started on `uname -n`" <dest>
 
 # Option:  actionstop
 # Notes.:  command executed once at the end of Fail2Ban
 # Values:  CMD
 #
 actionstop = printf %%b "Hi,\n
              The jail <name> has been stopped.\n
              Regards,\n
-             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
+             Fail2Ban" | <mailcmd> "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
 
 # Option:  actioncheck
 # Notes.:  command executed once before each actionban command
 # Values:  CMD
 #
@@ -46,11 +46,11 @@ actionban = printf %%b "Hi,\n
             Here is more information about <ip> :\n
             `%(_whois_command)s`\n\n
             Lines containing IP:<ip> in <logpath>\n
             `grep -E <grepopts> '(^|[^0-9])<ip>([^0-9]|$)' <logpath>`\n\n
             Regards,\n
-            Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from  `uname -n`" <dest>
+            Fail2Ban" | <mailcmd> "[Fail2Ban] <name>: banned <ip> from  `uname -n`" <dest>
 
 # Option:  actionunban
 # Notes.:  command executed when unbanning an IP. Take care that the
 #          command is executed with Fail2Ban user rights.
 # Tags:    See jail.conf(5) man page
@@ -58,10 +58,16 @@ actionban = printf %%b "Hi,\n
 #
 actionunban = 
 
 [Init]
 
+# Option:  mailcmd
+# Notes.:  Your system mail command. Is passed 2 args: subject and recipient
+# Values:  CMD
+#
+mailcmd = mail -E 'set escape' -s
+
 # Default name of the chain
 #
 name = default
 
 # Destinataire of the mail
diff --git a/config/action.d/mail-whois.conf b/config/action.d/mail-whois.conf
index 018c327d..2c346bfe 100644
--- a/config/action.d/mail-whois.conf
+++ b/config/action.d/mail-whois.conf
@@ -15,20 +15,20 @@ before = mail-whois-common.conf
 # Values:  CMD
 #
 actionstart = printf %%b "Hi,\n
               The jail <name> has been started successfully.\n
               Regards,\n
-              Fail2Ban"|mail -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
+              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
 
 # Option:  actionstop
 # Notes.:  command executed once at the end of Fail2Ban
 # Values:  CMD
 #
 actionstop = printf %%b "Hi,\n
              The jail <name> has been stopped.\n
              Regards,\n
-             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
+             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
 
 # Option:  actioncheck
 # Notes.:  command executed once before each actionban command
 # Values:  CMD
 #
@@ -44,11 +44,11 @@ actionban = printf %%b "Hi,\n
             The IP <ip> has just been banned by Fail2Ban after
             <failures> attempts against <name>.\n\n
             Here is more information about <ip> :\n
             `%(_whois_command)s`\n
             Regards,\n
-            Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
+            Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
 
 # Option:  actionunban
 # Notes.:  command executed when unbanning an IP. Take care that the
 #          command is executed with Fail2Ban user rights.
 # Tags:    See jail.conf(5) man page
diff --git a/config/action.d/mail.conf b/config/action.d/mail.conf
index 7bf51a1d..9755f097 100644
--- a/config/action.d/mail.conf
+++ b/config/action.d/mail.conf
@@ -11,20 +11,20 @@
 # Values:  CMD
 #
 actionstart = printf %%b "Hi,\n
               The jail <name> has been started successfully.\n
               Regards,\n
-              Fail2Ban"|mail -s "[Fail2Ban] <name>: started  on `uname -n`" <dest>
+              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started  on `uname -n`" <dest>
 
 # Option:  actionstop
 # Notes.:  command executed once at the end of Fail2Ban
 # Values:  CMD
 #
 actionstop = printf %%b "Hi,\n
              The jail <name> has been stopped.\n
              Regards,\n
-             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
+             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
 
 # Option:  actioncheck
 # Notes.:  command executed once before each actionban command
 # Values:  CMD
 #
@@ -38,11 +38,11 @@ actioncheck =
 #
 actionban = printf %%b "Hi,\n
             The IP <ip> has just been banned by Fail2Ban after
             <failures> attempts against <name>.\n
             Regards,\n
-            Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
+            Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
 
 # Option:  actionunban
 # Notes.:  command executed when unbanning an IP. Take care that the
 #          command is executed with Fail2Ban user rights.
 # Tags:    See jail.conf(5) man page

Vulnerable code: mailcmd = mail -s
mailcmd = mail -s
              Fail2Ban"|mail -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
                 Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary from `uname -n`" <dest>
             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
                Fail2Ban"|mail -s "[Fail2Ban] <name>: Summary" <dest>
              Fail2Ban"|mail -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
            Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from  `uname -n`" <dest>
              Fail2Ban"|mail -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
            Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
              Fail2Ban"|mail -s "[Fail2Ban] <name>: started  on `uname -n`" <dest>
             Fail2Ban"|mail -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
            Fail2Ban"|mail -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
Fixed code: mailcmd = mail -E 'set escape' -s
mailcmd = mail -E 'set escape' -s
              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
                 Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: Summary from `uname -n`" <dest>
             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
                Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: Summary" <dest>
              Fail2Ban" | <mailcmd> "[Fail2Ban] <name>: started on `uname -n`" <dest>
             Fail2Ban" | <mailcmd> "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
            Fail2Ban" | <mailcmd> "[Fail2Ban] <name>: banned <ip> from  `uname -n`" <dest>
# Option:  mailcmd
# Notes.:  Your system mail command. Is passed 2 args: subject and recipient
# Values:  CMD
#
mailcmd = mail -E 'set escape' -s

              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started on `uname -n`" <dest>
             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
            Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>
              Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: started  on `uname -n`" <dest>
             Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: stopped on `uname -n`" <dest>
            Fail2Ban"|mail -E 'set escape' -s "[Fail2Ban] <name>: banned <ip> from `uname -n`" <dest>