zoukankan      html  css  js  c++  java
  • PHP代码审计分段讲解(8)

    20 十六进制与数字比较

    源代码为:

    <?php
    
    error_reporting(0);
    function noother_says_correct($temp)
    {
        $flag = 'flag{test}';
        $one = ord('1');  //ord — 返回字符的 ASCII 码值
        $nine = ord('9'); //ord — 返回字符的 ASCII 码值
        $number = '3735929054';
        // Check all the input characters!
        for ($i = 0; $i < strlen($number); $i++)
        { 
            // Disallow all the digits!
            $digit = ord($temp{$i});
            if ( ($digit >= $one) && ($digit <= $nine) )
            {
                // Aha, digit not allowed!
                return "flase";
            }
        }
        if($number == $temp)
            return $flag;
    }
    $temp = $_GET['password'];
    echo noother_says_correct($temp);
    
    ?>

    GET方式传入password的值,输出经过noother_says_correct函数处理之后的值。

    noother_says_correct函数处理的逻辑为:先对password中的每一位进行判断,若在1--9之间,则直接返回false,若都满足,并且$number = '3735929054',$number==$password,则返回flag。

    我们很容易能够注意到:

    $number == $temp

    这里两个等号,是弱类型比较,即会先将比较的两者类型进行转化后再比较,在计算机中0x开头的表示为十六进制,所以我们可以使用十六进制来绕过前面的for循环,同时满足等于temp

    3735929054转换成十六进制后为:deadc0de

    加上0x后为0xdeadc0de,可以看出可以逃逸出for循环中的限制,所以最后的payload为:

    ?password=0xdeadc0de

     

    21 数字验证正则绕过

    <?php
    
    error_reporting(0);
    $flag = 'flag{test}';
    if  ("POST" == $_SERVER['REQUEST_METHOD']) 
    { 
        $password = $_POST['password']; 
        if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 执行一个正则表达式匹配
        { 
            echo 'Wrong Format'; 
            exit; 
        } 
        while (TRUE) 
        { 
            $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/'; 
            if (6 > preg_match_all($reg, $password, $arr)) 
                break; 
            $c = 0; 
            $ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字  [[:upper:]] 任何大写字母  [[:lower:]] 任何小写字母 
            foreach ($ps as $pt) 
            { 
                if (preg_match("/[[:$pt:]]+/", $password)) 
                    $c += 1; 
            } 
            if ($c < 3) break; 
            //>=3,必须包含四种类型三种与三种以上
            if ("42" == $password) echo $flag; 
            else echo 'Wrong password'; 
            exit; 
        } 
    }
    
    ?>

    这里用到了PHP正则表达式,简单列举一下字符串类的正则表达式:

    [[:alpha:]] :匹配任何字母
    [[:digit:]] :匹配任何数字
    [[:alnum:]] :匹配任何字母和数字
    [[:space:]] :匹配任何空白字符
    [[:upper:]] :匹配任何大写字母
    [[:lower:]] :匹配任何小写字母
    [[:punct:]] :匹配任何标点符号
    [[:xdigit:]] :匹配任何16进制数字,相当于[0-9a-fA-F]
    [[:blank:]] :匹配空格和Tab,等价于[	]
    [[:cntrl:]] :匹配所有ASCII 0到31之间的控制符
    [[:graph:]] :匹配所有的可打印字符,等价于[^ 	
    
    fv]
    [[:print:]] :匹配所有的可打印字符和空格,等价于[^	
    
    fv]

    使用POST方式传输password

    if  ("POST" == $_SERVER['REQUEST_METHOD']) 
    { 
        $password = $_POST['password']; 

    第一个if中正则表达式匹配所有的可打印字符,并且需要大于等于12个

        if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 执行一个正则表达式匹配
        { 
            echo 'Wrong Format'; 
            exit; 
        } 

    然后是一个while循环

    第二个 if 里面,使用 preg_match_all

    $reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';

    按照这个规则(标点符号;数字;大写字母;小写字母),将password至少分为6段

    例如:abc123+a1? 就可以分为:abc 123 + a 1 ? 这6段

    第三个 if 中,使用 for 循环判断 password 中是否存在 标点符号,数字,大写字母,小写字母中的至少三种

            $c = 0; 
            $ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字  [[:upper:]] 任何大写字母  [[:lower:]] 任何小写字母 
            foreach ($ps as $pt) 
            { 
                if (preg_match("/[[:$pt:]]+/", $password)) 
                    $c += 1; 
            } 
            if ($c < 3) break;

    最后想要获得 flag ,还需要令传入的password=="42"

    if ("42" == $password) echo $flag; 

    从最后的相等出发,因为是弱类型比较,我们首先想到的是十六进制或者科学计数法。

    在科学计数法中,有:https://www.php.net/manual/en/language.operators.comparison.php

    其中

    var_dump(0 == "a"); // 0 == 0 -> true
    var_dump("1" == "01"); // 1 == 1 -> true
    var_dump("10" == "1e1"); // 10 == 10 -> true
    var_dump(100 == "1e2"); // 100 == 100 -> true

    所以我们可以有 4.2e1==42,也可以有420e-1==42,当然还可以继续如0.42e2==42

    为了多一个减号,我们采用420e-1,再变形为:420.0e-1,满足password分成六段的要求,接着满足长度大于等于12的要求,变形为:420.00000e-1

    POST传输:

    数字验证正则绕过.png

     

     

     

    参考链接:

    http://bayescafe.com/php/yuebaomei-ctf.html

  • 相关阅读:
    POJ 1269 Intersecting Lines --计算几何
    URAL 2014 Zhenya moves from parents --线段树
    HDU 4122 Alice's mooncake shop --RMQ
    HDU 4121 Xiangqi --模拟
    HDU 4045 Machine scheduling --第二类Strling数
    HDU 4041 Eliminate Witches! --模拟
    HDU 5105 Math Problem --数学,求导
    2014-2015 Codeforces Trainings Season 2 Episode 7 G Gophers --线段树
    HDU 4419 Colourful Rectangle --离散化+线段树扫描线
    HDU 5102 The K-th Distance
  • 原文地址:https://www.cnblogs.com/Cl0ud/p/13290628.html
Copyright © 2011-2022 走看看