Smarty模板注入

Smarty模板注入

CVE-2021-29454

漏洞报告

Smarty 是 PHP 的模板引擎,有助于将表示 (HTML/CSS) 与应用程序逻辑分离。在 3.1.42 和 4.0.2 版本之前,模板作者可以通过制作恶意数学字符串来运行任意 PHP 代码。如果数学字符串作为用户提供的数据传递给数学函数,则外部用户可以通过制作恶意数学字符串来运行任意 PHP 代码。用户应升级到版本 3.1.42 或 4.0.2 以接收补丁。

源码修复

/plugins/function.math.php中添加下面代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// Remove whitespaces
    $equation = preg_replace('/\s+/', '', $equation);

    // Adapted from https://www.php.net/manual/en/function.eval.php#107377
    $number = '(?:\d+(?:[,.]\d+)?|pi|π)'; // What is a number
    $functionsOrVars = '((?:0x[a-fA-F0-9]+)|([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*))';
    $operators = '[+\/*\^%-]'; // Allowed math operators
    $regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)+\)|\((?1)+\)))(?:'.$operators.'(?2))?)+$/';

    if (!preg_match($regexp, $equation)) {
        trigger_error("math: illegal characters", E_USER_WARNING);
        return;
    }

对恶意拼接的数学字符串进行过滤(漏洞利用POC格式其实也在这里写出来了,参考$regexp

1
$regexp = '/^(('.$number.'|'.$functionsOrVars.'|('.$functionsOrVars.'\s*\((?1)+\)|\((?1)+\)))(?:'.$operators.'(?2))?)+$/';

而在较低版本下,缺少过滤部分,进而导致RCE

并且,在tests/UnitTests/TemplateSource/ValueTests/Math/MathTest.php中,也有添加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
     * @expectedException PHPUnit_Framework_Error_Warning
     */
    public function testBackticksIllegal()
    {
        $expected = "22.00";
        $tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="`ls` x * y" x=$x y=$y}');
        $this->assertEquals($expected, $this->smarty->fetch($tpl));
    }

    /**
     * @expectedException PHPUnit_Framework_Error_Warning
     */
    public function testDollarSignsIllegal()
    {
        $expected = "22.00";
        $tpl = $this->smarty->createTemplate('eval:{$x = "4"}{$y = "5.5"}{math equation="$" x=$x y=$y}');
        $this->assertEquals($expected, $this->smarty->fetch($tpl));
    }

    /**
     * @expectedException PHPUnit_Framework_Error_Warning
     */
    public function testBracketsIllegal()
    {
        $expected = "I";
        $tpl = $this->smarty->createTemplate('eval:{$x = "0"}{$y = "1"}{math equation="((y/x).(x))[x]" x=$x y=$y}');
        $this->assertEquals($expected, $this->smarty->fetch($tpl));
    }
0%