file_put_contents利用技巧(php://filter协议)
Round 1
<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);
$content在开头增加了exit过程,导致即使我们成功写入一句话,也执行不了。幸运的是,这里的$_POST['filename']是可以控制协议的,我们即可使用 php://filter协议来施展魔法。
#方法一、base64编码
使用php://filter流的base64-decode方法,将$content解码,利用php base64_decode函数特性去除“死亡exit”。
众所周知,base64编码中只包含64个可打印字符(A-Z a-z 0-9 + /)'='补位,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。
所以,当$content被加上了<?php exit; ?>以后,我们可以使用 php://filter/write=convert.base64-decode 来首先对其解码。在解码的过程中,字符<、?、;、>、空格等一共有7个字符不符合base64编码的字符范围将被忽略,所以最终被解码的字符仅有“phpexit”和我们传入的其他字符。
“phpexit”一共7个字符,因为base64算法解码时是4个byte一组,所以给他增加1个“a”一共8个字符。这样,"phpexita"被正常解码,而后面我们传入的webshell的base64内容也被正常解码。结果就是<?php exit; ?>没有了。
最终效果:

#方法二、利用字符串操作方法+base64组合拳
除了使用base64特性的方法外,我们还可以利用php://filter字符串处理方法来去除“死亡exit”。我们观察一下,这个<?php exit; ?>实际上是什么?
实际上是一个XML标签,既然是XML标签,我们就可以利用strip_tags函数去除它,而php://filter刚好是支持这个方法的。
编写如下测试代码即可查看 php://filter/read=string.strip_tags/resource=php://input 的效果:
echo readfile('php://filter/read=string.strip_tags/resource=php://input');

可见,<?php exit; ?>被去除了。但回到上面的题目,我们最终的目的是写入一个webshell,而写入的webshell也是php代码,如果使用strip_tags同样会被去除。
万幸的是,php://filter允许使用多个过滤器,我们可以先将webshell用base64编码。在调用完成strip_tags后再进行base64-decode。“死亡exit”在第一步被去除,而webshell在第二步被还原。
最终效果:

#方法三、ROT13编码
原理和上面类似,核心是将“死亡exit”去除。<?php exit; ?>在经过rot13编码后会变成<?cuc rkvg; ?>,在PHP不开启short_open_tag时,php不认识这个字符串,当然也就不会执行了:

Round 2
<?php
$a = $_POST['txt'];
file_put_contents($a,"<?php exit();".$a);
这种是前后两个变量相同,假设$a可控情况。
这种相同变量的构造方式和不同变量的构造方式思路是大差不差的,都是需要干掉<?php exit();,只不过构造起来相对更复杂一些。
#方法一、base64编码
根据前面介绍的不同变量的构造方法,很容易拓展到相同的变量,同样利用php://filter来构造,反正后面是写入的内容,只要在后面解码的时候把shell解码出来,不需要的东西解码成乱码即可,而Base64构造的话,例如
$a=php://filter/write=convert.base64-decode|PD9waHAgcGhwaW5mbygpOz8+/resource=shell.php ( <?php phpinfo();?> base64编码 PD9waHAgcGhwaW5mbygpOz8+ )
构造的shell可以放在过滤器的位置和文件名位置都可以(其他编码有时候会有空格什么的乱码,文件名不一定好用),php://filter面对不可用的规则(一串base64)是报个Warning,绕后跳过继续执行的(不会退出),所以按理说这样构造是“很完美”的。我们看下base-decode哪些字符
php//filter/write=convertbase64decodePD9waHAgcGhwaW5mbygpOz8+/resource=shellphp
而默认情况下base64编码是以 = 作为结尾的,所以正常解码的时候到了 = 就解码结束了,即使我们构造payload的时候不用write=,但是在最后获取文件名的时候resource=中的 = 过不掉,所以导致过滤器解码失败,从而报错...
这里用base64编码我还没找到好的方法,待补充...
#方法二、ROT13
rot13编码就不存在base64的问题,所以和前面base64构造的思路一样
$a = php://filter/write=string.rot13|<?cuc cucvasb();?>/resource=shell.php


和前面提到的一样,这种方法是需要服务器没有开启短标签的时候才可以使用(默认情况是没开启的:php.ini中的short_open_tag)
#方法三、iconv字符编码转换
通过字符转换把<?php exit();转成不能解析的,这里采用的是UCS-2或者UCS-4编码方式,而我们构造的转成可正常解析的
#echo iconv("UCS-2LE","UCS-2BE",'<?php phpinfo();?>');
?<hp phpipfn(o;)>?
这里用的是UCS-2,当然我们也可以用UCS-4
echo iconv("UCS-4LE","UCS-4BE",'aa<?php phpinfo();?>');
?<aa phpiphp(ofn>?;)
通过UCS-2或者UCS-4的方式,对目标字符串进行2/4位一反转,也就是说构造的需要是UCS-2或UCS-4中2或者4的倍数,不然不能进行反转,那我们就可以利用这种过滤器进行编码转换绕过了,构造payload
$a='php://filter/convert.iconv.UCS-2LE.UCS-2BE|?<hp phpipfn(o;)>?/resource=shell.php'; **or** $a='php://filter/convert.iconv.UCS-4LE.UCS-4BE|xxx?<aa phpiphp(ofn>?;)/resource=shell.php';
#由于是4位一反转,所以需要保证?<aa phpiphp(ofn>?;)之前字符个数是4的倍数,所以补充了 xxx

#方法四、iconv字符编码转换+ROT13编码组合拳
和前后不同的变量的利用一样,相同变量一样可以使用组合拳,原因前面描述过了,就不赘述,这里就用UCS-2和rot13举一个例子吧
$a = 'php://filter/write=convert.iconv.UCS-2LE.UCS-2BE|string.rot13|x?<uc cucvcsa(b;)>?/resource=shell.php'
#先将 <?php phpinfo(); ?> 进行rot13得到<?cuc cucvasb();?>
#再对<?cuc cucvasb();?>进行UCS2编码转换得到?<uc cucvcsa(b;)>?
#最后x 补位
#最终得到x?<uc cucvcsa(b;)>?

为何不用string.strip_tags呢?因为rot13转换的同样会被strip_tags方法给删除了,而UCS-2或UCS-4构造的也同样会被strip_tags方法给删除,这里需要找其他的编码方式进行构造。
参考:
https://www.leavesongs.com/PENETRATION/php-filter-magic.html
https://mp.weixin.qq.com/s/BXBe0sviIpjzQb49fk1TCg
file_put_contents利用技巧(php://filter协议)的更多相关文章
- 利用maven的filter和profile实现不同环境使用不同的配制
在我们平常的java开发中,会经常使用到很多配制文件(xxx.properties,xxx.xml),而当我们在本地开发(dev),测试环境测试(test),线上生产使用(product)时,需要不停 ...
- UNIX网络编程——利用ARP和ICMP协议解释ping命令
一.MTU 以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节,将这个限制称作最大传输单元(MTU,Maximum Transmission Unit) ...
- 浅析PHP正则表达式的利用技巧
浅析PHP正则表达式的利用技巧 正则表达式是什么 正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串. 将匹配的子串替换 ...
- 利用ARP和ICMP协议解释ping命令
一.MTU 以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节,将这个限制称作最大传输单元(MTU,Maximum Transmission Unit).如果IP ...
- SSRF漏洞挖掘利用技巧
参考文章 SSRF漏洞(原理&绕过姿势) SSRF绕过方法总结 SSRF绕过IP限制方法总结 Tag: #SSRF Ref: 概述 总结 利用一个可以发起网络请求的服务当作跳板来攻击内部其他服 ...
- 利用Netty构建自定义协议的通信
在复杂的网络世界中,各种应用之间通信需要依赖各种各样的协议,比如:HTTP,Telnet,FTP,SMTP等等. 在开发过程中,有时候我们需要构建一些适应自己业务的应用层协议,Netty作为一个非常优 ...
- 利用KVC实现无需协议的委托模式
在<精通iOS开发>一书中看到的技巧.假设BIDTaskListController是一个列表,点击列表上的一项将会导航到BIDTaskDetailController,在BIDTaskD ...
- 利用vue写filter时 当传入是一个对象时注意
vue或angular 写filter时,传入的是对象时一定注意,不能直接改变对象的值,因为在使用该filter的页面上,若传入的对象其他值发生变化,该filter也会重新运行,这样可能会报错,如下例 ...
- php 利用http上传协议(表单提交上传图片 )
主要就是利用php 的 fsocketopen 消息传输. 这里先通过upload.html 文件提交,利用chrome抓包,可以看到几个关键的信息. 首先指定了表单类型为multipart/form ...
随机推荐
- MySQL高性能学习笔记
索引 何为索引?有什么作用? 索引是一种用于快速查询和检索数据的数据结构.常见的索引结构有: B 树, B+树和 Hash. 索引的作用就相当于目录的作用.打个比方: 我们在查字典的时候,如果没有目录 ...
- 降维处理PCA
要理解什么是降维,书上给出了一个很好但是有点抽象的例子. 说,看电视的时候屏幕上有成百上千万的像素点,那么其实每个画面都是一个上千万维度的数据:但是我们在观看的时候大脑自动把电视里面的场景放在我们所能 ...
- CentOS7编译安装升级openssh8.7p1
因生成环境服务器安全扫描出的漏洞问题,只能升级最新的openssh,适用于centos6和centos7的升级使用. 一.编译前工作 openssl版本要求1.0.1以上,zlib版本要求1.1.4以 ...
- Session、Session共享、Token演变
巨人的肩膀 深夜,我偷听到程序员要对session下手-- (qq.com)
- docker迁移工作目录
yum安装的docker 工作目录在系统盘,迁移到数据盘 首先需要停止docker服务 systemctl stop docker.service 通过命令df -h 先去看下磁盘大概的情况,找一个大 ...
- Linux下的Tmux分屏操作
Linux中,我们使用命令行的时候,一个窗口只能使用一个命令行,若是需要使用多个输入位置进行操作,那么只能多开几个窗口,今天介绍一款软件,可以让我们在一个窗口使用多个输入行,先来效果图展示下 Linu ...
- windev的弹窗详情页滚动条实现方法以及弹窗尺寸规划
按照企业信息系统的设计习惯,我们一般将信息以列表的方式在主窗口展现,同时设置需要展现的字段,一些系统会将这个窗口称为总表页.列表页等.而信息的编辑或完整信息的查询,一般通过一个弹窗来实现,一些系统会将 ...
- pycharm创建模板
用pycharm构造作者模板 模板,就是创建一个文件时自动生成模板内容. 这里用pycharm创建作者模板,步骤如下: File-->Settings Editor-->File and ...
- C语言字符串输入输出函数(gets()函数、puts()函数、fgets()函数、fputs()函数)
scanf("%s", str) 不能读取空白字符,遇到第一个空白字符就停止读取. gets(str) 读取整行输入,直至遇到换行符,丢弃换行符储存其余字符,并在末尾添加 \0.与 ...
- 【C# Parallel】ParallelLoopState
总结 总之,要编写一个健壮的并行循环,必须在并行循环体中检测 ParallelLoopState 对象的 IsExceptional, IsStopped 和 LowestBreakIteration ...