题目简介
-
题目名称:[HCTF 2018]WarmUp 1
-
题目平台:BUUCTF
-
题目类型:Web
-
考察知识点:
-
本地文件包含漏洞
解题步骤
1. 启动并访问靶机,前端只有一个滑稽的表情
2. 右击或F12审计一下代码,可以看到source.php,我们访问一下该页面
3. 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\" />"; } ?>
4. 可以看到include函数没有任何过滤措施,那么我们可以利用本地文件包含漏洞来访问任意文件,以获取flag,但是想要执行include函数,我们需要满足三个条件:
-
file不为空
-
file的值是字符串
-
file通过emmm类的checkFile方法校验
5. 第一和第二个条件都很简单,主要是第三个条件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\" />"; } ?>
6. 读懂了emmm类的代码后,我们需要构造file的值。本地文件包含漏洞的格式一般是file=../../../.../xxx
,其中../
的个数不固定,xxx为flag文件名,那么这个xxx具体是什么呢?我们尝试访问一下hint.php,发现提示:flag not here, and flag in ffffllllaaaagggg,可以猜测到服务器存放flag的文件名可能为ffffllllaaaagggg,我们可以构造的file=../ffffllllaaaagggg
,将其带入checkFile中看一下是否可以返回true。
7. 步骤一:因为我们定义了file的值且是string类型,所以第一个if 的return false 顺利绕过
if (! isset($page) || !is_string($page)) { echo "第一个if未通过"; eturn false; }
8. 步骤二:因为我们的file的值既不是souce.php也不是hint.php,所以是无法通过该if的,直接放弃这个return true的机会,继续往下看。
if (in_array($page, $whitelist)) { return true; }
9. 步骤三: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; }
10. 我们逐个添加../的个数,最终发现当file=source.php?../../../../../ffffllllaaaagggg
的时候,输出flag:flag{784155f9-68a0-4772-ac02-3eaa0105f3ac}
知识详解
一:php常见函数
-
isset:检测变量是否已声明并且其值不为 null
-
in_array:检查数组中是否存在某个值,第一个参数为待搜索的值,第二个参数为要搜索的数组
-
is_string:检测变量是否是字符串
-
empty:检查一个变量是否为空
-
$_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]
请登录之后再进行评论