文章目录
在很多CTF比赛里面,经常出现如下代码(以下代码也为后面例题源码):
$a=$_GET['cmd'];
if (preg_match("/system/i", $a))
{
echo 'isset flag!!';
die();
}
eval($a);
先不考虑其他绕过取反,异或等等绕过方式,纯粹的从二次传参出发,playload应该如下:
?cmd=\$_GET[a] (\$_GET[b])&b=system&b=ls
这里我们采用system(dir)的命令在本地运行:
很显然,这里可以绕过死亡die从而执行命令
问题1:虽然是二次传参传给了cmd,但是为什么可以绕过那么正则表达式呢?
我们改下源码看看:
这里增加了一个 echo $a,这样更方便我们清楚传进去$a的值,很显然,虽然这里我想用二次传参,但是这里没有传进去,$_GET[shell]在这里仅仅是一个字符串
问题2:那么为什么在后面,$_GET[shell]又可以进行传参了呢?
这里应该是由于eval存在的原因,eval执行$_GET[shell],并且可以命令执行传入进来的字符串
问题3:既然可以把传入进来的字符串命令执行,那为什么不直接用一个$_GET然后执行所有呢?
而是?cmd=$_GET[a] ($_GET[b])&b=system&b=ls ,我们在看一下效果:
没有执行命令,至于为什么没有执行,我猜测是因为传进来的数值依然是当成了字符串
比如:?cmd=$_GET[shell];&shell=system(‘dir’);
最后还是被当成了字符串:eval(‘system(“dir”);’);,eval一个字符串,自然也得不到一个输出
为了更好的证实一下我的猜想,我们修改一下代码看看:
果然,传进去的system(‘dir’);被当成了字符串输出了。
为了避免被当成字符串的现象,所以我们才会采用多次传参的方法,具体原因我认为应该是由于()的存在