CTF中PHP原生类的妙用
前言
前段时间,朋友发我了一道题,代码基本的意思都能看懂。
源码如下:

这里可以看到,对象实例化的类名和参数,我们都是可控的。那么我们只需要找到 PHP原生类 中可以执行命令或者列出目录以及读取文件的类型。基本上就可以实现利用了。
但是由于当时知识量欠缺,于是进行了 Google 搜索,最终使用了PHP的 Directorylterator 内置类列出目录,使用 SplFileObject 类读取 FLAG 文件的内容。
最终将本题解出。
之前一直没有了解过相关的PHP内置类,今天想着对PHP原生类做一个总结,故而该篇文章就应运而生。
PHP原生类读取目录/文件
列出目录文件类
Directorylterator
这里介绍两个PHP的原生类:
- Directorylterator (PHP5, PHP7, PHP8)
- Filesystemlterator (PHP 5 >= 5.3.0, PHP 7, PHP 8)
两类的关系可以从PHP官方文档中看出:

其实就是个继承关系,FilesystemIterator 继承父类 Directorylterator。
以下是PHP官方文档对 Directorylterator 类的官方简介:
DirectoryTerator类提供了一个用于查看文件系统目录内容的简单接口。
我们查看 DirectoryTerator 类,发现类中存在 __toString 方法。

点进该方法当中:

该方法的作用是以字符串形式获取文件名。其返回值为 返回当前DirectoryTerator项的文件名。大概意思就是说,该方法会返回 Directorylterator 列出目录下的所有文件名。
__toString 是魔术方法,当当前对象被echo的时候触发,故而编写如下测试代码:
1 |
|

当然这里除了直接给路径以外,还可以使用 glob 协议。如:

使用 glob 协议的好处就是,该协议不受 open_basedir 配置的限制。
Filesystemlterator 类用法和 **Directorylterator ** 类的利用用法一样,因为 FilesystemIterator 继承自 Directorylterator 且父类的 __toString 是公有方法,因此可以被继承。
1 |
|



这里可以发现,Directorylterator 和 FilesystemIterator 区别就在于,前者返回的为 文件和目录。而后者返回的是绝对路径。
这两个类也有一句话的PAYLOAD:
DirectoryIterator:
1 | $a = new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().'<br>');} |
FilesystemIterator:
1 | $a = new FilesystemIterator("glob:///*");foreach($a as $f){echo($f->__toString().'<br>');} |
使用前言的题目测试一下:
1 |
|
PAYLOAD:
1 | args1=DirectoryIterator&args2=glob:///fl* |

这里就可以发现根目录下存在文件名为 flllllllllllllag.txt 的文件。
CTFshow web74
1 | error_reporting(0); |
由于这里禁用了 scandir 函数,无法列出目录,故而这里只能使用 Directorylterator 或 FilesystemIterator 类列出。
PAYLOAD:
1 | c=$a = new DirectoryIterator("/");foreach($a as $f){echo($f->__toString().'<br>');};exit(); |

最终配合 include 语句包含读取FLAG文件即可。
Globlterator
(PHP 5 >= 5.3.0, PHP 7, PHP 8)
PHP的官方简介:
遍历一个文件系统行为类似于 glob()。
与前两个类的作用相似,GlobIterator 类也是可以遍历一个文件目录,使用方法与前两个类也基本相似。但与上面略不同的是其行为类似于 glob(),可以通过模式匹配来寻找文件路径。
既然遍历一个文件系统性为类似于glob(),所以在这个类中不需要配合glob伪协议,可以直接使用 glob 协议。
看了一下文档发现该原生类是继承FilesystemIterator的,所以也是以绝对路径显示的。

1 |
|

传参这里直接给路径就行。
读取文件内容类
SplFileInfo (PHP 5 >= 5.1.2, PHP 7, PHP 8)
官方解释:
SplFileInfo 类为单个文件的信息提供了一个高级的面向对象的接口。
该类也存在 __toString 方法:

其返回值为文件的路径。
测试代码:
1 |
|

小扩展:
在PHP7版本中是支持如下方式调用函数:

以上两种方法等同于传统的 system('ls');。
测试代码二:
1 |
|
这里我们只需要让 class 属性的值为 SplFileObject,而 data 为具体读取文件的路径,利用 __destruct 魔术方法即可实现文件读取。
构造POC:
1 |
|

PHP原生类构造XSS
Error/Exception内置类
- 适用于php7版本
- 在开启报错回显的情况下
Error 类是 php 的一个内置类,用于自动自定义一个 Error,在 php7 的环境下可能会造成一个xss漏洞,因为它内置有一个 __toString() 的方法,常用于 PHP 反序列化中。
如果有个POP链走到一半就走不通了,不如尝试利用这个来做一个xss,其实我看到的还是有好一些cms会选择直接使用 echo <Object> 的写法,当 PHP 对象被当作一个字符串输出或使用时候(如echo的时候)会触发__toString 方法。
从官方文档中可以看出,这两个原生类的属性相同,都是对message、code、file、line的信息处理,并调用__toString() 方法将异常的对象转换为字符串。

下面来演示使用 Error 内置类来触发XSS:
测试代码:
1 |
|
利用 Exception::__toString 来构造XSS:
1 |
|









