PHP代码审计之WEB安全系列基础文章(十三)之SSTI篇

【如需转载,请详细表明来源,请勿设置原创】

嗨,大家好,我是闪石星曜CyberSecurity创始人Power7089。

欢迎大家扫描下方二维码关注 “闪石星曜CyberSecurity” 公众号,这里专注分享渗透测试,Java代码审计,PHP代码审计等内容,都是非常干的干货哦。

公众号

今天为大家带来PHP代码审计基础系列文章第十三篇之SSTI篇

这是【炼石计划@PHP代码审计】知识星球第二阶段的原创基础系列文章,拿出部分课程分享给零基础的朋友学习。本系列原创基础文章涵盖了PHP代码审计中常见的十余种WEB漏洞,是匹夫老师精心的创作,欢迎关注我的公众号跟着一起学习。

【炼石计划@PHP代码审计】是一个系统化从入门到提升学习PHP代码审计的成长型知识星球。这里不仅注重夯实基础,更加专注实战进阶。强烈推荐加入我们,一起来实战提升PHP代码审计。

公众号

PHP代码审计之SSTI模板注入

1.SSTI模板注入原理

SSTI(Server-Side Template Injection)服务器模板注入也是注入的一种类型,它的原理与SQL注入有些类似,SQL注入是从前端获取用户输入,然后通过后端代码带到数据库中进行查询来执行我们想要执行的SQL语句。SSTI也是一样的,从前端获取参数值,然后在后端进行渲染处理时进行语句拼接执行。

由于如今大部分框架都是基于MVC模式进行开发的,我们的输入通过 V(view) 接收,交给 C(controller) ,然后由 C 调用M(model) 或者其他的 C 进行处理,最后再返回给 V ,这样就最终显示在我们的面前了,那么这里的 V 中就大量的用到了一种叫做模板的技术,而凡是使用模板的地方都有可能存在模板注入。

1.1 PHP常见模板引擎

1
2
3
4
5
6
7
8
9
10
11
12
Smarty

Smarty算是一种很老的PHP模板引擎了,非常的经典,使用的比较广泛。

Twig

Twig是来自于Symfony的模板引擎,它非常易于安装和使用。它的操作有点像Mustache和liquid。

Blade

Blade 是 Laravel 提供的一个既简单又强大的模板引擎。
和其他流行的 PHP 模板引擎不一样,Blade 并不限制你在视图中使用原生PHP代码。所有Blade视图文件都将被编译成原生的PHP代码并缓存起来,除非它被修改,否则不会重新编译,这就意味着 Blade基本上不会给你的应用增加任何额外负担。

1.2 模板引擎payload格式

1
2
3
4
5
6
7
8
9
10
11
12
Smarty
{php}echo `id`;{/php} //在smarty 3.X中废弃
{}
{literal} //PHP5中适用
{if}{/if}

Twig
{{2*3}}

Blade
{{}}
{!! !!}

2.SSTI相关函数

在PHP中如果使用了如上所述的模板引擎,在这些模板引擎之中分别利用不同的模板函数进行模板的渲染,如果函数中存在可控参数,那么很大概率会存在SSTI模板注入,下面我们通过介绍上述不同的模板引擎来引出引擎中的SSTI相关函数。

Twig

Twig是一款灵活、快速、安全的PHP模板引擎。

如果你接触过其他基于文本的模板语言,比如 Smarty、Django、或者Jinja,你便能轻松掌握Twig。它坚持PHP的原则,并为模板环境添加了有用的功能,使其同时保持对设计师和开发者友好。

Twig由一个灵活的词法分析器和解析器驱动。这使得开发者可以自定义标签和过滤器,并创建自己的DSL。

Twig已被用于许多开源项目,比如Symfony, Drupal8, eZPublish,phpBB, Piwik, OroCRM;并且许多框架也支持它,例如Slim, Yii, Laravel, Codeigniter and Kohana。

安装

将源码(https://github.com/twigphp/Twig/tree/v1.16.1)放置phpstudy中www目录下,并在phpstudy下创建网站让其解析。

image-20220831160140363

image-20220831160413977

代码示例:

在根目录下创建test.php代码用于测试代码是否正常运行。

Twig 首先使用一个加载器 Twig_Loader_Array 来定位模板,然后使用一个环境变量 Twig_Environment 来存储配置信息。其中, render() 方法通过其第一个参数载入模板,并通过第二个参数中的变量来渲染模板。

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
require_once 'lib/Twig/Autoloader.php';
Twig_Autoloader::register();

$loader = new Twig_Loader_Array(array(

'index' => 'Hello {{ name }}!',

));

$twig = new Twig_Environment($loader);

echo $twig->render('index',array('name'=>'World'));

模板加载成功

image-20220831145255803

Twig 模板注入也是发生在直接将用户输入作为模板,比如下面的代码:

这里我们需要渲染的内容用户可控,所以存在以下利用方式。

1
2
3
4
5
6
7
8
9
10
<?php

include 'lib/Twig/Autoloader.php';
Twig_Autoloader::register();

$loader = new Twig_Loader_String();

$twig = new Twig_Environment($loader);
echo $twig->render($_GET['name']);
?>

在Twig 1.X版本中有三个全局变量

image-20220831162331031

这里主要就是利用 _self 变量,它会返回当前 \Twig\Template 实例,并提供了指向 Twig_Environmentenv 属性,这样我们就可以继续调用 Twig_Environment 中的其他方法,从而进行 SSTI。

getFilter 里发现了危险函数 call_user_func。通过传递参数到该函数中,我们可以调用任意 PHP 函数。

image-20220831164011992

通过调用registerUndefinedFilterCallback()函数调用回调函数传入call_user_func()来执行命令

image-20220831164257740

paylaod如下:

1
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("calc")}}

image-20220831163649132

Twig 2.X、3.X中也存在相应的模板注入问题,感兴趣的同学们可以学习一下先知社区的这篇文章:

https://xz.aliyun.com/t/10056#toc-14

Smarty

Smarty 是 PHP 的模板引擎,有助于将表示 (HTML/CSS) 与应用程序逻辑分离。

在 3.X<3.1.42 和4.X< 4.0.2 版本之前,攻击者可以通过制作恶意数学字符串来运行任意 PHP 代码。

如果数学字符串作为用户提供的数据传递给数学函数,则外部用户可以通过制作恶意数学字符串来运行任意 PHP 代码。

安装

将源码(https://github.com/twigphp/Twig/tree/v1.16.1)放置phpstudy中www目录下,并在phpstudy下创建网站让其解析,与上面Twig部署方式类似。

我们可以直接使用其demo中的代码进行漏洞演示,如果大家想创建自己的demo,必须在自己的文件夹下创建cache,config,templates,templates_c四个文件夹。

image-20220831211127926

手动创建demo1文件夹,文件夹下相应创建如下目录以及文件

image-20220831213616544

我们来看一下smarty.inc.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
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>common</title>
</head>

<body>
<?php
include_once "../libs/Smarty.class.php"; //第一步要包含Smarty类文件
$smarty = new Smarty(); //实例化Smarty类


//文件夹名字可自定义
$smarty->joined_config_dir="./config"; //设置配置目录(非必选)
$smarty->cache_dir="./caches"; //设置缓存目录
$smarty->caching=true; //打开缓存
$smarty->cache_lifetime=1; //设置缓存时间
$smarty->joined_template_dir="./templates"; //设置模板目录
$smarty->compile_dir = "./templates_c"; //设置编译目录
$smarty->cache_dir = "./smarty_cache";

?>
</body>
</html>

网站主页index.php中代码如下:

$smarty->assign(‘value’,’Hello World’);的意思为用Hello World替代模板文件index.tpl里面的value字段的位置,也就是一个替换操作,具体等会看index.tpl文件就明白。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>index</title>
</head>

<body>
<?php
include "./smarty.inc.php"; //包含smarty.inc.php配置文件
$smarty->assign('value','Hello World'); //将变量value赋值为hello world

$smarty->display('index.tpl'); //这里的index.tpl文件名要与index.php文件名相对应
?>

</body>

</html>

templates文件夹下创建index.tpl文件

image-20220831215831723

代码如下:

1
2
3
4
5
6
7
8
9
10
11
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>hello</title>
</head>

<body>
Hi~{$value}!
</body>
</html>

将value替换为我们上述的Hello World。

image-20220831220435680

如果这里**displa()**函数中我们的内容可控就会造成模板注入。

image-20220831234541547

这里name传入XSS payload

image-20220831230902465

3.SSTI漏洞利用

这里我们用一道CTF靶场来进行SSTI模板注入漏洞的演示:

地址:https://buuoj.cn/challenges(注册登录即可)

image-20220831231051546

该题使用了Smarty模板,那么大概率和Smarty模板注入有关了。

image-20220831231134140

在页面的右上角显示了IP地址,猜测可能是通过Smarty模板获取IP地址并通过渲染显示在前端,我们可以尝试该处获取IP地址处是否可控。

image-20220831231353341

很明显这里的IP地址是从XFF获取,且直接通过display()进行渲染输入。

image-20220831231652608

可通过**{$smarty.version}**探测smarty版本为3.1.30

image-20220831232539092

这里我们可以通过{if php代码}{/if}的形式在{if}标签中执行任意PHP代码。

image-20220831232901648

4.SSTI模板注入代码审计总结

1
在PHP的中很多地方都使用到了模板去渲染文件,SSTI在PHP中不仅应用在上述所说的一些模板引擎中,在很多例如ThinkPHP、CMS中的一些自定义模板引擎中都可能存在SSTI注入。在代码审计中要多去关注一些视图模板的功能点,在这些功能点处在去观察渲染时的参数是否可控。如果遇到上述引擎模板要重点去查看对应模板的利用方式从而进行针对性的利用。

PHP代码审计之WEB安全系列基础文章(十三)之SSTI篇
http://example.com/2022/10/10/PHP代码审计之WEB安全系列基础文章(十三)之SSTI篇/
作者
Power7089
发布于
2022年10月10日
许可协议