php 文件包含漏洞

正文索引 [隐藏]

解题过程

题目名称:flag 在 index 里

进去之后一个页面:

1565665621150

那点一下叭:

1565665643253

哦哦哦, 题目名称提示说 flag 在 index 里面,那把 show.php 改成 index.php 试一下

1565666121874

1565666146893

。。。。没卵用,还刷出来一堆 titile,有猫腻,经查阅资料,在读取HTML、PHP等文件时可能会抛出此类错误parser error : StartTag: invalid element name 。其原因是,PHP是基于标签的脚本语言,<?php ... ?>这个语法也与XML相符合,所以在解析XML的时候会被误认为是XML,而其中内容(比如特殊字符)又有可能和标准XML冲突,所以导致了出错。那么,为了读取包含有敏感信息的PHP等源文件,我们就要先将“可能引发冲突的PHP代码”编码一遍,这里就会用到php://filter,作用是作为一个“中间流”来处理其他流,将PHP等容易引发冲突的文件流用php://filter协议流处理一遍,能有效规避特殊字符造成混乱,这道题就利用这一点:

1565682513000

这样就能得到 index.php 的页面啦,不过得 base64 解一下码,得到如下内容:

'<html>\r\n    <title>Bugku-ctf</title>\r\n    \r\n<?php\r\n\terror_reporting(0);\r\n\tif(!$_GET[file]){echo \'<a href="./index.php?file=show.php">click me? no</a>\';}\r\n\t$file=$_GET[\'file\'];\r\n\tif(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){\r\n\t\techo "Oh no!";\r\n\t\texit();\r\n\t}\r\n\tinclude($file); \r\n//flag:flag{edulcni_elif_lacol_si_siht}\r\n?>\r\n</html>\r\n'

其实就是 index.php 的代码内容啦,flag 在注释里面,整理一下是这样的:

<?php
error_reporting(0);
if(!$_GET[file]){
    echo '<a href="./index.php?file=show.php">click me? no</a>';
}
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
    echo "Oh no!";
    exit();
}
include($file); 
//flag:flag{edulcni_elif_lacol_si_siht}
?>

2333,flag 是 include else if local is shit。。。。命题人很皮啊

知识储备:文件包含

1. 文件包含简介

这个和 C 中的 include 啊、python 中的 import 啊比较像,可以通过 include 加载另一个文件中的 PHP 代码并执行,有以下几种:

require();
require_once();
include();
include_once();

includerequire区别主要是,include在包含的过程中如果出现错误,会抛出一个警告,程序继续正常运行;而require函数出现错误的时候,会直接报错并退出程序的执行。

include_once()require_once()这两个函数,与前两个的不同之处在于这两个函数只包含一次,适用于在脚本执行期间同一个文件有可能被包括超过一次的情况下,想确保它只被包括一次以避免函数重定义,变量重新赋值等问题。

2. 漏洞产生的原因

包含函数加载的参数未经过滤或严格定义,可能导致被恶意利用,比如这样的:

<?php
    $filename = $_GET['filename'];
    include($filename);
?>

这种就非常危险,可以构造一些非常骚气的 filename 进行攻击

3. 本地文件包含漏洞

就是上面列举的,最为骚气,可以为所欲为:

<?php
    $filename = $_GET['filename'];
    include($filename);
?>

直接看一下 /etc/passwd

1565678006377

4. 远程文件包含漏洞

PHP的配置文件allow_url_fopen和allow_url_include设置为ON,include/require等包含函数可以加载远程文件,如果远程文件没经过严格的过滤,导致了执行恶意文件的代码:

<?php
    $filename  = $_GET['filename'];
    include($filename);
?>

危害巨大,可以在自己的机子上写个php,开启 http 服务后在靶机上执行

5. 文件名限制

有时候会加上一个文件类型限制,就比较烦啦,如下:

<?php
    $filename = $_GET['filename'];
    include($filename.'.html');
?>

这个时候再用之前那一招就不好使了,这时可以用简单的截断 %00:

截断的核心,就是chr(0)这个字符,先说一下这个字符,这个字符不为空(Null),也不是空字符(“”),更不是空格。当程序在输出含有chr(0)变量时,chr(0)后面的数据会被停止,换句话说,就是误把它当成结束符,后面的数据直接忽略,这就导致漏洞产生

可以构造 filename = /etc/passwd%00 解决

但是!现在这个基本上不会出现了。。。原因是:

  1. php版本小于5.3.4
  2. php的magic_quotes_gpc为OFF状态

    emmmmm,基本上无效了,需要考虑一些其他骚气的绕过

6. PHP 伪协议

PHP 带有很多内置 URL 风格的封装协议,可用于类似 fopen()、 copy()、 file_exists() 和 filesize() 的文件系统函数。 除了这些封装协议,还能通过 stream_wrapper_register() 来注册自定义的封装协议,支持的协议如下:

1565679748210

1. php://filter

本地磁盘文件进行读取

用法:

  • ?filename=php://filter/convert.base64-encode/resource=xxx.php

  • ?filename=php://filter/read=convert.base64-encode/resource=xxx.php

条件:只是读取,需要开启 allow_url_fopen,不需要开启 allow_url_include;

这个东西的应用场景是这样的:

<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

exit 简直恶心,管你 post 啥都执行不了,这时候就要 php://filter 上场了,基本思路是:使用php://filter 流的 base64-decode 方法,将$content解码,由于 base64 是只包含 a-z 0-9 -A-Z + / 的编码形式,所以解码过程中会抛弃其他的字符,所以,一个正常的base64_decode实际上可以理解为如下两个步骤:

<?php
$_GET['txt'] = preg_replace('|[^a-z0-9A-Z+/]|s', '', $_GET['txt']);
base64_decode($_GET['txt']);
?>

所以,当$content被加上了<?php exit; ?>以后,我们可以使用 php://filter/write=convert.base64-decode 来首先对其解码。在解码的过程中,字符<、?、;、>、空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有“phpexit”和我们传入的其他字符。

“phpexit”一共7个字符,因为base64算法解码时是4个byte一组,所以给他增加1个“a”一共8个字符。这样,"phpexita"被正常解码,而后面我们传入的经过 base64 编码的内容也被正常解码,这样就绕过了 exit

2. php://input

读取 POST 没有经过解析数据,注意enctype=”multipart/form-data” 时是无效的。

用法:?file=php://input 数据利用POST传过去,

条件:开启 allow_url_fopen 和 allow_url_include(PHP < 5.30)

<?php
    $filename = $_GET['filename'];
    include($filename);
?>

还是用最简单的例子,一目了然1565680432073

参考文章:

https://www.leavesongs.com/PENETRATION/php-filter-magic.html

https://bbs.pediy.com/thread-247844.htm