0x00 漏洞概述
当遇到PHP文件包含漏洞时,如果找不到可以包含的文件,可以通过包含临时文件来GetShell。由于临时文件的文件名是随机的,如果目标网站存在phpinfo,则可以通过phpinfo来获取临时文件名,进而完成包含。
0x01 漏洞原理
在给PHP服务器POST数据包时,如果数据包含有文件区块,无论访问路径的代码是否具有处理文件上传的逻辑,PHP都会将这个区块(文件)保存为一个临时文件,通常位于/tmp/php[6个随机字符]。文件名可以在$_FILES
变量中找到。该临时文件会在请求结束后被删除。
因为phpinfo会将当前请求的上下文全部打印出来,所以如果向phpinfo页面发送包含文件区块的数据包,则可以在返回包找到$_FILES
变量的内容,自然也包含临时文件名。
实际情况下,文件包含漏洞和phpinfo通常来自于两个页面,理论上需要先发送给phpinfo页面,然后从返回包得到临时文件名,再将这个文件名发送给文件包含漏洞页面,进行GetShell。在第一个请求结束时,临时文件就被删除了,第二个请求自然无法完成文件包含。
此时需要用到条件竞争:
- 发送包含webshell的上传数据到phpinfo页面,这个数据包的header、get等位置充满了垃圾数据。
- 因为phpinfo页面会将所有数据打印出来,垃圾数据会将整个phpinfo页面过分填充。
- PHP默认的输出缓冲区大小为4096,可理解为PHP每次返回4096个字节给socket连接。直接操作原生socket,每次读取4096个字节,只要读取到的字符里包含临时文件名,就立即发送第二个数据包。
- 此时第一个数据包的socket连接还未结束,因为PHP还在继续每次输出4096个字节,所以临时文件此时还未被删除。
- 利用时间差完成包含临时文件,最终GetShell。
0x02 环境搭建
建立一个Docker项目,Apache部分直接依靠拉取,只需要编写三个文件。
执行
docker-compose up -d
等待完成即可。
~/docker-compose.yml
version: ‘2‘
services:
php:
image: php:7.2-apache
volumes:
- ./www:/var/www/html
ports:
- "8080:80"
~/www/lfi.php
即文件包含漏洞所在地。
<?php
include $_GET[‘file‘];
~/www/phpinfo.php
<?php
phpinfo();
0x03 利用流程
访问靶机
根目录为403。通过目录扫描等途径可得/phpinfo.php和/lfi.php。
访问/lfi.php,从报错信息可知服务端系统Linux、网站路径、include
函数。
由于不知道lfi.php所接受的参数名称,需要爆破一下。
得到参数名为file
。
EXP
使用优质EXP,需要Python2。
因为已知网站路径/var/www/html/,所以可以在Payload处做一点自定义(同时注意文件包含路径和phpinfo路径是否正确):
执行:
python exp.py 192.168.31.39 8080 100
连接
刚才自定了Payload中的文件路径,所以访问网站根目录的cmd.php即可。
大功告成!