题目
<?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__);
}
?>
思路
背景知识
-
$_SERVER['PHP_SELF']
和$_SERVER['REQUEST_URI']
-
$_SERVER['PHP_SELF']
:返回当前脚本的路径部分(不包括查询字符串)。例如,对于 URLhttps://www.shawroot.cc/php/index.php/test/foo?username=root
,它的值是/php/index.php/test/foo
。 -
$_SERVER['REQUEST_URI']
:返回完整的请求 URI(包括路径和查询字符串)。例如,对于上述 URL,它的值是/php/index.php/test/foo?username=root
。
-
basename()
函数
-
basename()
函数用于提取路径中的文件名部分。例如:php 深色版本 basename('/path/to/file/utils.php'); // 输出 'utils.php'
-
在某些语言环境设置下,
basename()
会删除文件名开头的非 ASCII 字符(如%ff
或中文字符),这可以用来绕过正则表达式过滤。
-
正则表达式过滤
-
第一个正则表达式:
preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])
它的作用是检测$_SERVER['PHP_SELF']
是否以utils.php/
或utils.php
结尾。如果匹配成功,则退出程序。 -
第二个正则表达式:
preg_match('/show_source/', $_SERVER['REQUEST_URI'])
它的作用是检测$_SERVER['REQUEST_URI']
是否包含字符串show_source
。如果匹配成功,则退出程序。
-
URL 编码
-
URL 编码是一种将特殊字符转换为百分号格式(如
%ff
)的方式。在某些情况下,未解码的参数可以通过正则表达式过滤。
漏洞分析
1. 绕过第一个正则表达式
-
正则表达式:
preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])
-
漏洞点:
basename()
函数的行为 -
解析:
-
当我们构造 URL 为
/index.php/utils.php/%ff
时:-
$_SERVER['PHP_SELF']
的值为/index.php/utils.php/%ff
。 -
basename($_SERVER['PHP_SELF'])
的结果会因为%ff
被删除而变为utils.php
。 -
因此,尽管原始路径包含
utils.php
,但由于%ff
的存在,正则表达式无法匹配到utils.php
,从而绕过了过滤。
-
2. 绕过第二个正则表达式
-
正则表达式:
preg_match('/show_source/', $_SERVER['REQUEST_URI'])
-
漏洞点:URL 编码未被解码。
-
解析:
-
当我们构造 URL 参数为
?%73how_source=1
或?%73%68%6f%77%5f%73%6f%75%72%63%65=1
时:-
%73
是s
的 URL 编码,%68
是h
的 URL 编码,以此类推。 -
$_SERVER['REQUEST_URI']
获取到的是未解码的参数值,因此正则表达式无法匹配到字符串show_source
。
-
EXP
-
构造 URL 为:
/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