0x00 前言

在审计代码的时候,经常会遇到readfile函数

在未做限制的情况下,这种可以触发phar反序列化的问题

phar协议还可以通过zip或者php伪协议之类的触发

当只限制了http时,底层是怎么处理的呢

0x01 Phar触发流程

进入到readfile方法中

1657078549839

跟进之后

1657078615916

这里通过php_stream_locate_url_wrapper函数解析协议,

1657078677400

该函数则通过遍历⽂件名,
解析对应 protocol 的⽅式从 hash 中查找对应的 wrapper ,⽽ phar 单独注册了⼀个 wrapper

1
2
3
4
5
6
7
8
9
10
11
php_stream_ops phar_ops = {
phar_stream_write, /* write */
phar_stream_read, /* read */
phar_stream_close, /* close */
phar_stream_flush, /* flush */
"phar stream",
phar_stream_seek, /* seek */
NULL, /* cast */
phar_stream_stat, /* stat */
NULL, /* set option */
};

之后就调用wraper解析文件结构

1
2
3
stream = wrapper->wops->stream_opener(wrapper,
path_to_open, mode, options ^ REPORT_ERRORS,
opened_path, context STREAMS_REL_CC);

这里实际上调用到的是

1657078945570

继续跟进

1657079002749

接下来调用到phar_open_from_fp的时候就开始解析phar文件了

1657079067548

然后可以看到,集中phar解析的方式,最后进入函数中,会对元数据进行处理

1657079207383

在此处完成了反序列化

1657079261161

所以要想完成phar文件的解析,最重要的入口点就是php_stream_locate_url_wrapper进行协议解析

全局搜索一下,可以看到基本算是一一对应

就拿不常用的为什么xxe也可以触发phar协议

1657092778742

没有看到关于解析http协议后二次触发的,估计白搭

0x02 http协议的解释流程

默认情况下,readfile会跟进跳转

1
2
<?php
readfile("http://127.0.0.1:82/test.php");
1
2
<?php
header("Location: phar://aaa/aaa.txt");

这里获取到wraper自然是http协议的php_stream_url_wrap_http

1657093525532

这里说一下这个方法,这里在http之前可以有这些字符,本来想看看能不能通过这些绕waf,但是白搭,可以取出来协议,但是找不到对应的wraper

1657093658184

当走到是否支持跳转的时候

1657093821279

这里可以看到我们的location字符串

重点就在这里了,当协议不是http或者ftp时,会将跳转的路径直接拼接到原来的url上

1657093962853

所以转换其他的协议是不可以的

这里能调用的依然只有http或者ftp,相当于普通的ssrf

0x03 end

暂时没研究ftp协议是否存在利用点

这里知识针对一次遇到的情况做记录