0x1 php中与包含有关的函数
php中一共有4个文件包含相关的函数,分别为:
include 如果未找到文件,发出警告,继续执行。
require 如果未找到文件,发出致命错误,停止执行。
include_once 与include相同,只包含一次。
require_once 与require相同,只包含一次。
0x2 支持的协议和封装协议
- file:// —访问本地文件系统
- http:// — 访问 HTTP(s) 网址
- ftp:// — 访问 FTP(s) URLs
- php:// — 访问各个输入/输出流
- zlib:// — 压缩流
- data:// — 数据(RFC 2397)
- glob:// — 查找匹配的文件路径模式
- phar:// — PHP 归档
- ssh2:// — Secure Shell 2
- rar:// — RAR
- ogg:// — 音频流
- expect:// — 处理交互式的流
其中需要注意的是伪协议,如下:
-
file://
此协议默认目录是当前的工作目录。 /path/to/file.ext 等价于file://path/to/file.ext
-
php://
(1)php://input
可以访问请求的原始数据的只读流。
(2)php://filter
是一种元封装器, 设计用于数据流打开时的筛选过滤应用。
使用例子:
- php://filter/resource=<待过滤的数据流>
readfile("php://filter/resource=http://www.example.com");这简单等同于:readfile("http://www.example.com"); 实际上没有指定过滤器
- php://filter/read=<读链需要应用的过滤器列表>
这个参数采用一个或以管道符 | 分隔的多个过滤器名称。
/* 这会以大写字母输出 www.example.com 的全部内容 */
readfile("php://filter/read=string.toupper/resource=http://www.example.com");
/* 这会和以上所做的一样,但还会用 ROT13 加密。 */
readfile("php://filter/read=string.toupper|string.rot13/resource=http://www.example.com");
- php://filter/write=<写链需要应用的过滤器列表>
这个参数采用一个或以管道符 | 分隔的多个过滤器名称。
/* 这会通过 rot13 过滤器筛选出字符 "Hello World"
然后写入当前目录下的 example.txt */
file_put_contents("php://filter/write=string.rot13/resource=example.txt","Hello World");
0x3 ctf中关于包含的漏洞
-
包含漏洞特征:
?page=a.asp
? home=b.html
? file=content -
通过构造含有漏洞的语句,查看想要看的代码
file=php://filter/read=convert.base64-encode/resource=index.php -
?action=xxx&mode=xxx(文件夹加上文件名)
源码:include($action.'/'.$mode.'.php');
伪协议包含形式:?action=php://filter/read-convert.base64-encode/resource=./&mode=login -
绕过方法
?f=php://filter/read=convert.base64-encode/resource=1.jpg/resource=./show.php(正则 /resource=*.jpg/i)
?f=data:text/plain,<?php phpinfo()?>
?file=data:text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
借鉴Thinking师傅整理的手册:
0x4 getshell思路
-
文件自包含getshell
我们可以通过上传文件在tmp目录生成临时的缓存文件,如果在这个过程中,让php崩溃(通过文件自包含,让php奔溃),导致没有把这个缓存文件删除,就可以让缓存文件一直留在tmp目录。如果这个时候存在一个文件包含的漏洞,就可以达到getshell的目的。
-
默认phpstudy安装环境下实现getshell
默认安装的时候是没有开启日志记录功能的也就是不存在 access.log,但是默认存在php error log。我们通过访问不存在的带有payload文件,然后access.log就会写入payload,直接包含access.log来getshell。