php文件包含
Last updated on September 27, 2024 am
一个php文件包含另一个php文件,可以提升代码的复用性。
若包含不当会导致安全漏洞。
php常见的文件包含函数
1 | |
require 包含文件遇到错误时,程序就不会继续往下执行了。
include包含文件遇到错误时,程序还可以继续往下执行。读到不存在的目录仍然能路径穿越,1?/../../flag
文件包含会先将文件的内容读出来,如果包含的文件内容是php代码则会解析成php,如果不是则原样输出,和文件的后缀名无关。
php本地文件包含
直接指定服务器的文件进行包含
无限制
1 | |
可以通过绝对路径或者伪协议进行文件包含
前面限制
1 | |
只能利用路径穿越进行文件包含
利用/etc/passwd进行测试,有回显说明是无限制,无回显说明有限制,可以用../../etc/passwd进行路径穿越,确定根目录
有一道远程文件包含限制前缀为https://www\.php\.net,(HCERT CTF)
1 | |
利用payload:?f=flag.php&url=https://www.php.net/cached.php?f=cached.php(包含cached.php这个文件后进行文件读取)
后面限制
限制后缀名
可以使用伪协议中的php://filter、phar://、zip://来进行rce
php get-shell方式
思路:将php代码植入主机中,再使php代码得到解析
1.利用文件上传
上传php代码,例如
1 | |
2.利用中间件日志文件
例如当请求
1 | |
这个请求会保存在日志中,通过文件包含日志文件,则可解析植入的php代码
3.ssh日志文件包含
利用ssh协议去连接主机,例如
1 | |
代码将被当成用户名保存在/var/log/auth.log中,利用文件包含即可
pearcmd.php
pecl是PHP中用于管理扩展而使用的命令行工具,而pear是pecl依赖的类库。在7.3及以前,pecl/pear是默认安装的;在7.4及以后,需要我们在编译PHP的时候指定--with-pear才会安装。
在Docker任意版本镜像中,pcel/pear都会被默认安装,安装的路径在/usr/local/lib/php。
利用条件:存在pearcmd.php,可以利用文件包含测试。
1.写文件getshell poc
1 | |
再访问/tmp/hello.php
2.下载文件 poc
1 | |
将木马写好放在vps上,再利用pearcmd.php将文件下载到靶机getshell。
https://www.leavesongs.com/PENETRATION/docker-php-include-getshell.html
文件包含被限制后缀时可以尝试pearcmd
1 | |
条件:
- 安装了pear
- 开启了register_argc_argv
用bp发包,get 需要用短标签
1 | |
访问/evil.php
register_argc_argv与include to RCE的巧妙组合
php远程文件包含
需要php.ini中配置allow_url_include=On
利用协议远程包含文件
被包含的文件需要放在有公网ip的主机上
可用的协议有HTTP、FTP、SMB、Webdav等
漏洞攻击伪协议利用方法
可以利用伪协议的函数:include(),file_get_contens(),highlight_file(),file_exists()
file://
file://用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响
1 | |
file:// [文件的绝对路径和文件名]
example:http://localhost:37917/?page=file:///var/www/html/phpinfo.php
php://input
需要allow_url_include=On
对于HTTP请求中Content-Type:multipart/form-data是无效的
php://input是PHP的输入流,获取POST的所有数据(把要传的数据写在post中)
data://
需allow_url_include=On
传入数据的协议
1 | |
php://filter
需要开启allow_url_fopen
对读到的文件内容进行处理
常见的过滤器
1 | |
除了用php:filter来读取文件还可以用来写入文件
以明文方式写入
1 | |
编码写入
1 | |
base64解码特点
base64编码中只包含64个可打印字符,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。
可以使用 php://filter/write=convert.base64-decode 来先解码去除base64中没有的字符,在编码得到新的字符。
死亡exit绕过
1 | |
写入的语句在执行前先执行了exit退出了。
base64
通过php://filter的base64-decode来绕过
1 | |
前面加一个a的原因:phpexit共7个字符,base64算法解码时是4个byte一组,所以给他增加1个a一共8个字符。phpexita被正常解码,后面传入的websehll也能够正常解码。
rot13
1 | |
相邻两位反转
1 | |
1 | |
https://www.leavesongs.com/PENETRATION/php-filter-magic.html
https://xiaolong22333.top/archives/114/
filterchain绕过
(本地文件包含)无需可控文件
原理
利用本地已有的固定文件内容
convert.iconv 将数据从字符集 A 转换为字符集 B
基于PHP Base64 Filter 宽松的解析,通过编码再解码去除多余的不可见字符构造webshell
字符转换例子
1 | |
利用base64去除不可见字符例子
1 | |
利用https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT/tree/main 来生成字母对应的字符编码(与要用的本地文件内容无关)
使用方法(linux系统)
在test.py中修改要写入的命令的base64编码(注意:base64编码后不能含有+ / =等,有的话可以通过加空格或者后面补一些垃圾字符来消除)
运行test.py,将结果中resource=后面的内容换成本地文件,如果不能文件内容是中文,需要先用php://filter/convert.base64-encode/resource= 进行转换,相当于两次php://filter
https://github.com/synacktiv/php_filter_chain_generator 这个工具就直接一把梭(base64所有字符都支持)
1 | |
https://tttang.com/archive/1395/#toc_php-base64-filter
受php filter链影响的函数(都要通过post传参才可)
| Function | Pattern |
|---|---|
| *file_get_contents* | file_get_contents($_POST[0]); |
| *readfile* | readfile($_POST[0]); |
| *finfo->file* | $file = new finfo(); $fileinfo = $file->file($_POST[0], FILEINFO_MIME); |
| *getimagesize* | getimagesize($_POST[0]); |
| *md5_file* | md5_file($_POST[0]); |
| *sha1_file* | sha1_file($_POST[0]); |
| *hash_file* | hash_file('md5', $_POST[0]); |
| *file* | file($_POST[0]); |
| *parse_ini_file* | parse_ini_file($_POST[0]); |
| *copy* | copy($_POST[0], '/tmp/test'); |
| *file_put_contents (only target read only with this)* | file_put_contents($_POST[0], ""); |
| *stream_get_contents* | $file = fopen($_POST[0], "r"); stream_get_contents($file); |
| *fgets* | $file = fopen($_POST[0], "r"); fgets($file); |
| *fread* | $file = fopen($_POST[0], "r"); fread($file, 10000); |
| *fgetc* | $file = fopen($_POST[0], "r"); fgetc($file); |
| *fgetcsv* | $file = fopen($_POST[0], "r"); fgetcsv($file, 1000, ","); |
| *fpassthru* | $file = fopen($_POST[0], "r"); fpassthru($file); |
| *fputs* | $file = fopen($_POST[0], "rw"); fputs($file, 0); |
phar://
1 | |
例如
1 | |
/tmp/a.zip表示要解析的压缩包,与扩展名无关,可以是/tmp/a.jpg等
文件操作函数都会触发phar反序列化
phar结合文件上传进行反序列利用
(要将php.ini中的phar.readonly选项设置为Off才能生成phar文件)
基础操作
1 | |
会将内容写到1.phar中
加GIF89a
1 | |
1 | |
1 | |
phar重签名
如果修改了.phar里面的内容则需要对phar进行重签名
1 | |
过滤
- 不能是phar开头
1 | |
1 | |
- 过滤__HALT_COMPILER
进行压缩就可以绕过__HALT_COMPILER
zip://
1 | |
压缩文件要用绝对路径,#要url编码%23,同样与压缩包的扩展名无关
本地文件包含需要能进行文件上传,压缩包需要先上传到主机
glob://
1 | |
DirectoryIterator与glob://结合将无视open_basedir(这个是限制php脚本能够访问的文件路径)
1 | |
本文作者: fru1ts
本文链接: https://fru1ts.github.io/2023/07/07/php%E6%96%87%E4%BB%B6%E5%8C%85%E5%90%AB/
版权声明: 本站均采用BY-SA协议,除特别声明外,转载请注明出处!