從底層分析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內核動態調試關於弱類型比較


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM