[HCTF 2018]WarmUp 1 【文件包含漏洞】
·
题目简介
- 题目名称:[HCTF 2018]WarmUp 1
- 题目平台:BUUCTF
- 题目类型:Web
- 考察知识点:
- 代码审计
- 本地文件包含漏洞
解题步骤
- 启动并访问靶机,前端只有一个滑稽的表情

- 右击或F12审计一下代码,可以看到source.php,我们访问一下该页面

- 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\" />";
}
?>
- 可以看到include函数没有任何过滤措施,那么我们可以利用本地文件包含漏洞来访问任意文件,以获取flag,但是想要执行include函数,我们需要满足三个条件:
- file不为空
- file的值是字符串
- file通过emmm类的checkFile方法校验
- 第一和第二个条件都很简单,主要是第三个条件checkFile方法的校验规则非常麻烦,我们先来逐行解释一emmm类每一行代码的作用:
<?php
highlight_file(__FILE__);
class emmm
{
//$page前面加&代表引用,这里是引用传递
public static function checkFile(&$page)
{
//定义whitelist数组
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
//如果page变量未声明或为null,或者不是字符串,则进入if
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
//如果page的值在$whitelist数组里则进入if
if (in_array($page, $whitelist)) {
return true;
}
//截取从0到?首次出现的位置的字符串
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?') //点在php中用来连接两个字符串或变量,此代码意思为拼接page和?的值,并返回?字符首次出现的位置
);
//如果_page的值在$whitelist数组里则进入if
if (in_array($_page, $whitelist)) {
return true;
}
//对page解码
$_page = urldecode($page);
//截取从0到?首次出现的位置的字符串
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
//如果_page的值在$whitelist数组里则进入if
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
//如果file变量为空 且 是字符串 且 通过checkFile 校验,则进入if
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\" />";
}
?>
- 读懂了emmm类的代码后,我们需要构造file的值。本地文件包含漏洞的格式一般是
file=../../../.../xxx,其中../的个数不固定,xxx为flag文件名,那么这个xxx具体是什么呢?我们尝试访问一下hint.php,发现提示:flag not here, and flag in ffffllllaaaagggg,可以猜测到服务器存放flag的文件名可能为ffffllllaaaagggg,我们可以构造的file=../ffffllllaaaagggg,将其带入checkFile中看一下是否可以返回true。 - 步骤一:因为我们定义了file的值且是string类型,所以第一个if 的return false 顺利绕过
if (! isset($page) || !is_string($page)) {
echo "第一个if未通过";
eturn false;
}
- 步骤二:因为我们的file的值既不是souce.php也不是hint.php,所以是无法通过该if的,直接放弃这个return true的机会,继续往下看。
if (in_array($page, $whitelist)) {
return true;
}
- 步骤三:mb_substr会将file的值通过一定的规则截取后,再次放入if判断,那么我们可以在file的值前面主动拼接一个
souce.php?或者hint.php?,也就是file=source.php?../ffffllllaaaagggg,通过mb_substr截取后的值是souce.php,此时checkFile返回true
//截取从0到?首次出现的位置的字符串
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?') //点在php中用来连接两个字符串或变量,此代码意思为拼接page和?的值,并返回?字符首次出现的位置
);
//如果_page的值在$whitelist数组里则进入if
if (in_array($_page, $whitelist)) {
return true;
}
- 我们逐个添加…/的个数,最终发现当
file=source.php?../../../../../ffffllllaaaagggg的时候,输出flag:flag{784155f9-68a0-4772-ac02-3eaa0105f3ac}
知识详解
一:php常见函数
- isset:检测变量是否已声明并且其值不为 null
- in_array:检查数组中是否存在某个值,第一个参数为待搜索的值,第二个参数为要搜索的数组
- is_string:检测变量是否是字符串
- empty:检查一个变量是否为空
- R E Q U E S T : _REQUEST: REQUEST:_REQUEST可以获取以POST方法和GET方法提交的数据
- mb_strcut() :根据 start 和 length 参数返回 str 的一部分
- mb_strpos():查找字符串在另一个字符串中首次出现的位置
- urldecode(): 解码已编码的 URL 字符串
- include():包含并运行指定文件
- include_once() :include_once 表达式和 include 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含
- require() :require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时脚本会中止,而include会继续运行。
- require_once():require_once 表达式和 require 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。
二:文件包含漏洞
文件包含漏洞
漏洞原因:
- php代码中使用了文件包含函数
- 文件包含函数参数可以自定义且没有经过过滤
漏洞分类:
- 本地文件包含漏洞(LFI):指包含本地服务器中的文件
- 格式:
?file=../../../xxxx
- 格式:
- 远程文件包含漏洞(RFI):指包含远程服务器中的文件
- php.ini中的allow_url_fopen = On和 allow_url_include = On 时,才可以利用该漏洞
- 格式:
?file=http://xxxx.xxx/xxxx
- php中引发文件包含漏洞的通常是以下四个函数:
- include():包含并运行指定文件
- include_once() :include_once 表达式和 include 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含
- require() :require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时脚本会中止,而include会继续运行。
- require_once():require_once 表达式和 require 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。
- 当利用这四个函数来包含文件时,不管文件是什么类型(图片、txt等等),都会直接作为php文件进行解析。[1]
参考资料
分享网络安全学习笔记和CTF真题详解,更多内容欢迎大家关注公众号:【张甲】
更多推荐
所有评论(0)