php 正则匹配反斜杠的问题
在做安洵杯 2019的easy web时碰到了php的反斜杠问题,想来研究一下,可以在buuctf上复现一下
稍微修改一下源代码,方便研究
$cmd = $_GET['cmd'];
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("forbid ~");
echo "<br>";
} else {
echo `$cmd`;
}
?>
先直接给出绕过的技巧,ca\t /flag即可执行系统命令,获得flag
那么问题来了,正则匹配中不是已经匹配了反斜杠了吗,为什么还能ca\t能过绕过?
将代码继续继续精简
<?php
$cmd='\\';
echo $cmd;
echo "</br>";
if(preg_match('/\\|\\\\/i',$cmd))
{
echo "yes";
}else{
echo "no";
}
// 结果为
// \
// no
下面来研究一下,为什么这样的正则匹配匹配不到反斜杠
首先猜测是转义的问题,那么怎么验证自己的想法呢?
直接将$cmd的值赋值成为 “\|\\” 看看输出结果
$cmd='\\|\\\\'
// \|\\</br>yes
看到这大概就有一个猜测,我怀疑在正则匹配的时候,反斜杠转义了两次,第一次变成 “|\\” 第二次变成 " |\ ",为了验证猜想,把$cmd赋值成 “|”,此时输出还是no,然后再把$cmd 赋值成 “|\\”,发现输出 yes,同时也要排除 "\"单独被匹配的情况
$cmd='|' // |</br>no
$cmd='|\\' //|</br>yes
$cmd='\\' //|</br>no
下面又有个猜想,会不会转义第三次,经过尝试发现没有成功
<?php
$cmd='\\';
echo $cmd;
echo "</br>";
if(preg_match('/\\\\\\\\/i',$cmd))
{
echo "yes";
}else{
echo "no";
//echo $cmd;
}
// \
// no
// 当$cmd为 \\\\的时候输出了 yes