看题目源码 及 分析
1 | <?php |
这边,我们主要看如何绕过if语句,第一想到的就是数组绕过,但是eval 执行的需要是字符串,数组转为字符串后就只剩下:Array 了,显然数组绕过行不通,在加上这边同时使用了MD5 和 sha1 我们想要利用 fastcoll
来碰撞也不行了。
解题分析
我们传入2个不相等对象,但是他们的__toString 魔法函数返回的一样。这就可以绕过我们的 if 了 ,且eval转为字符串时我们也像办法使其可以被执行。
查找带 __toString 的类
我们使用如下代码遍历:
1 | <?php |
得到结果如下:
1 | Exception |
我们这里利用第一个 Exception
我们去看看它的 toString 方法还回的是个什么。我直接在phpstorm中查看此类没发现它放回的是什么。接着我们看到了construct函数下面的提示:
也就是说它返回的是一个字符串类型的异常信息,我们调试一下进行测试。(同时根据这里我们也发现我们可以控制message和code)
我们发现这个string变量是将要返回的字符串,但是$ex1的string 并不等于$ex2的string,这就意味着md5值不相等(无法绕过),不过也号解决,我们只需要将$ex1 和 $ex2 放在同一行即可。但是这么一改2个类就完全相等了,就过不了($this->var1 != $this->var2)
.
此时我们想起了我们可以传入的code变量,使其不一样,那么类就不相等了。(我截图中已使用)
我们控制 message 来执行代码
前面虽然已经绕过了,但是我们没有插入任何代码进去。我们知道我们可以控制的还有message,他是会在string中回显的如下
我们可以看到外面的代码插进去了,但是怎么执行呢?它前后都有多余代码,直接这样肯定会报错的呀。
eval中不为人知的秘密
例如:我们在eval函数中执行php代码时 想要离开或重进 php 模式 怎么办?
?>
和<?php
(可以省略)之间的表示不以php代码执行(就普通字符,直接显示)<?
后面的语句继续进入php模式- return 语句会立即中止当前字符串的执行。
- 代码执行的作用域是调用 eval() 处的作用域。
因此,eval()里任何的变量定义、修改,都会在函数结束后被保留。
测试:参考链接1
2
3<?php
eval("abc: echo \"In PHP mode!\";\$a='mayi077';return; ?> in wef wer <?php system('dir');");
echo "\n".$a;
补充一点:__HALT_COMPILER(); 也会中止后面代码的执行。
但是,我们还记得string的值最前面还有个Exception:
它不会干扰我们的语句吗?
事实上确实不会我们做如下测试:
1 | eval("abc:echo 123;"); //123 |
就是说冒号前是一个合法变量名的话就可以正常执行的。其实这里就牵扯到了 一个 goto 的方法:如以下:
1 | <? |
就是他会直接跳到我们所做的标记位置。
得到payload
这边再提醒一下,因为Exception 类中有私有或保护类型 而非全部public所以我们进行urlencode进行包装
1 | <?php |
这样就可以完美绕过了。最先开始我还以为要利用到$var3呢,显然是我想多了。