php_bugs学习 02 绕过过滤的空白字符
<?php
$info = "";
$req = [];
$flag="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
ini_set("display_error", false); //为一个配置选项设置值
error_reporting(0); //关闭所有PHP错误报告
if(!isset($_GET['number'])){
header("hint:26966dc52e85af40f59b4fe73d8c323a.txt"); //HTTP头显示hint 26966dc52e85af40f59b4fe73d8c323a.txt
die("have a fun!!"); //die — 等同于 exit()
}
foreach([$_GET, $_POST] as $global_var) { //foreach 语法结构提供了遍历数组的简单方式
foreach($global_var as $key => $value) {
$value = trim($value); //trim — 去除字符串首尾处的空白字符(或者其他字符)
is_string($value) && $req[$key] = addslashes($value); // is_string — 检测变量是否是字符串,addslashes — 使用反斜线引用字符串
}
}
function is_palindrome_number($number) {
$number = strval($number); //strval — 获取变量的字符串值
$i = 0;
$j = strlen($number) - 1; //strlen — 获取字符串长度
while($i < $j) {
if($number[$i] !== $number[$j]) {
return false;
}
$i++;
$j--;
}
return true;
}
if(is_numeric($_REQUEST['number'])) //is_numeric — 检测变量是否为数字或数字字符串
{
$info="sorry, you cann't input a number!";
}
elseif($req['number']!=strval(intval($req['number']))) //intval — 获取变量的整数值
{
$info = "number must be equal to it's integer!! ";
}
else
{
$value1 = intval($req["number"]);
$value2 = intval(strrev($req["number"]));
if($value1!=$value2){
$info="no, this is not a palindrome number!";
}
else
{
if(is_palindrome_number($req["number"])){
$info = "nice! {$value1} is a palindrome number!";
}
else
{
$info=$flag;
}
}
}
正好代码的注释比较多,一句一句审计一下
代码审计
!isset
如果不存在GET请求的number值,就在返回包中的header添加hint
代码结束,返回have_fun
foreach将传入的GET和POST请求遍历赋值给$global_var
然后将$global_var
的值变为键值对应的形式,有点类似于python中的字典?
trim($value) 去除字符串首尾处的空白字符(或者其他字符)
is_string
检查value是否为字符串,&&,如果是字符串的话就通过addslashes
给字符串加反斜线
这一步相当于把传入的数据清洗了一遍
is_palindrome_number
验证回文数字的意思
如果不是回文的话,直接返回false
判断:
1.传入的number
如果是数字=>返回sorry, you cann't input a number!
2.传入的number
如果不能被自身整除,返回number must be equal to it's integer!!
也就是说,传入的number
不但要求不是数字,还要求它本身能被自己整除
感觉是个悖论,不是么
判断:
1.要求这个字符串是自己本身的反转
2.要求传入的数值是回文
解题
要求:
1.条件is_numeric($_REQUEST['number'])为假,这个绕过的方法很多使用%00开头就行,也可以再POST一个number参数把GET中的覆盖掉也可以,所以这一步很简单。
2.要求 $req['number']==strval(intval($req['number']))
3.要求intval($req['number']) == intval(strrev($req['number']))
4.is_palindrome_number()返回False,这个条件只要在一个回文数比如191前面加一个字符即可实现得到flag
函数对空白字符的特性 is_numeric函数在开始判断前,会先跳过所有空白字符。
也就是说,is_numeirc(” \r\n \t 1.2″)是会返回true的。同理,intval(” \r\n \t 12″),也会正常返回12。
可以引入\f(也就是%0c)在数字前面,来绕过最后那个is_palindrome_number函数,而对于前面的数字判断,因为intval和is_numeric都会忽略这个字符(因为\f也是空白字符),所以不会影响。
payload:
%00%0c191
A lion doesn't concern himself with the opinions of a sheep.