PHP代码审计——Day2-Twig

前置知识 - Twig

Twig是一个PHP模板引擎,它提供了一种更简洁和可扩展的方法来创建PHP应用程序的视图层。Twig模板引擎旨在将设计与业务逻辑分离,并为开发人员提供一种更加清晰和易于维护的方式来构建网页。

使用前提:在PHP项目中安装,然后引入Twig的自动加载文件

composer require twig/twig

require_once 'vendor/autoload.php';

基本配置示例:

$loader = new \Twig\Loader\FilesystemLoader('path/to/templates');
$twig = new \Twig\Environment($loader, [
    'cache' => 'path/to/cache',
    'debug' => true,
]);

使用FilesystemLoader来加载模板文件。将path/to/templates替换为你实际的模板目录。配置中的cache参数指定Twig编译后的缓存目录,debug参数设置为true可以使Twig在有错误时输出更详细的错误信息。

漏洞解析

// composer require "twig/twig"
require 'vendor/autoload.php';

class Template {
  private $twig;

  // 初始化 Twig 环境并加载模板
  public function __construct() { 
    $indexTemplate = '<img ' .
      'src="https://loremflickr.com/320/240">' .
      '<a href="{{link|escape}}">Next slide &raquo;</a>';

    // Default twig setup, simulate loading
    // index.html file from disk
    $loader = new Twig\Loader\ArrayLoader([
      'index.html' => $indexTemplate
    ]);
    $this->twig = new Twig\Environment($loader);
  }

  // 从 $_GET 中获取名为 nextSlide 的参数,并通过 filter_var 函数验证为一个有效的 URL,并返回该URL
  public function getNexSlideUrl() {
    $nextSlide = $_GET['nextSlide'];
    return filter_var($nextSlide, FILTER_VALIDATE_URL);
  }

  // 渲染模板,将下一张幻灯片的链接作为参数传递给 Twig 模板引擎,然后输出渲染后的 HTML 内容
  public function render() {
    echo $this->twig->render(
      'index.html',
      ['link' => $this->getNexSlideUrl()]
    );
  }
}

(new Template())->render();

考察点:xss漏洞

代码中使用了escapefilter_var两个过滤方法,但还是可以被绕过,程序使用 Twig 模板引擎定义的 escape 过滤器来过滤link,而实际上这里的 escape 过滤器,是用PHP内置函数 htmlspecialchars 来实现的

{{link|escape}}
这是twig自带的过滤器,在twig的文档中我们可以知道它是通过PHP的htmlspecialchars来实现的,他会将特殊字符转换为 HTML 实体。

htmlspecialchars函数:(PHP 4, PHP 5, PHP 7) 将特殊字符转换为 HTML 实体

定义 :string htmlspecialchars ( string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string$encoding = ini_get("default_charset") [, bool $double_encode = TRUE ]]] )

& (& 符号)  ===============  &amp;
" (双引号)  ===============  &quot;
' (单引号)  ===============  &apos;
< (小于号)  ===============  &lt;
> (大于号)  ===============  &gt;

filter_var: (PHP 5 >= 5.2.0, PHP 7) 使用特定的过滤器过滤一个变量

定义 :mixed filter_var ( mixed $variable [, int $filter = FILTER_DEFAULT [, mixed $options ]] )

过滤函数,有一些常用的过滤器类型及对应的预定义变量:

  • FILTER_VALIDATE_EMAIL:验证是否为有效的电子邮件地址。
  • FILTER_VALIDATE_URL:验证是否为有效的URL。
  • FILTER_VALIDATE_IP:验证是否为有效的IP地址。
  • FILTER_SANITIZE_STRING:去除字符串中的 HTML 和 PHP 标记。
  • FILTER_SANITIZE_NUMBER_INT:去除字符串中的所有字符,除了数字和符号。

绕过方法

使用JavaScript伪协议绕过

<a href="javascript:;">这个标签中的javascript是啥意思?</a>

// href 属性的值可以是任何有效文档的相对或绝对 URL,包括片段标识符和 JavaScript 代码段。
// 这里的href=”javascript:;”,其中javascript:是伪协议,它可以让我们通过一个链接来调用javascript函数。
// javascript:是表示在触发<a>默认动作时,执行一段JavaScript代码

demo测试

<?php
  $url = filter_var($_GET['url'], FILTER_VALIDATE_URL);
  var_dump($url);
  $url = htmlspecialchars($url);
  var_dump($url);
  echo "<a href='$url'>Next slide~~</a>";
?>

构造payload:?url=javascript://comment%250aalert(1);

  • 这里的 // 在JavaScript中表示单行注释,所以后面的内容均为注释
  • 字符 %0a 为换行符,所以 alert 语句与注释符 // 就不在同一行,就能执行
  • 这里我们要对 % 百分号编码成 %25 ,因为程序将浏览器发来的payload:javascript://comment%250aalert(1) 先解码成: javascript://comment%0aalert(1) 存储在变量 $url 中,然后用户点击a标签链接就会触发 alert 函数。

修复建议

对于XSS漏洞,最好过滤关键词,将特殊字符进行HTML实体编码替换

参考文章

https://xz.aliyun.com/t/2457?time__1311=n4%2BxnieDqQqWwqCwx0v%2Bb%2BoitrGQkQetKz4D&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fu%2F10394%3Fpage%3D2
https://lanvnal.com/2020/02/19/rips-php-security-calendar-2017-xue-xi-ji-lu/#toc-heading-2

posted @ 2024-04-02 09:43  smile_2233  阅读(124)  评论(0编辑  收藏  举报