文章目录

  • ​​写在前面​​
  • ​​关于php://filter的处理的一些简单解释​​
  • ​​php://filter常规流程分析​​
  • ​​关于exp的分析​​
  • ​​题外话​​

写在前面

慢慢不太想写博客了,很多东西都忙不过来,学的很多,今天抽出空来还是督促自己写一篇,灵感来源于刚刚在网上看到的一篇wp,https://xz.aliyun.com/t/10446,不得不说现在比赛可真多哈,小伙伴们也别太经常打,多做点实际的东西

关于php://filter的处理的一些简单解释

这里面呢,有几个比较关键的,一个是需要能获取到文件流(也就是我们后面常常写的resource=xxx.txt),另一个是可选的,就是是否使用其他的编码过滤器,有了这两个东西我们就能配合伪协议去做一些神奇的东西了

php://filter常规流程分析

大家在网上看的最多的也是​​php://filter/read=convert.base64-encode/resource=1.php​​​ 那它发生了什么,我们具体来看看,在​​ext\standard\php_fopen_wrapper.c#php_stream_url_wrap_php​​下一个断点

前六个是​​php://​​没毛病,指针移六位

[PHP底层]关于php://filter的分析_文件流

接下来,由于是filter我们进入分支

[PHP底层]关于php://filter的分析_赋值_02


给pathdup赋值,内容是指针向右移动六位后,也就是​​/read=convert.base64-decode/resource=1.php​

[PHP底层]关于php://filter的分析_php_03

接下来开始准备获取文件流了,上图可以看到获取从​​/resource​​​开始的字符串,因此p就是​​/resource=1.php​​​ 接下来比较重要的地方是从指针+10的地方,也就是​​1.php​​当中获取文件流(至于为什么加10,那是因为​​/resource=​​长度是10)

[PHP底层]关于php://filter的分析_赋值_04

跟进去,这里有一个zend_resolve_path的函数,这个支持用目录穿越的方式进行拼接组合路径,如这个函数名所说,会重新连接返回你一个绝对路径,这里就不带大家更深入为什么了,简单来说会获取你当前的目录路径再与1.php拼接后返回一个绝对路径,当然记住我说的支持路径穿越这很重要,这很重要

[PHP底层]关于php://filter的分析_文件流_05

之后让​​*p​​​值为​​\0​​​,也就是当前指针指向位置赋值为​​\0​​​,我们知道c中字符串结尾是​​\0​​,因此不难想到这就是简单的清空字符串,接着对其重新赋值

[PHP底层]关于php://filter的分析_php_06

因为这个​​php_strtok_r​​​函数跟进去以后比较复杂,那我简单搜索一下​​php_strtok_r​​,虽然没搜到但看这个能猜到意思是用于分割字符串,结合后面的while可以看出,是一个不断遍历分割后字符串的过程

[PHP底层]关于php://filter的分析_php_07


接下来,由于是​​read=​​​开头进入下面​​php_stream_apply_filter_list​​​函数,当然说一个题外话,这里不需要​​read=​​​或者​​write=​​​都行,php自己会判断,也就是为什么有第三个分支​​else​​了

[PHP底层]关于php://filter的分析_文件流_08


进去后又是这个函数,但结合后面不难猜到,这按照​​|​​分隔符创建多个过滤器

[PHP底层]关于php://filter的分析_赋值_09


现在整个流程也清楚了

关于exp的分析

可以看到exp为​​php://filter/resource=./convert.base64-decode/../1.php​​,理解了我上面的过程,这个exp其实都不需要跟入动态调试分析了,这里直接简单说一下

首先是必须要能获取到文件流,还记得我说的吗这个函数中使用了zend_resolve_path去重新连接路径,我们现在​​resource=​​​后面是​​./convert.base64-decode/../1.php​​​,连接后也就是​​当前运行文件路径/./convert.base64-decode/../1.php​​​,最终就是​​当前运行文件路径/1.php​

[PHP底层]关于php://filter的分析_php_10


第二部分就是是否有过滤器,有就添加上去了,记得怎么获取的吗,​​filter​​字符后面的部分用​​/​​分割

也就是​​/resource=./convert.base64-decode/../1.php​

因此就是遍历寻找正确的过滤器进行添加

resource=.
convert.base64-decode
..
1.php

整个流程结束

题外话

多提一句,至于是怎么判断有没有这个过滤器的,我的版本是php7.2.9,这里面是靠hash去判断的,还有就是之前很多时候我们对过滤器进行二次编码也是有原因的,如图所示

[PHP底层]关于php://filter的分析_php_11