From 4c650bb775ab849e48202a4923bac93bd74f9982 Mon Sep 17 00:00:00 2001 From: Samuel Georges Date: Fri, 4 Sep 2020 13:02:01 +1000 Subject: [PATCH] Security fixes for v1.0.469 Introduces sandbox policy to block extendable methods allowing arbitrary code execution --- modules/cms/classes/Controller.php | 3 ++ modules/system/ServiceProvider.php | 3 ++ modules/system/twig/SecurityPolicy.php | 61 ++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 modules/system/twig/SecurityPolicy.php diff --git a/modules/cms/classes/Controller.php b/modules/cms/classes/Controller.php index 381aab2bf..c86919f72 100644 --- a/modules/cms/classes/Controller.php +++ b/modules/cms/classes/Controller.php @@ -15,6 +15,7 @@ use SystemException; use BackendAuth; use Twig\Environment as TwigEnvironment; use Twig\Cache\FilesystemCache as TwigCacheFilesystem; +use Twig\Extension\SandboxExtension; use Cms\Twig\Loader as TwigLoader; use Cms\Twig\DebugExtension; use Cms\Twig\Extension as CmsTwigExtension; @@ -23,6 +24,7 @@ use System\Models\RequestLog; use System\Helpers\View as ViewHelper; use System\Classes\CombineAssets; use System\Twig\Extension as SystemTwigExtension; +use System\Twig\SecurityPolicy; use October\Rain\Exception\AjaxException; use October\Rain\Exception\ValidationException; use October\Rain\Parse\Bracket as TextParser; @@ -608,6 +610,7 @@ class Controller $this->twig = new TwigEnvironment($this->loader, $options); $this->twig->addExtension(new CmsTwigExtension($this)); $this->twig->addExtension(new SystemTwigExtension); + $this->twig->addExtension(new SandboxExtension(new SecurityPolicy, true)); if ($isDebugMode) { $this->twig->addExtension(new DebugExtension($this)); diff --git a/modules/system/ServiceProvider.php b/modules/system/ServiceProvider.php index 9fc858f39..055d89ba5 100644 --- a/modules/system/ServiceProvider.php +++ b/modules/system/ServiceProvider.php @@ -19,6 +19,7 @@ use System\Classes\UpdateManager; use System\Twig\Engine as TwigEngine; use System\Twig\Loader as TwigLoader; use System\Twig\Extension as TwigExtension; +use System\Twig\SecurityPolicy as TwigSecurityPolicy; use System\Models\EventLog; use System\Models\MailSetting; use System\Classes\CombineAssets; @@ -27,6 +28,7 @@ use October\Rain\Support\ModuleServiceProvider; use October\Rain\Router\Helper as RouterHelper; use Illuminate\Pagination\Paginator; use Illuminate\Support\Facades\Schema; +use Twig\Extension\SandboxExtension; class ServiceProvider extends ModuleServiceProvider { @@ -297,6 +299,7 @@ class ServiceProvider extends ModuleServiceProvider App::singleton('twig.environment', function ($app) { $twig = new TwigEnvironment(new TwigLoader, ['auto_reload' => true]); $twig->addExtension(new TwigExtension); + $twig->addExtension(new SandboxExtension(new TwigSecurityPolicy, true)); return $twig; }); diff --git a/modules/system/twig/SecurityPolicy.php b/modules/system/twig/SecurityPolicy.php new file mode 100644 index 000000000..d215e328b --- /dev/null +++ b/modules/system/twig/SecurityPolicy.php @@ -0,0 +1,61 @@ +setBlockedMethods($this->blockedMethods); + } + + public function setBlockedMethods(array $methods) + { + foreach ($this->blockedMethods as $i => $m) { + $this->blockedMethods[$i] = strtr($m, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); + } + } + + public function checkSecurity($tags, $filters, $functions) + { + } + + public function checkMethodAllowed($obj, $method) + { + if ($obj instanceof Template || $obj instanceof Markup) { + return; + } + + $blockedMethod = strtr($method, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'); + + if (in_array($blockedMethod, $this->blockedMethods)) { + $class = get_class($obj); + throw new SecurityNotAllowedMethodError(sprintf('Calling "%s" method on a "%s" object is blocked.', $method, $class), $class, $method); + } + } + + public function checkPropertyAllowed($obj, $property) + { + if (in_array($property, $this->blockedProperties)) { + $class = get_class($obj); + throw new SecurityNotAllowedPropertyError(sprintf('Calling "%s" property on a "%s" object is blocked.', $property, $class), $class, $property); + } + } +}