php://filter是PHP中独有的协议,利用这个协议可以创造很多“妙用”,本文说几个有意思的点,剩下的大家自己下去体会。

XXE中的使用

php://filter之前最常出镜的地方是XXE。由于XXE漏洞的特殊性,我们在读取HTML、PHP等文件时可能会抛出此类错误parser error : StartTag: invalid element name 。其原因是,PHP是基于标签的脚本语言,<?php ... ?>这个语法也与XML相符合,所以在解析XML的时候会被误认为是XML,而其中内容(比如特殊字符)又有可能和标准XML冲突,所以导致了出错。

那么,为了读取包含有敏感信息的PHP等源文件,我们就要先将“可能引发冲突的PHP代码”编码一遍,这里就会用到php://filter。

php://filter是PHP语言中特有的协议流,作用是作为一个“中间流”来处理其他流。比如,我们可以用如下一行代码将POST内容转换成base64编码并输出:

readfile("php://filter/read=convert.base64-encode/resource=php://input");

如下:

所以,在XXE中,我们也可以将PHP等容易引发冲突的文件流用php://filter协议流处理一遍,这样就能有效规避特殊字符造成混乱。

如下,我们使用的是php://filter/read=convert.base64-encode/resource=./xxe.php

巧用编码与解码

使用编码不光可以帮助我们获取文件,也可以帮我们去除一些“不必要的麻烦”。

记得前段时间三个白帽有个比赛,其中有一部分代码大概类似于以下:

<?php
$content = '<?php exit; ?>';
$content .= $_POST['txt'];
file_put_contents($_POST['filename'], $content);

$content在开头增加了exit过程,导致即使我们成功写入一句话,也执行不了(这个过程在实战中十分常见,通常出现在缓存、配置文件等等地方,不允许用户直接访问的文件,都会被加上if(!defined(xxx))exit;之类的限制)。那么这种情况下,如何绕过这个“死亡exit”?

幸运的是,这里的$_POST['filename']是可以控制协议的,我们即可使用 php://filter协议来施展魔法:使用php://filter流的base64-decode方法,将$content解码,利用php base64_decode函数特性去除“死亡exit”。

众所周知,base64编码中只包含64个可打印字符,而PHP在解码base64时,遇到不在其中的字符时,将会跳过这些字符,仅将合法字符组成一个新的字符串进行解码。

所以,一个正常的base64_decode实际上可以理解为如下两个步骤:

<?php
$_GET['txt'] = preg_replace('|[^a-z0-9A-Z+/]|s', '', $_GET['txt']);
base64_decode($_GET['txt']);

所以,当$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不认识这个字符串,当然也就不会执行了:

当然,这个方法的条件就是不开启短标签。

【转】浅谈php://filter的妙用的更多相关文章

  1. 谈一谈php://filter的妙用

    php://filter是PHP中独有的协议,利用这个协议可以创造很多"妙用",本文说几个有意思的点,剩下的大家自己下去体会.本来本文的思路我上半年就准备拿来做XDCTF2016的 ...

  2. 浅谈UI设计中妙用无穷的深色系背景

    英文:medium 译者:优设网 - 陈子木 链接:http://www.uisdc.com/ui-benefits-of-dark-background# --------------------- ...

  3. 浅谈HTML5单页面架构(一)——requirejs + angular + angular-route

    心血来潮,打算结合实际开发的经验,浅谈一下HTML5单页面App或网页的架构. 众所周知,现在移动Webapp越来越多,例如天猫.京东.国美这些都是很好的例子.而在Webapp中,又要数单页面架构体验 ...

  4. 浅谈五大Python Web框架

    转载:http://feilong.me/2011/01/talk-about-Python-web-framework 说到Web Framework,Ruby的世界Rails一统江湖,而Pytho ...

  5. MVC5-11 浅谈拦截器

    Filter拦截器 Aop是MVC的主要设计方式之一,而微软也希望我们在使用MVC的时候更好的使用拦截器来进行切面编程.拦截器则是Mvc中的一大亮点与重点 AOP(面向切面)编程已经广泛应用在各个项目 ...

  6. [转]浅谈Python web框架

    说到web framework,Ruby的世界Rails一统江湖,而Python则是一个百花齐放的世界,各种micro-framework.framework不可胜数,不完全列表见:http://wi ...

  7. [C#]6.0新特性浅谈

    原文:[C#]6.0新特性浅谈 C#6.0出来也有很长一段时间了,虽然新的特性和语法趋于稳定,但是对于大多数程序猿来说,想在工作中用上C#6.0估计还得等上不短的一段时间.所以现在再来聊一聊新版本带来 ...

  8. 浅谈一下SSI+Oracle框架的整合搭建

    浅谈一下SSI+Oracle框架的整合搭建 最近换了一家公司,公司几乎所有的项目都采用的是Struts2+Spring+Ibatis+Oracle的架构,上一个东家一般用的就是JSF+Spring,所 ...

  9. 车大棒浅谈jQuery源码(二)

    前言 本来只是一个自己学习jQuery笔记的简单分享,没想到获得这么多人赏识.我自己也是傻呵呵的一脸迷茫,感觉到受宠若惊. 不过还是有人向批判我的文章说,这是基本知识点,完全跟jQuery源码沾不上边 ...

随机推荐

  1. MariaDB数据表操作实例

    1. MariaDB 数据库操作实例 MariaDB>create database class; //创建class数据库 MariaDB>use class; MariaDB>c ...

  2. Linux下查看端口,强制kill进程

    1.查看8088端口被哪个进程占用:netstat -apn | grep 8088 2.强制kill某一进程:kill -s 9 1827

  3. 2018.09.01 09:08 Genesis

    Nothing to think about, I don't know where to start, the mastery of learning is not an easy task, yo ...

  4. 联想笔记本BIOS设置中文详解

    对于很多新装系统的小伙伴们 可能很多都不是太懂BIOS中都是干什么用的,小编这里给大家详细介绍一下 联想笔记本的主板BIOS设置跟别的笔记本或许有些不同但大体相差不多,和大家分享一下. BIOS介绍 ...

  5. 用AOP拦截自定义注解并获取注解属性与上下文参数(基于Springboot框架)

    目录 自定义注解 定义切面 获取上下文信息JoinPoint ProceedingJoinPoint 定义测试方法 测试结果 小结 AOP可以用于日志的设计,这样话就少不了要获取上下文的信息,博主在设 ...

  6. [python]关于列表增加元素的几种操作

    1.insert方法,该方法包含两个参数,第一个参数为插入的位置参数,第二个参数为插入内容 a = [0,0,0] b = [1,2,3] a.insert(0,b) print a 输出: [[1, ...

  7. JS强制刷新页面、清除缓存刷新

    清理网站缓存的几种方法 meta方法 <meta http-equiv="pragma" content="no-cache"> <meta ...

  8. __init__函数

    初始化函数,类似于c++的构造函数 在创建一个对象时默认被调用,不需要手动调用.self后面接的形参,在类实例化的时候必须传递,__init__函数里的参数都属于成员变量

  9. 一兄弟把/etc/init.d/functions误删除了,这是多么悲催的节奏啊;

    RPM resource /lib/lsb/init-functions /lib/lsb/init-functions vs. /etc/init.d/functions in init scrip ...

  10. lua连接redis集群

    连接redis集群需要用到llua-resty-redis-cluster模块 github地址:https://github.com/cuiweixie/lua-resty-redis-cluste ...