[CTF]安全大赛,决赛题目。唯一和PHP有关的题目,大佬进来看看

回复列表(31|隐藏机器人聊天)
  • @Ta / 2021-11-01 / /

    呃,从@老虎会仰泳 的截图来看,它甚至都没有修复会调用有问题的对象本身的析构函数这个问题。
    所以 https://github.com/php/php-src/commit/20ce2fe8e3c211a42fee05a461a5881be9a8790e 仅仅只是从测试用例出发,只是阻止了有问题的对象从unserialize返回,没有任何进一步的思考???

    图片.png

  • @Ta / 2021-11-01 / /

    实验结果表明,@老虎会仰泳 左边的代码确实说明了,PHP不会调用有问题的对象的析构函数。而且@老虎会仰泳 犯了一个错误,他没有看到\0Wo\0name中的\0(因为它不会在终端里显示)。

    我的测试用例:

    <?php
    class Wo {
        private $name = 'mmmm111111111';
    
        public function __wakeup() {
            echo "__wakeup\n";
        }
    
        public function __destruct() {
            echo "__destruct\n";
            var_dump($this->name);
        }
    }
    
    echo "----------- normal -----------\n";
    $WoObj = new Wo();
    echo str_replace("\0", '\0', serialize($WoObj)), "\n";
    var_dump($WoObj);
    $WoObj = null;
    
    echo "----------- normal -----------\n";
    $WoObj2 = unserialize(<<<EOF
    O:2:"Wo":1:{s:8:"\0Wo\0name";s:13:"mmmm111111111";}
    EOF);
    var_dump($WoObj2);
    $WoObj2 = null;
    
    echo "----------- bad -----------\n";
    $WoObj3 = unserialize(<<<EOF
    O:2:"Wo":2:{s:8:"\0Wo\0name";s:1:"mmmm";}
    EOF);
    var_dump($WoObj3);
    $WoObj3 = null;
    

    运行结果:
    image.png

    bad那一段确实没有调用析构函数。PHP开发者可能觉得这样就足够了,但是没想到还可以通过外层对象的析构函数使用有问题的数据。

  • @Ta / 2021-11-01 / /

    确实如此,外部对象的析构函数可以触发,并且可以使用内部有问题的对象数据。

    <?php
    class A {
        private $name = 'hello';
    
        public function setName($name) {
            $this->name = $name;
        }
    
        public function __destruct() {
            echo "__destruct\n";
            echo $this->name, "\n";
        }
    }
    
    class B {
        private $name = 'world';
    
        public function setName($name) {
            $this->name = $name;
        }
    
        public function __toString() {
            return $this->name;
        }
    
        public function __wakeup() {
            echo "__wakeup\n";
            $this->setName('no unserialize');
        }
    }
    
    echo "----------- normal -----------\n";
    $a = new A();
    $a->setName(new B());
    echo str_replace("\0", '\0', serialize($a)), "\n";
    var_dump($a);
    $a = null;
    
    echo "----------- normal -----------\n";
    $a2 = unserialize(<<<EOF
    O:1:"A":1:{s:7:"\0A\0name";O:1:"B":1:{s:7:"\0B\0name";s:5:"pwned";}}
    EOF);
    var_dump($a2);
    $a2 = null;
    
    echo "----------- bad -----------\n";
    $a3 = unserialize(<<<EOF
    O:1:"A":1:{s:7:"\0A\0name";O:1:"B":2:{s:7:"\0B\0name";s:5:"pwned";}}
    EOF);
    var_dump($a3);
    $a3 = null;
    

    image.png

  • @Ta / 2021-11-02 / /
    @老虎会游泳,目前topthink这种php框架 内,好像大量采用了序列化,是否有必要通知下呢
  • @Ta / 2021-11-03 / /

    @老虎会游泳,我理解的json化是:对象出了车祸,被压路机压扁了,变成了一张纸,已经死了。有些东西已经失真了,但是还能看出原样的必要信息。
    序列化就是量子转移,分解成最小原子,在特定环境下还能还原出来
    小米MIX2s(白)

  • @Ta / 2021-11-03 / /

    @老虎会仰泳@胡椒舰长@水木易安,php的开发者说__wakeup()不是安全措施,反序列化不信任的内容本身就是不安全的。他们可能不会修复该问题了,该问题以后也可以一直出现在比赛题中了,并且不限php版本。

    Screenshot_20211103_170306_com.huawei.browser.jpg

  • @Ta / 2021-11-03 / /

    @老虎会游泳,意思就是我以后要自己来处理。

    顺便提一句,我之前在上面做的测试太不严谨了,自己也没仔细看就发表了评论,希望大家引以为戒。
    白日梦还是要做的blog.wz52.cn

  • @Ta / 2021-11-03 / /

    @老虎会仰泳,嗯,不要把serialize的内容发给用户,改用JSON。@胡椒舰长,如果serialize的内容只是在内部使用,从未接收来自用户的serialize内容,则没有安全问题。

  • @Ta / 2021-11-03 / /

    牛啊牛啊
    小米MIX2s(白)

  • @Ta / 2021-11-03 / /

    @水木易安,你在25楼的理解是正确的。序列化可以还原对象的类,JSON则不能,只有对象的属性。所以从用户侧接收JSON是安全的,接收序列化内容则不安全。

  • @Ta / 2021-11-03 / /
    小米MIX2s(白)
  • @Ta / 2021-11-03 / /

    按照“serialize的内容只是在内部使用,从未接收来自用户的serialize内容”这个标准,虎绿林在帖子里存储serialize内容其实是安全的。不过我还是改成了JSON,因为JSON有一个好处:不在结构里存储内容长度。

    所以我终于可以进行这种替换了:

    update hu60_bbs_topic_content set content=replace(content, 'file.hu60.cn//////', 'file.hu60.cn/') where content like '%file.hu60.cn//////%'
    

    从SQL也能看出来,使用serialize的时候想要做个替换是多么辛苦。为什么有那么多/?因为它来自上一次替换,并且不等长替换会导致serialize结构错误。

添加新回复
回复需要登录