[红日安全]代码审计Day2 - filter_var函数缺陷
字数 1606 2025-08-18 11:37:33
PHP代码审计:filter_var函数缺陷与XSS漏洞利用
1. 概述
本文基于红日安全团队的代码审计Day2内容,详细分析PHP中filter_var函数的缺陷以及如何利用这些缺陷绕过安全防护实现XSS攻击。
2. 漏洞背景
2.1 示例代码分析
原始漏洞代码来自PHP Security Calendar 2017中的Twig题目:
// 使用Twig模板引擎的escape过滤器过滤link
$link = $twig->escape($link);
// 使用filter_var函数验证URL
if (filter_var($nextSlide, FILTER_VALIDATE_URL)) {
// 处理URL
}
2.2 双重过滤机制
-
第一重过滤:使用Twig的
escape过滤器,底层实现为PHP的htmlspecialchars函数- 转换特殊字符为HTML实体
- 默认配置转换:
&,",',<,>
-
第二重过滤:使用
filter_var函数配合FILTER_VALIDATE_URL过滤器- 验证变量是否为合法URL
- 但不保证URL内容的安全性
3. 绕过技术分析
3.1 JavaScript伪协议绕过
有效payload:
?nextSlide=javascript://comment%250aalert(1)
绕过原理:
-
URL解码过程:
- 原始payload:
javascript://comment%250aalert(1) - 解码后:
javascript://comment%0aalert(1)
- 原始payload:
-
JavaScript解释:
//表示单行注释%0a是换行符的URL编码,使alert(1)在新行执行- 百分号编码
%25确保%0a能正确传递
3.2 filter_var函数缺陷
FILTER_VALIDATE_URL仅验证URL格式,不验证内容安全性- 接受
javascript:伪协议作为合法URL - 对URL中的编码字符处理不严格
4. 实际案例分析:Anchor CMS 0.9.2
4.1 漏洞位置
themes/default/404.php中的404错误处理页面:
<code><?php echo current_url(); ?></code>
4.2 漏洞链分析
-
current_url()函数调用链:function current_url() { return Uri::current(); } -
Uri::current()方法:- 调用
static::detect()获取当前URI - 使用
filter_var($uri, FILTER_SANITIZE_URL)过滤
- 调用
-
关键问题:
FILTER_SANITIZE_URL仅移除非法URL字符- 不进行XSS防护
- 不过滤
<script>等危险标签
4.3 漏洞利用
Payload构造:
http://localhost/anchor/index.php/<script>alert('www.sec-redclub.com')</script>
利用过程:
- 访问不存在的URL触发404页面
current_url()获取并输出恶意脚本- 脚本在受害者浏览器执行
5. 防御措施
5.1 输入验证强化
-
对URL协议进行白名单验证:
if (!preg_match('/^https?:\/\//i', $url)) { die('Invalid URL protocol'); } -
结合
parse_url()分析URL结构:$parts = parse_url($url); if ($parts['scheme'] !== 'http' && $parts['scheme'] !== 'https') { die('Invalid URL scheme'); }
5.2 输出编码
-
对所有动态内容进行HTML实体编码:
echo htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8'); -
在上下文中使用适当的编码:
- HTML属性:
htmlspecialchars($var, ENT_QUOTES) - JavaScript:
json_encode($var) - URL:
urlencode($var)
- HTML属性:
5.3 安全函数使用建议
- 避免单独依赖
filter_var进行安全验证 - 结合多种过滤方法:
$url = filter_var($input, FILTER_SANITIZE_URL); if (filter_var($url, FILTER_VALIDATE_URL)) { $parts = parse_url($url); // 额外验证 }
6. CTF题目分析
6.1 题目代码
// index.php
<?php
$url = $_GET['url'];
if(isset($url) && filter_var($url, FILTER_VALIDATE_URL)){
$site_info = parse_url($url);
if(preg_match('/sec-redclub.com$/',$site_info['host'])){
exec('curl "'.$site_info['host'].'"', $result);
echo "<center><h1>You have curl {$site_info['host']} successfully!</h1></center>
<center><textarea rows='20' cols='90'>";
echo implode(' ', $result);
} else{
die("<center><h1>Error: Host not allowed</h1></center>");
}
}else{
echo "<center><h1>Just curl sec-redclub.com!</h1></center><br>
<center><h3>For example:?url=http://sec-redclub.com</h3></center>";
}
?>
// f1agi3hEre.php
<?php $flag = "HRCTF{f1lt3r_var_1s_s0_c00l}"?>
6.2 解题思路
- 利用
filter_var的URL验证缺陷 - 绕过主机名验证
sec-redclub.com$ - 可能的攻击向量:
- 使用
@符号:http://evil.com@sec-redclub.com - 使用子域名:
http://xxx.sec-redclub.com.evil.com - 利用URL解析差异
- 使用
7. 总结
filter_var函数的安全过滤器不能单独依赖- JavaScript伪协议是常见的绕过手段
- URL验证需要结合多种方法和严格的白名单
- 输出编码是防御XSS的最后防线
- 安全应该采用纵深防御策略,多层防护
通过本文的分析,开发者应该更加谨慎地使用PHP的过滤函数,并理解其局限性,在实际开发中实施更全面的安全措施。