• PHP代码审计


    Extract()函数引起的变量覆盖漏洞

    该函数使用数组键名作为变量名,使用数组键值作为变量值。但是当变量中有同名的元素时,该函数默认将原有的值给覆盖掉。这就造成了变量覆盖漏洞。

    例:

    <?php
    $a = 1;    //原变量值为1
    $b = array('a' => '3');
    extract($b);    //经过extract()函数对$b处理后
    echo $a;    //输出结果为3
    ?>
    

    实战题

    "extract($_GET);
    if(isset($a))
    {
    $content=trim(file_get_contents($flag));//file_get_contents—将整个文件读入一个字符串
    if($a==$content)                             //trim—去除字符串首尾处的空白字符(或者其他字符)
    { echo'flag{**********}'; }
    else
    { echo'这不是flag啊'; }
    }"
    

    题目使用了extract($_GET)接收了GET请求中的数据,并将键名和键值转换为变量名和变量的值,然后再进行两个if 的条件判断,所以可以使用GET提交参数和值,利用extract()对变量进行覆盖,从而满足各个条件。

    ?a=&content=
    或者可以利用file_get_contents()可以读取只读流:php://input构造Payload
    

    is_numeric() 判断变量是否为数字或数字字符串

    is_numeric() 函数会判断如果是数字和数字字符串则返回 TRUE,否则返回 FALSE,且php中弱类型比较时,会使('1234a' == 1234)为真,或者'12345%00',is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后。该函数还可能造成sql注入,例如将‘1 or 1'转换为16进制形式 0x31206f722031,再传参,就可以造成sql注入

    -ereg正则%00截断

    ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。
    ereg函数存在NULL截断漏洞,导致了正则过滤被绕过,所以可以使用%00截断正则匹配
    strlen函数对%00不截断但substr对%00截断

    实战题

    <?php
    if (isset ($_GET['password'])) {
       if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
       {
           echo '<p>You password must be alphanumeric</p>';
       }
       else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
       {
           if (strpos ($_GET['password'], '*-*') !== FALSE)
           {
               die('Flag: ' . $flag);
           }
           else
           {
               echo('<p>*-* have not been found</p>');
           }
       }
       else
       {
           echo '<p>Invalid password</p>';
       }
    }
    ?>
    

    ereg函数存在NULL截断漏洞,可以%00截断,则不会读取后面的内容,可以绕过输入-
    大小和长度限制可以利用科学计数法

    ?password=1e8%00*-*
    

    strcmp()漏洞

    用法:

    int strcmp ( string $str1 , string $str2 )
    参数 str1第一个字符串。str2第二个字符串。
    如果 str1 小于 str2 返回 < 0;
    如果 str1 大于 str2 返回 > 0;
    如果两者相等,返回 0。

    php在5.3版本之前若传入的是一个非字符串类型数据,比如数组和对象,则会报错,但在报错的同时会返回0。可以利用这一点来绕过

    实战题

    <?php
        $password="***************"
         if(isset($_POST['password'])){
            if (strcmp($_POST['password'], $password) == 0) {
                echo "Right!!!login success";
                exit();
            } else {
                echo "Wrong password..";
            }
    ?>
    

    只要我们$_POST[‘password’]是一个数组或者一个object即可

    password[]=admin
    

    md5和sha1绕过"==="

    无法处理数组类型,可以构造数组绕过

    in_array()绕过(适用不设第三个参数的情况)

    bool in_array ( mixed $needle , array $haystack [, bool $strict = FALSE ] )
    说明:在 haystack 中搜索 needle,如果没有设置 strict 则使用 宽松 的比较。如果第三个参数 strict 的值为 true,则 in_array 函数还会检查 needle 的 类型 是否和 haystack 中的相同。

    in_array 函数存在第三个参数 strict,它用来标记函数在对两元素进行比较时是否采用 严格比较,类似 == 和 === 区别,in_array 函数默认采用 宽松 比较,即不比较类型,只比较值是否相等。
    例如:in_array(0, array('s'))会返回 TRUE,这是因为因为 in_array 函数没有使用第三个参数,而默认进行了 宽松 比较,即等同于 0 == 's' ,而为什么0 == 's',可参照下表:

    不同类型转化规则

    参照第四点,当两不同类型数值中含有数字类型,都会转化为数字类型进行比较。那么s转化为数字类型为0,所以0 == 0 ?判断为 true。

    filter_var() (仅对FILTER_VALIDATE_URL)

    filter_var() 要求传入参数符合url规定,函数通过指定的过滤器过滤一个变量。 如果成功,则返回被过滤的数据。如果失败,则返回 FALSE。
    FILTER_VALIDATE_URL:把值作为 URL 来验证。

    该函数的具体使用方法可参考http://www.findme.wang/blog/detail/id/473.html

    FILTER_VALIDATE_URL 过滤器来判断是否是一个合法的url。

    实战题

    // index.php
    <?php 
    $url = $_GET['url'];
    if(isset($url) && filter_var($url, FILTER_VALIDATE_URL)){
        $site_info = parse_url($url);
        if(preg_match('/sec-redclub.com$/',$site_info['host'])){
            exec('curl "'.$site_info['host'].'"', $result);
            echo "<center><h1>You have curl {$site_info['host']} successfully!</h1></center>
                  <center><textarea rows='20' cols='90'>";
            echo implode(' ', $result);
        }
        else{
            die("<center><h1>Error: Host not allowed</h1></center>");
        }
    
    }
    else{
        echo "<center><h1>Just curl sec-redclub.com!</h1></center><br>
              <center><h3>For example:?url=http://sec-redclub.com</h3></center>";
    }
    
    ?>
    

    构造符合函数要求的URL即可,又因为题目正则匹配了要求以sec-redclub.com结尾,构造如下:

    ?url=0://xxx.com;sec-redclub.com  
    ?url=http://xxx.com()sec-redclub.com
    ()里换成@&?/,:#这些任意一个均可
    

    .htmlentities()

    在写PHP代码时,不能在字符串中直接写实体字符,因此需要一个将HTML特殊字符转换成实体字符的函数 htmlentities()。
    注:htmlentities() 并不能转换所有的特殊字符,是转换除了空格之外的特殊字符,且单引号和双引号需要单独控制(通过第二个参数)。第2个参数取值有3种,分别如下:

    • ENT_COMPAT(默认值):只转换双引号。
    • ENT_QUOTES:两种引号都转换。
    • ENT_NOQUOTES:两种引号都不转换。

  • 相关阅读:
    redis客户端windows版中文乱码解决方案
    nginx做负载均衡,怎么在有宕机情况出现时保证网站的响应速度
    支付宝同步和异步验签结果不一致的解决方法
    @ResponseBody中文乱码解决方案
    [javamail]AUTH LOGIN failed;Invalid username or password报错
    Could not load driverClass ${driverClassName} 的解决方案
    eclipse中,maven报错maven.multiModuleProjectDirectory system property is not set
    spring bean初始化和销毁方法
    关于静态资源是否应该放到WEB-INF目录
    使用Jedis出现Connection refused的解决方案
  • 原文地址:https://www.cnblogs.com/NPFS/p/12673552.html
Copyright © 2020-2023  润新知