PHP代码审计02之filter_var()函数缺陷

前言

根据红日安全写的文章,学习PHP代码审计审计的第二节内容,题目均来自PHP SECURITY CALENDAR 2017,讲完这个题目,会有一道CTF题目来进行巩固,外加一个实例来深入分析,想了解上一篇的内容,可以点击这里:PHP代码审计01之in_array()函数缺陷
下面我们开始分析。

漏洞分析

下面来看第一题,代码如下:

'.
            'Next slide »';
            
         $loader = new Twig\Loader\ArrayLoader([
             'index.html'=>$indexTemplate
         ]);
         $this->twig = new Twig\Environment($loader);
    }

    public function getNexSlideUrl(){
        $nexSlide = $_GET['nexSlide'];
            //这里是第二次过滤
        return filter_var($nexSlide,FILTER_VALIDATE_URL);
    }

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

这一关用的是PHP的一个模板引擎Twig,考察的是XSS漏洞,也就是跨站脚本攻击。虽然程序使用了escape和filter_var()两个过滤方法,但是。还是可以被绕过的。下面我们看第一处过滤,在上面代码的第10行,使用Twig模板引擎定义的escape过滤器来过滤link。而escape过滤器默认情况下,它使用HTML转义策略,也就是escape将PHP本机htmlspecialchars函数用于HTML转义策略,现在我们看一下PHP手册,htmlspecialchars函数是如何定义的。
PHP代码审计02之filter_var()函数缺陷_第1张图片
其实就是把一些预定义字符转换成HTML实体。具体看下表:
PHP代码审计02之filter_var()函数缺陷_第2张图片
下面我们来看第二处过滤,是在上面代码第20行,是用filter_var()来进行过滤,下面我们来看看PHP手册对这个函数的定义:
PHP代码审计02之filter_var()函数缺陷_第3张图片
具体参数设置如下表:
PHP代码审计02之filter_var()函数缺陷_第4张图片
上面代码是用了FILTER_VALIDATE_URL,把值作为 URL 来验证。这个函数过滤其他的参数设置说明,如下:

  • FILTER_CALLBACK:调用用户自定义函数来过滤数据。
  • FILTER_SANITIZE_STRING:去除标签,去除或编码特殊字符。
  • FILTER_SANITIZE_STRIPPED:”string” 过滤器的别名。
  • FILTER_SANITIZE_ENCODED:URL-encode 字符串,去除或编码特殊字符。
  • FILTER_SANITIZE_SPECIAL_CHARS:HTML 转义字符 ‘”<>& 以及 ASCII 值小于 32 的字符。
  • FILTER_SANITIZE_EMAIL:删除所有字符,除了字母、数字以及 !#$%&’*+-/=?^_{|}~@.[]
  • FILTER_SANITIZE_URL:删除所有字符,除了字母、数字以及 $-_.+!*'(),{}|\^~[]<>#%”;/?&=
  • FILTER_SANITIZE_NUMBER_INT:删除所有字符,除了数字和 +-
  • FILTER_SANITIZE_NUMBER_FLOAT:删除所有字符,除了数字、+- 以及 .,eE。
  • FILTER_SANITIZE_MAGIC_QUOTES:应用 addslashes()。
  • FILTER_UNSAFE_RAW:不进行任何过滤,去除或编码特殊字符。
  • FILTER_VALIDATE_INT:在指定的范围以整数验证值。
  • FILTER_VALIDATE_BOOLEAN:如果是 “1”, “true”, “on” 以及 “yes”,则返回 true,如果是 “0”, “false”, “off”, “no” 以及 “”,则返回 false。否则返回 NULL。
  • FILTER_VALIDATE_FLOAT:以浮点数验证值。
  • FILTER_VALIDATE_REGEXP:根据 regexp,兼容 Perl 的正则表达式来验证值。
  • FILTER_VALIDATE_URL:把值作为 URL 来验证。
  • FILTER_VALIDATE_EMAIL:把值作为 e-mail 来验证。
  • FILTER_VALIDATE_IP:把值作为 IP 地址来验证。

通过对两个过滤器的了解,我们想想该如何绕过呢?,其实,这里可以通过JavaScript伪协议来绕过,为了更好的理解,这里写一小段简单的代码。

$url = filter_var($_GET['url'],FILTER_VALIDATE_URL);
var_dump($url);
$url = htmlspecialchars($url);
var_dump($url);
echo "测试一下";

下面我们构造payload,用JavaScript伪协议来绕过,payload为:javascript://test%250aalert(1),然后执行如下图:
PHP代码审计02之filter_var()函数缺陷_第5张图片
其实上面payload中,//后面的内容全是注释的内容,那为什么还是会被执行呢?因为在上面的payload用了%0a,%进行了编码,成了%25,这是换行符,所以执行了咱们的弹窗。

CTF练习

通过上面的分析,是不是对filter_var()函数有了一定的了解呢,让咱们用一道CTF的题目来巩固一下吧。这道题也是因为filter_var被绕过,导致命令执行。看下面代码。

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