php代码审计片段 02 绕过过滤的空白字符

源码点这:bowu678/php_bugs: PHP代码审计分段讲解 (github.com)

掌握本题应具备的能力/技巧:php基础知识、对php特定函数的理解、对URL编码与ASCII码的理解与使用。(python基本语法的掌握、python Requests库的基础使用)【可选用】


甜点部分:

ini_set("display_error", false);    #关闭错误报告

error_reporting(0); //关闭所有PHP错误报告

foreach([$_GET, $_POST] as $global_var) { 
    foreach($global_var as $key => $value) { 
        $value = trim($value);  //trim — 去除字符串首尾处的空白字符(或者其他字符)
        is_string($value) && $req[$key] = addslashes($value); // is_string — 检测变量是否是字符串,addslashes — 使用反斜线引用字符串
    } 
} 
 

 #req数组里 有一系列键值对,键与值是通过GET和POST接收的,例如url为xxx.php?a=2

则$_GET["a"]=2      在req数组也有$req["a"]=2,req数组的值用addslashes做过防注入,且用trim函数去除过前后两端的空格

正餐部分:

第一个函数:is_palindrome_number($number)      #palindrome:回文

strval($number)函数获取$number的变量值,然后将这个字符串两端向中间逐渐比较,用这种方式判断,传入参数$number是否为回文字符串。


整体通读可以得知,想要转到Flag里,就要满足以下四个条件:

①:is_numeric($_REQUEST['number']) ==0     

is_numeric函数必须判断REQUEST中number的值不为数字。

②:$req['number'] == strval(intval($req['number']))

req数组的number经过strvalintval这两个函数筛选后,必须不变。

③:$value1 == $value2

                $value1 = intval($req["number"])

                $value2 =intval(strrev ($req["number"]) )

$req数组中number的值,经过intval函数处理后得到的值, 必须等于经过strrev函数与intval函数双重处理后的值。

④:is_palindrome_number $req["number"] ) == 0

$req数组中number的值传入函数i_p_n中,必须返回0,也就是说,回文函数应该判断number不是回文数。


由上可得,传入参数number既要是回文数,又得满足一系列条件。

number=11    就不能够满足条件①。

从①开始,可以发现,只有①的number是从REQUEST数组里面选的,而②③④的number都是$req数组里的。而$req数组里的number是经过"处理"的(甜点部分)。

所以可用%00这个空字符绕过①,number=%0011,满足条件①不为数字,$REQUEST数组接收number后,会自动去除空字符%00,所以REQUEST["number"]=11 不变。

number=%0011     现在不满足最重要的条件④;

条件④的回文判断是用逻辑写的,而条件②③的回文判断使用函数intval,strrev,strval这三个函数写的,也就是说,添加一个字符,让它绕过条件②③这三个函数,就能满足条件④。

这个符号可以是%0c(换页符 \t ) %2B(+) 

最终结果为number=%00%0c11   或 number=%00%2B11

%2B能够从逻辑上被盘出来;因为intval()对+号的处理比较特殊:

+123 会变成123        123+ 会变成 123     1+23  会变成 1       12+3 会变成 12

这样将+号放数字前面就能绕过条件②③了。

下面介绍Fuzzing(模糊测试)思路。


%00{?}11     ?为ASCII字符,要找到一个ASCII字符让它满足上面的②③④条件。

#基本ASCII码128位,再加扩展ASCII码128位,共256位  所以是%00 到%255 但是这里需要用16进制      就是%00~%FF
#hex(1)=0x1

#理解这段代码着重python的“字符串切片”以及“格式化输出”

import requests
for i in range(256):
    i=str(hex(i))               
    if len(i)==3:               #0x1  把x去了
        i=i[0:1:]+i[2::]
    else:                       #0x10 把0x去了
        i=i[2::]
    i="%"+i
    #print(i)
    number=f"%00{i}11"
    re = requests.get(f"http://127.0.0.1/php_bugs/02%20%E7%BB%95%E8%BF%87%E8%BF%87%E6%BB%A4%E7%9A%84%E7%A9%BA%E7%99%BD%E5%AD%97%E7%AC%A6.php?number={number}")
    #print(re.text)
    if "x" in re.text:
        print(i)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值