网鼎杯2020-小知识点

前言

在网鼎杯中遇见了许多令人迷惑的问题、以及不知道的知识,故在此记录。

php反序列化中对象属性问题

在这次的一道php反序列化的一道题中。我们要利用的属性被设置为了protected,这意味着我们的序列化字符串中将会出现%00这个不可见字符,但题目中ban掉了所有不可见字符,需要进行绕过。

我正当想着怎么绕过,突然有师傅说不必理会那个%00,利用的属性直接按照public得到的序列化字符串也可以被利用。
当时的我:???????我之前的一道ctf中,因为没有注意到某一个属性的可见性是private导致痛失一题。

故在这里尝试不同版本php的反序列化处理
尝试以下代码

<?php
echo phpversion().'<br>';

class test
{
    public $a;
    private $b;
    protected $c;

    public function __construct()
    {
        $this->a = 1;
        $this->b = 2;
        $this->c = 3;
    }

    private function outputAll()
    {
        echo 'a:'.$this->a.'<br>';
        echo 'b:'.$this->b.'<br>';
        echo 'c:'.$this->c;
    }

    public function __destruct()
    {
        $this->outputAll();
    }
}

if(isset($_GET['str']))
    $obj = unserialize($_GET['str']);
else
{
    $obj = new test;
    echo serialize($obj);
}

环境为linux加apache2
设置get参数为str=O:4:"test":3:{s:1:"a";i:1;s:1:"b";i:2;s:1:"c";i:3;}
分别获得以下输出

php:7.4-apache:
    7.4.5<br>a:1<br>b:2<br>c:3
php:7.3-apache:
    7.3.17<br>a:1<br>b:2<br>c:3
php:7.2-apache:
    7.2.30<br>a:1<br>b:2<br>c:3
php:7.1-apache:
    7.1.33<br>a:1<br>b:<br>c:
php:7.0-apache:
    7.0.33<br>a:1<br>b:<br>c:
php:5.6-apache:
    5.6.40<br>a:1<br>b:<br>c:

可以看到,在7.2以后的版本(包括7.2)php在进行反序列化处理时并没有对属性的可见性进行检验
这便是矛盾的来源,之后在进行反序列化时,一定要注意php的版本,这上述的情况可能会带来意想不到的漏洞。

php反序列化中的S类型

在一个对象被序列化后的字符串中的字符有特殊的含意
O:4:"test":3:{s:1:"a";i:1;s:1:"b";i:2;s:1:"c";i:3;}
在上面的字符串中,O为对象、s为字符串、i为数字…
这里要讲一种S类型,S类型指的是是已经被转义的字符串
在一个privateprotected的对象属性中,序列化后,会有特殊的字符

以上面的代码为例(PS:%00为hex值为00的字符)
序列化b为:s:7:"%00test%00b";i:2;
序列化c为:s:4:"%00*%00c";i:3;
可以看到,当在浏览器这么输入后,会向服务器发送不可见字符。

但对于S类型则没有必要了,将s替换为S后:
序列化b为:S:7:"\00test\00b";i:2;
序列化c为:S:4:"\00*\00c";i:3;
这样传入的是3个字符组成的字符串\00而不是00这个不可见字符

这么做的目的其实在这次的CTF便可以见得。有时候,服务器会BAN掉不可见的字符,防止这些字符导致系统错误。但对于php的反序列化字符串来说,S类型恰好绕过了这个限制。

后言

目前就学到这么多(,之后靠复现来学习吧。
当时java的xxe试了半天没有出网,还以为payload的锅,结果复现发现一模一样的payload,buuoj可以出网(指靶机内网)。不知道为什么脑壳痛(
还有就是吐槽一下那个/web那个目录有点坑(以后先尝试去读一下httpd.conf
PS:php真是博大精深(((

Comments