fix: Auth Remote Code execution

This commit is contained in:
d.saschenko 2023-09-28 17:43:58 +03:00
parent 2323e9c0e3
commit 97a075cf63
4 changed files with 89 additions and 9 deletions

View File

@ -23,9 +23,12 @@ use CachetHQ\Cachet\Models\Meta;
use CachetHQ\Cachet\Services\Dates\DateFactory; use CachetHQ\Cachet\Services\Dates\DateFactory;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Contracts\Auth\Guard; use Illuminate\Contracts\Auth\Guard;
use Twig\Environment as Twig_Environment; use Twig\Environment as Twig_Environment;
use Twig\Loader\ArrayLoader as Twig_Loader_Array; use Twig\Loader\ArrayLoader as Twig_Loader_Array;
/** /**
* This is the create incident command handler. * This is the create incident command handler.
* *
@ -49,6 +52,8 @@ class CreateIncidentCommandHandler
*/ */
protected $dates; protected $dates;
protected $twigConfig;
/** /**
* Create a new create incident command handler instance. * Create a new create incident command handler instance.
* *
@ -61,6 +66,8 @@ class CreateIncidentCommandHandler
{ {
$this->auth = $auth; $this->auth = $auth;
$this->dates = $dates; $this->dates = $dates;
$this->twigConfig = config("cachet.twig");
} }
/** /**
@ -131,6 +138,34 @@ class CreateIncidentCommandHandler
return $incident; 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. * Compiles an incident template into an incident message.
* *
@ -141,8 +176,7 @@ class CreateIncidentCommandHandler
*/ */
protected function parseTemplate(IncidentTemplate $template, CreateIncidentCommand $command) protected function parseTemplate(IncidentTemplate $template, CreateIncidentCommand $command)
{ {
$env = new Twig_Environment(new Twig_Loader_Array([])); $template = $this->sandboxedTwigTemplateData($template->template);
$template = $env->createTemplate($template->template);
$vars = array_merge($command->template_vars, [ $vars = array_merge($command->template_vars, [
'incident' => [ 'incident' => [
@ -158,6 +192,6 @@ class CreateIncidentCommandHandler
], ],
]); ]);
return $template->render($vars); return $template->render('secondStageLoader', $vars);
} }
} }

View File

@ -47,6 +47,11 @@ class UpdateIncidentCommandHandler
*/ */
protected $dates; protected $dates;
/**
* Twig configuration array.
*/
protected $twigConfig;
/** /**
* Create a new update incident command handler instance. * Create a new update incident command handler instance.
* *
@ -59,6 +64,8 @@ class UpdateIncidentCommandHandler
{ {
$this->auth = $auth; $this->auth = $auth;
$this->dates = $dates; $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. * Compiles an incident template into an incident message.
* *
@ -150,8 +179,7 @@ class UpdateIncidentCommandHandler
*/ */
protected function parseTemplate(IncidentTemplate $template, UpdateIncidentCommand $command) protected function parseTemplate(IncidentTemplate $template, UpdateIncidentCommand $command)
{ {
$env = new Twig_Environment(new Twig_Loader_Array([])); $template = $this->sandboxedTwigTemplateData($template->template);
$template = $env->createTemplate($template->template);
$vars = array_merge($command->template_vars, [ $vars = array_merge($command->template_vars, [
'incident' => [ 'incident' => [
@ -167,6 +195,6 @@ class UpdateIncidentCommandHandler
], ],
]); ]);
return $template->render($vars); return $template->render('secondStageLoader', $vars);
} }
} }

View File

@ -55,7 +55,7 @@
"nexmo/client": "^1.5", "nexmo/client": "^1.5",
"pragmarx/google2fa": "^5.0", "pragmarx/google2fa": "^5.0",
"predis/predis": "^1.1", "predis/predis": "^1.1",
"twig/twig": "^2.6" "twig/twig": "^3.0"
}, },
"require-dev": { "require-dev": {
"ext-sqlite3": "*", "ext-sqlite3": "*",

View File

@ -46,4 +46,22 @@ return [
'beacon' => env('CACHET_BEACON', true), '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' => [],
]
]; ];