由filter_var()函数引起的技术探讨

0x01 起因

最近在看PHP SECURITY CALENDAR 2017的题目,这是第二题

Day 2 - Twig

Can you spot the vulnerability?

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

class Template {
  private $twig;

  public function __construct() {
    $indexTemplate = '' .
      'Next slide »';

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

  public function getNexSlideUrl() {
    $nextSlide = $_GET['nextSlide'];
    return filter_var($nextSlide, FILTER_VALIDATE_URL);
  }

  public function render() {
    echo $this->twig->render(
      'index.html',
      ['link' => $this->getNexSlideUrl()]
    );
  }
}

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

这里考察的是XSS漏洞。对于XSS漏洞,大部分出现的地方在输出环节,如 echo $var; $var可控且无过滤,或者过滤不严格,导致了XSS漏洞的产生。

而在这里,XSS的出现是因为标签内的code过滤不严格,导致可利用javascript伪协议绕过。

0x02 分析

代码不长,首先来通读下整段代码。 这是一个Template的类的定义,类的内部定义了三个函数函数,分别为construct()、getNexSlideUrl()以及render()。

construct()主要实现了模板载入,getNexSlideUrl()主要实现了URL过滤识别,render()则主要是实现了传入URL的功能。函数的功能并不复杂,关键点在于两个过滤函数:

  • twig的escape过滤器
  • filter_var()的URL判断

对于twig的escape过滤器,可以见官网的说明:

escape uses the PHP native htmlspecialchars function for the HTML escaping strategy.

其实也就是将htmlspecialchars包装到了escape的过滤器中,换了个使用方式,真正起作用的,还是htmlspecialchars函数

htmlspecialchars(string,flags,character-set,double_encode)

由filter_var()函数引起的技术探讨_第1张图片

由filter_var()函数引起的技术探讨_第2张图片

我们都知道htmlspeciachars的主要作用就是将特殊字符转换为 HTML 实体,这一方法不但可以在一定程度上防止SQL,也可以在一定程度上防止XSS。

但是有些xss并不需要特殊字符。 再来看看filter_var():

filter_var(variable, filter, options)

由filter_var()函数引起的技术探讨_第3张图片

filter_var($nextSlide, FILTER_VALIDATE_URL);

将获取的nextSlide值传入filter_var()函数中,然后判断其是否符合URL的相关规则。 这里的URL的判断就很有意思,有很多绕过判断的方式,有兴趣的朋友可以自行谷歌。 但是这里考虑到htmlspecicalchars,因此对于单双引号以及尖括号的payload都不考虑。

官方给的解答是:

?nextSlide=javascript://comment%250aalert(1)

NextSlide传入的值为

javascript://comment%250aalert(1)

如果将这个值echo出来,结合标签,就会产生xss,具体流程如下: 首先传入到标签内:

Next slide »

//为注释符,%25为百分号,%与0a组成为换行符
最终单独生成一行为alert(1),成功执行了alert函数

由filter_var()函数引起的技术探讨_第4张图片

0x03 实例

// index.php

You have curl {$site_info['host']} successfully!