[HCTF 2018]Warmup
按f12显示有/source.php
访问之后会显示源代码:
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
可以先看到有hint.php
访问一下:
提示了我们flag在ffffllllaaaagggg
文件中
这题涉及了in_array()
、mb_substr()
、mb_strpos()
、include
函数
先来介绍一下这四个函数
in_array() 函数
in_array() 函数搜索数组中是否存在指定的值。
in_array(search, array, type)
如果 search 参数是字符串且 type 参数被设置为 TRUE,则搜索区分大小写。 type 如果第三个参数设置为 true,函数只有在元素存在于数组中且数据类型与给定值相同时才返回 true。如 果没有在数组中找到参数,函数返回 false。
mb_substr()函数
mb_substr() 函数返回字符串的⼀部分,之前我们学过 substr() 函数,它只针对英⽂字符,如果要分割的中⽂⽂字则需 要使⽤ mb_substr()。
mb_substr(string $str,int $start[,int $length =NULL [, string $encoding=mb_internal_encoding() ]] ) :
string
参数及描述:
<?php
echo mb_substr("你好呀", 0, 2);
// 输出:你好
?>
mb_strpos()函数
mb_strpos():返回要查找的字符串在别⼀个字符串中⾸次出现的位置。
mb_strpos(
string $haystack,
string $needle,
int $offset = 0,
string $encoding = mb_internal_encoding()
): int
返回 string 的 haystack 中 needle ⾸次出现位置的数值。 如果没有找到 needle,它将返回 false。
<?php
$str = 'http://www.baidu.com';
echo mb_strpos($str,'bai');
?>
//11
<?php
header("Content–type:text/html;chartset=utf-8");
$str = '你好,早上吃啥了';
echo mb_strpos($str,'早上');
?>
//3
include函数
寻找包含⽂件的顺序先是在当前⼯作⽬录的相对的 include_path下寻找,然后是当前运⾏脚本所在⽬录相 对的 include_path 下寻找。例如 include_path 是 .,当前⼯作⽬录是 /www/,脚本中要 include ⼀个 include/a.php 并且在该⽂件中有⼀句 include “b.php”,则寻找 b.php 的顺序先是 /www/,然后是 /www/include/。如果⽂件名以 ./ 或者 …/ 开始,则只在当前⼯作⽬录相对的 include_path 下寻找。
即,当include后的文件找不到且有路径时,会沿此路径一直找,直到找到文件 即,当include后的文件找不到且有路径时,会沿此路径一直找,直到找到文件
所以首先白名单就说明了我们必须要要利用hint.php
或者source.php
文件来进行文件读取,而且我们传入的需要是一个字符串
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
这段代码的意思是代码首先在$page字符串末尾加上一个问号,然后使用mb_strpos()函数查找该字符串中第一个问号的位置,返回的位置是问号在字符串中的索引值。由于在末尾加上问号后,如果$page字符串本身没有问号,mb_strpos()函数会返回false,因此这个函数的返回值还需要进行一次判断。
接着,代码使用mb_substr()函数从$page字符串的开头截取到第一个问号的位置之前的所有字符,即获取了URL路径部分,并将其赋值给$_page变量。
最终的效果就是,将$page字符串中的URL路径部分提取出来,用于后续的处理和判断。需要注意的是,如果$page字符串本身就是一个URL路径,且没有问号,那么$_page变量将会和$page变量的值相同。
则到达checkfile处的:
我们发现想要在第A个if处,就return ture 并且找到flag是不可能的
在第B个if处,经过前一步的mb_substr,_page变为 hint.php,所以return ture;
然后因为找不到,hint.php?,于是沿着路径四次返回上一层文件后访问ffffllllaaaaggg,找到了flag
为什么我们会写出/…/…/…/…/ffffllllaaaagggg这个路径的,一个一个试呗
最后的payload:
1.source.php?file=hint.php%253f/../../../../../../ffffllllaaaagggg
2.source.php?file=hint.php?/../../../../ffffllllaaaagggg
3.source.php?file=hint.php%3f/../../../../ffffllllaaaagggg