打开网址,发现只有一个计算器,正常的计算是没有问题的,但一输入字符就会报错,查看源代码也没有任何收获,然后抓包瞅瞅,有意外收获:
得到了传参方式GET:/calc.php?num=1,还有一个文件calc.php,那就去看看吧:
这段代码交代出过滤了很多东西。
然后…我就抓瞎了,因为num不能传字符(运算符除外),就没法传进去命令参数什么的,再然后我就去找了题解,大佬们分享,这道题是出题人对PHP字符串解析漏洞的理解,需要了解一些前置知识:
我们知道PHP将查询字符串(在URL或正文中)转换为内部GET或的关联数组_POST。例如:/?foo=bar变成Array([foo] => “bar”)。
值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替。
例如,/?%20news[id%00=42会转换为Array([news_id] => 42)。
如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,
那么我们就可以用以下语句绕过:
/news.php?%20news[id%00=42"+AND+1=0–
上述PHP语句的参数%20news[id%00的值将存储到$_GET[“news_id”]中。
PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:
1.删除空白符
2.将某些字符转换为下划线(包括空格)
最关键的就是最后,解析查询字符串时,会删除空白格和将某些字符转换成下划线。这题就是利用删除空白符。还有就是关于chr(int a),这个函数的作用就是返回a在ASCII码表中对应的字符,比如chr(65)就返回A。
这样waf就找不到num这个变量了,因为现在的变量叫“ num”,而不是“num”。但php在解析的时候,会先把空格给去掉,这样我们的代码还能正常运行,还上传了非法字符。解题中,我们还用到了scandir()函数,这是列出 参数目录中的文件和目录,要不然我们怎么知道flag在哪。
接下来回归解题:
利用scandir("/")来查看全部目录,但是双引号被过滤了,这时候就用到chr了,我们利用chr这个函数来构造函数内的字符串参数,就不需要用单双引号,从而成功绕过正则表达式:
? num=var_dump(scandir(chr(47)))
这样我们就找到了存放flag的地方,就下来就是查看了依旧使用chr:
? num=file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))
这样,我们就得到了flag。