From 97a075cf637dc0bb439f19c6f8c4c00af487598d Mon Sep 17 00:00:00 2001 From: "d.saschenko" Date: Thu, 28 Sep 2023 17:43:58 +0300 Subject: [PATCH] fix: Auth Remote Code execution --- .../Incident/CreateIncidentCommandHandler.php | 42 +++++++++++++++++-- .../Incident/UpdateIncidentCommandHandler.php | 36 ++++++++++++++-- composer.json | 2 +- config/cachet.php | 18 ++++++++ 4 files changed, 89 insertions(+), 9 deletions(-) diff --git a/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php b/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php index fe9cec9dd..9b7b83e7f 100644 --- a/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php +++ b/app/Bus/Handlers/Commands/Incident/CreateIncidentCommandHandler.php @@ -23,9 +23,12 @@ use CachetHQ\Cachet\Models\Meta; use CachetHQ\Cachet\Services\Dates\DateFactory; use Carbon\Carbon; use Illuminate\Contracts\Auth\Guard; + use Twig\Environment as Twig_Environment; use Twig\Loader\ArrayLoader as Twig_Loader_Array; + + /** * This is the create incident command handler. * @@ -49,6 +52,8 @@ class CreateIncidentCommandHandler */ protected $dates; + protected $twigConfig; + /** * Create a new create incident command handler instance. * @@ -61,6 +66,8 @@ class CreateIncidentCommandHandler { $this->auth = $auth; $this->dates = $dates; + + $this->twigConfig = config("cachet.twig"); } /** @@ -131,6 +138,34 @@ class CreateIncidentCommandHandler return $incident; } + protected function sandboxedTwigTemplateData(String $templateData) { + + if (!$templateData) { + return ""; + } + + $policy = new \Twig\Sandbox\SecurityPolicy($this->twigConfig["tags"], + $this->twigConfig["filters"], + $this->twigConfig["methods"], + $this->twigConfig["props"], + $this->twigConfig["functions"]); + + $sandbox = new \Twig\Extension\SandboxExtension($policy); + + $templateBasicLoader = new Twig_Loader_Array([ + 'firstStageLoader' => $templateData + ]); + + $sandBoxBasicLoader = new Twig_Loader_Array([ + 'secondStageLoader' => '{% sandbox %}{% include "firstStageLoader" %} {% endsandbox %}' + ]); + + $hardenedLoader = new \Twig\Loader\ChainLoader([$templateBasicLoader, $sandBoxBasicLoader]); + $twig = new Twig_Environment($hardenedLoader); + $twig->addExtension($sandbox); + return $twig; + } + /** * Compiles an incident template into an incident message. * @@ -141,8 +176,7 @@ class CreateIncidentCommandHandler */ protected function parseTemplate(IncidentTemplate $template, CreateIncidentCommand $command) { - $env = new Twig_Environment(new Twig_Loader_Array([])); - $template = $env->createTemplate($template->template); + $template = $this->sandboxedTwigTemplateData($template->template); $vars = array_merge($command->template_vars, [ 'incident' => [ @@ -157,7 +191,7 @@ class CreateIncidentCommandHandler 'component_status' => $command->component_status, ], ]); - - return $template->render($vars); + + return $template->render('secondStageLoader', $vars); } } diff --git a/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php b/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php index dff31ccfd..7f6074128 100644 --- a/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php +++ b/app/Bus/Handlers/Commands/Incident/UpdateIncidentCommandHandler.php @@ -47,6 +47,11 @@ class UpdateIncidentCommandHandler */ protected $dates; + /** + * Twig configuration array. + */ + protected $twigConfig; + /** * Create a new update incident command handler instance. * @@ -59,6 +64,8 @@ class UpdateIncidentCommandHandler { $this->auth = $auth; $this->dates = $dates; + + $this->twigConfig = $twigConfig = config("cachet.twig"); } /** @@ -140,6 +147,28 @@ class UpdateIncidentCommandHandler }); } + protected function sandboxedTwigTemplateData(String $templateData) { + $policy = new \Twig\Sandbox\SecurityPolicy($this->twigConfig["tags"], + $this->twigConfig["filters"], + $this->twigConfig["methods"], + $this->twigConfig["props"], + $this->twigConfig["functions"]); + $sandbox = new \Twig\Extension\SandboxExtension($policy); + + $templateBasicLoader = new \Twig\Loader\ArrayLoader([ + 'firstStageLoader' => $templateData + ]); + + $sandBoxBasicLoader = new \Twig\Loader\ArrayLoader([ + 'secondStageLoader' => '{% sandbox %}{% include "firstStageLoader" %} {% endsandbox %}' + ]); + + $hardenedLoader = new \Twig\Loader\ChainLoader([$templateBasicLoader, $sandBoxBasicLoader]); + $twig = new \Twig\Environment($hardenedLoader); + $twig->addExtension($sandbox); + return $twig; + } + /** * Compiles an incident template into an incident message. * @@ -150,8 +179,7 @@ class UpdateIncidentCommandHandler */ protected function parseTemplate(IncidentTemplate $template, UpdateIncidentCommand $command) { - $env = new Twig_Environment(new Twig_Loader_Array([])); - $template = $env->createTemplate($template->template); + $template = $this->sandboxedTwigTemplateData($template->template); $vars = array_merge($command->template_vars, [ 'incident' => [ @@ -166,7 +194,7 @@ class UpdateIncidentCommandHandler 'component_status' => $command->component_status, ], ]); - - return $template->render($vars); + + return $template->render('secondStageLoader', $vars); } } diff --git a/composer.json b/composer.json index 5a757891c..ab5a06562 100644 --- a/composer.json +++ b/composer.json @@ -55,7 +55,7 @@ "nexmo/client": "^1.5", "pragmarx/google2fa": "^5.0", "predis/predis": "^1.1", - "twig/twig": "^2.6" + "twig/twig": "^3.0" }, "require-dev": { "ext-sqlite3": "*", diff --git a/config/cachet.php b/config/cachet.php index dd3f27051..b8f41b899 100644 --- a/config/cachet.php +++ b/config/cachet.php @@ -46,4 +46,22 @@ return [ 'beacon' => env('CACHET_BEACON', true), + + /* + |-------------------------------------------------------------------------- + | Templates configurations + |-------------------------------------------------------------------------- + | + | Security fix: now user can provide information which will be included to the Twig sandbox settings + | + | Default: Described below + | + */ + 'twig' => [ + 'methods' => [], + 'functions' => [], + 'filters' => ['escape'], + 'tags' => ['if'], + 'props' => [], + ] ];