红日代审Day2-filter_var函数缺陷
参考:https://github.com/hongriSec/PHP-Audit-Labs/blob/master/Part1/Day2/files/README.md
filter_var
1 | filter_var(mixed $value, int $filter = FILTER_DEFAULT, array|int $options = 0): mixed |
value
要过滤的内容。注意标量值在过滤前,会先转换成字符串。
filter
要应用的过滤器。可以使用
FILTER_VALIDATE_\*常量作为验证过滤器,使用FILTER_SANITIZE_\*或FILTER_UNSAFE_RAW作为清理过滤器,也可以使用FILTER_CALLBACK作为自定义过滤器。注意: 默认值为 **
FILTER_DEFAULT**,是FILTER_UNSAFE_RAW的别名。这将导致默认情况下不进行过滤。options
要么是选项的关联 array,要么是过滤器 flag 常量
FILTER_FLAG_\*的位掩码。 如果filter接受选项(option),则可以使用数组的"flags"字段提供 flag。返回值
成功时返回过滤后的数据。失败时返回 **
false**,除非使用FILTER_NULL_ON_FAILUREflag,在这种情况下会返回 **null**。
demo:
1 |
|
输出:
1 | string(15) "bob@example.com" |
第一个验证字符串
bob@example.com是否是有效的邮箱格式第二个验证字符串
https://example.com是否是有效的URL,并且要求必须包含路径
htmlspecialchars
1 | htmlspecialchars( |
字符替换:
| 字符 | 替换后 |
|---|---|
& (& 符号) |
& |
" (双引号) |
",除非设置了 ENT_NOQUOTES |
' (单引号) |
设置了 ENT_QUOTES 后, ' (如果是 ENT_HTML401) ,或者 &apos (如果是 **ENT_XML1**、 ENT_XHTML 或 ENT_HTML5)。 |
< (小于) |
< |
> (大于) |
> |
string待转换的 string。
flags位掩码,由以下某个或多个标记组成,设置转义处理细节、无效单元序列、文档类型。 默认是
ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401。
demo:
1 |
|
漏洞原理
demo:
这一关采用的php的一个模板引擎Twig,本题只要考察XSS(跨站脚本攻击)漏洞。虽然题目用了escape和filter_var过滤方法,但依然能被绕过。
在上图 第8行 中,程序使用 Twig 模板引擎定义的 escape 过滤器来过滤link,而实际上这里的 escape 过滤器,是用PHP内置函数 htmlspecialchars 来实现的
第二处过滤在 第17行 ,这里用了 filter_var 函数来过滤 nextSlide 变量,且用了 FILTER_VALIDATE_URL 过滤器来判断是否是一个合法的url
但这里可以利用javascript伪协议 来绕过,为了更好理解,举个例子:
我们使用payload:
1 | ?url=javascript://comment%250aalert(1) |
可以看到当点击链接时执行了alert函数
这是因为实际上这里的//在JavaScript中表示单行注释,所以后面的内容均为注释,那为什么会执行 alert 函数呢?那是因为我们这里用了字符 %0a ,该字符为换行符,所以 alert 语句与注释符 // 就不在同一行,就能执行。当然,这里我们要对 % 百分号编码成 %25 ,因为程序将浏览器发来的payload:javascript://comment%250aalert(1) 先解码成: javascript://comment%0aalert(1) 存储在变量 $url 中(上图第二行代码),然后用户点击a标签链接就会触发 alert 函数。
而且这里主要是由于PHP内置函数 htmlspecialchars 过滤,如果不过滤仅靠filter_var过滤很容易实现XSS:
CTF例题练习
环境搭建
1 | // index.php |
1 | // f1agi3hEre.php |
WP
审计代码发现filter_var和parse_url 两个函数用来过滤我们的url参数,我们需要通过url参数执行exec函数获得flag,但又需要url以sec-redclub.com结尾
绕过filter_var简单,只需要满足FILTER_VALIDATE_URL的url规则即可,这里提供几个绕过方法:
1 | http://localhost/index.php?url=http://demo.com@sec-redclub.com |
接着需要绕过parse_url,并且满足 $site_info[‘host’] 的值以 sec-redclub.com 结尾,payload如下:
1 | ?url=1://111111111@sec-redclub.com |
为了更好分析,我在源码添加了 var_dump($site_info);
带入命令执行:
1 | ?url=demo://";ls;#;sec-redclub.com:80/ |
先引号闭合前面的引号,然后命令执行,在注释掉后面的内容
当我们直接用 cat f1agi3hEre.php 命令的时候,过不了 filter_var 函数检测,因为包含空格,具体payload如下:
1 | http://localhost/index.php?url=demo://%22;cat%20f1agi3hEre.php;%23;sec-redclub.com:80/ |
所以我们可以换成 cat<f1agi3hEre.php 命令,即可成功获取flag:
1 | ?url=demo://%22;cat<f1agi3hEre.php;%23;sec-redclub.com:80/ |


















