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 |
|